summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk8
-rw-r--r--api/current.txt723
-rw-r--r--api/removed.txt4
-rw-r--r--api/system-current.txt773
-rw-r--r--api/system-removed.txt11
-rw-r--r--api/test-current.txt725
-rw-r--r--api/test-removed.txt4
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java12
-rw-r--r--cmds/app_process/Android.mk2
-rw-r--r--cmds/app_process/app_main.cpp2
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java97
-rw-r--r--cmds/hid/jni/Android.mk2
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.cpp8
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--cmds/svc/src/com/android/commands/svc/NfcCommand.java2
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java7
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java5
-rw-r--r--core/java/android/accounts/AccountManager.java72
-rw-r--r--core/java/android/animation/AnimatorSet.java2
-rw-r--r--core/java/android/app/Activity.java143
-rw-r--r--core/java/android/app/ActivityManager.java222
-rw-r--r--core/java/android/app/ActivityManagerInternal.java42
-rw-r--r--core/java/android/app/ActivityManagerNative.java73
-rw-r--r--core/java/android/app/ActivityThread.java104
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java11
-rw-r--r--core/java/android/app/AppOpsManager.java42
-rw-r--r--core/java/android/app/ApplicationLoaders.java33
-rw-r--r--core/java/android/app/ApplicationPackageManager.java292
-rw-r--r--core/java/android/app/ApplicationThreadNative.java7
-rw-r--r--core/java/android/app/AutomaticZenRule.java7
-rw-r--r--core/java/android/app/BackStackRecord.java4
-rw-r--r--core/java/android/app/ContextImpl.java129
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java13
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java23
-rw-r--r--core/java/android/app/Fragment.java4
-rw-r--r--core/java/android/app/FragmentManager.java17
-rw-r--r--core/java/android/app/IActivityManager.java10
-rw-r--r--core/java/android/app/IApplicationThread.java3
-rw-r--r--core/java/android/app/INotificationManager.aidl19
-rw-r--r--core/java/android/app/ITaskStackListener.aidl5
-rw-r--r--core/java/android/app/IWallpaperManager.aidl16
-rw-r--r--core/java/android/app/Instrumentation.java9
-rw-r--r--core/java/android/app/JobSchedulerImpl.java4
-rw-r--r--core/java/android/app/LoadedApk.java265
-rw-r--r--core/java/android/app/NativeActivity.java9
-rw-r--r--core/java/android/app/Notification.java610
-rw-r--r--core/java/android/app/NotificationManager.java79
-rw-r--r--core/java/android/app/SearchableInfo.java3
-rw-r--r--core/java/android/app/SharedPreferencesImpl.java46
-rw-r--r--core/java/android/app/SystemServiceRegistry.java24
-rw-r--r--core/java/android/app/WallpaperManager.java114
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java63
-rw-r--r--core/java/android/app/admin/DeviceAdminReceiver.java40
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java527
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl18
-rw-r--r--core/java/android/app/backup/BackupAgent.java152
-rw-r--r--core/java/android/app/backup/BackupManager.java7
-rw-r--r--core/java/android/app/backup/BackupTransport.java2
-rw-r--r--core/java/android/app/backup/FullBackup.java91
-rw-r--r--core/java/android/app/job/IJobScheduler.aidl2
-rw-r--r--core/java/android/app/job/JobInfo.java34
-rw-r--r--core/java/android/app/job/JobScheduler.java3
-rw-r--r--core/java/android/app/job/JobService.java6
-rw-r--r--core/java/android/app/trust/TrustManager.java25
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl1
-rw-r--r--core/java/android/app/usage/NetworkStatsManager.java99
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java11
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java9
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java76
-rw-r--r--core/java/android/auditing/SecurityLog.java9
-rw-r--r--core/java/android/auditing/SecurityLogTags.logtags2
-rw-r--r--core/java/android/content/ClipboardManager.java11
-rw-r--r--core/java/android/content/Context.java40
-rw-r--r--core/java/android/content/ContextWrapper.java5
-rw-r--r--core/java/android/content/Intent.java77
-rw-r--r--core/java/android/content/RestrictionsManager.java10
-rw-r--r--core/java/android/content/pm/ActivityInfo.java27
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java12
-rw-r--r--core/java/android/content/pm/FeatureInfo.java40
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl9
-rw-r--r--core/java/android/content/pm/LauncherApps.java16
-rw-r--r--core/java/android/content/pm/PackageInstaller.java40
-rw-r--r--core/java/android/content/pm/PackageManager.java139
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java6
-rw-r--r--core/java/android/content/pm/PackageParser.java53
-rw-r--r--core/java/android/content/pm/PermissionInfo.java6
-rw-r--r--core/java/android/content/pm/UserInfo.java7
-rw-r--r--core/java/android/content/res/Resources.java37
-rw-r--r--core/java/android/content/res/TypedArray.java66
-rw-r--r--core/java/android/hardware/Camera.java9
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java3
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java14
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java41
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java10
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java20
-rw-r--r--core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl16
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.aidl2
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java40
-rw-r--r--core/java/android/hardware/usb/UsbManager.java36
-rw-r--r--core/java/android/net/BaseDhcpStateMachine.java35
-rw-r--r--core/java/android/net/ConnectivityMetricsEvent.aidl19
-rw-r--r--core/java/android/net/ConnectivityMetricsEvent.java82
-rw-r--r--core/java/android/net/ConnectivityMetricsLogger.java57
-rw-r--r--core/java/android/net/DataUsageRequest.java5
-rw-r--r--core/java/android/net/DhcpStateMachine.java462
-rw-r--r--core/java/android/net/IConnectivityMetricsLogger.aidl (renamed from tools/aapt2/util/Comparators.h)27
-rw-r--r--core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl25
-rw-r--r--core/java/android/net/INetworkStatsService.aidl10
-rw-r--r--core/java/android/net/NetworkPolicy.java47
-rw-r--r--core/java/android/net/NetworkPolicyManager.java16
-rw-r--r--core/java/android/net/NetworkScoreManager.java3
-rw-r--r--core/java/android/net/NetworkTemplate.java37
-rw-r--r--core/java/android/net/NetworkUtils.java84
-rw-r--r--core/java/android/net/TrafficStats.java6
-rw-r--r--core/java/android/nfc/NfcAdapter.java2
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulation.java2
-rw-r--r--core/java/android/nfc/cardemulation/NfcFCardEmulation.java2
-rw-r--r--core/java/android/os/BatteryStats.java4
-rw-r--r--core/java/android/os/CpuUsageInfo.aidl18
-rw-r--r--core/java/android/os/DeadSystemException.java27
-rw-r--r--core/java/android/os/Debug.java26
-rw-r--r--core/java/android/os/DropBoxManager.java26
-rw-r--r--core/java/android/os/Environment.java100
-rw-r--r--core/java/android/os/FileUtils.java6
-rw-r--r--core/java/android/os/HardwarePropertiesManager.java52
-rw-r--r--core/java/android/os/IHardwarePropertiesManager.aidl28
-rw-r--r--core/java/android/os/IRecoverySystem.aidl28
-rw-r--r--core/java/android/os/IRecoverySystemProgressListener.aidl24
-rw-r--r--core/java/android/os/PowerManager.java20
-rw-r--r--core/java/android/os/Process.java10
-rw-r--r--core/java/android/os/RecoverySystem.java333
-rw-r--r--core/java/android/os/RemoteException.java22
-rw-r--r--core/java/android/os/StrictMode.java18
-rw-r--r--core/java/android/os/UserHandle.java9
-rw-r--r--core/java/android/os/UserManager.java167
-rw-r--r--core/java/android/os/UserManagerInternal.java20
-rw-r--r--core/java/android/os/storage/StorageManager.java84
-rw-r--r--core/java/android/os/storage/StorageVolume.java154
-rw-r--r--core/java/android/preference/Preference.java10
-rw-r--r--core/java/android/print/PrintManager.java25
-rw-r--r--core/java/android/provider/BlockedNumberContract.java94
-rw-r--r--core/java/android/provider/ContactsContract.java23
-rw-r--r--core/java/android/provider/DocumentsContract.java7
-rw-r--r--core/java/android/provider/DocumentsProvider.java71
-rwxr-xr-xcore/java/android/provider/Settings.java243
-rw-r--r--core/java/android/security/IKeystoreService.aidl2
-rw-r--r--core/java/android/security/keymaster/KeymasterCertificateChain.aidl20
-rw-r--r--core/java/android/security/keymaster/KeymasterCertificateChain.java85
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java6
-rw-r--r--core/java/android/security/net/config/ManifestConfigSource.java12
-rw-r--r--core/java/android/security/net/config/NetworkSecurityConfig.java23
-rw-r--r--core/java/android/security/net/config/NetworkSecurityTrustManager.java18
-rw-r--r--core/java/android/security/net/config/ResourceCertificateSource.java2
-rw-r--r--core/java/android/security/net/config/XmlConfigSource.java13
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java7
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java57
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java13
-rw-r--r--core/java/android/service/persistentdata/IPersistentDataBlockService.aidl2
-rw-r--r--core/java/android/service/persistentdata/PersistentDataBlockManager.java61
-rw-r--r--core/java/android/service/quicksettings/TileService.java10
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java10
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java5
-rw-r--r--core/java/android/text/BidiFormatter.java8
-rw-r--r--core/java/android/text/BoringLayout.java11
-rw-r--r--core/java/android/text/Emoji.java74
-rw-r--r--core/java/android/text/Html.java585
-rw-r--r--core/java/android/text/method/BaseKeyListener.java219
-rw-r--r--core/java/android/text/style/ReplacementSpan.java43
-rw-r--r--core/java/android/transition/Fade.java27
-rw-r--r--core/java/android/transition/Transition.java3
-rw-r--r--core/java/android/transition/TransitionSet.java11
-rw-r--r--core/java/android/transition/Visibility.java69
-rw-r--r--core/java/android/util/BackupUtils.java54
-rw-r--r--core/java/android/util/Log.java10
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java3
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java7
-rw-r--r--core/java/android/view/FrameMetrics.java281
-rw-r--r--core/java/android/view/FrameMetricsObserver.java75
-rw-r--r--core/java/android/view/FrameStatsObserver.java122
-rw-r--r--core/java/android/view/IDockedStackListener.aidl9
-rw-r--r--core/java/android/view/IWindow.aidl3
-rw-r--r--core/java/android/view/IWindowManager.aidl8
-rw-r--r--core/java/android/view/IWindowSession.aidl2
-rw-r--r--core/java/android/view/KeyEvent.java1
-rw-r--r--core/java/android/view/RenderNode.java6
-rw-r--r--core/java/android/view/SurfaceView.java5
-rw-r--r--core/java/android/view/ThreadedRenderer.java38
-rw-r--r--core/java/android/view/View.java95
-rw-r--r--core/java/android/view/ViewRootImpl.java85
-rw-r--r--core/java/android/view/Window.java48
-rw-r--r--core/java/android/view/WindowInsets.java21
-rw-r--r--core/java/android/view/WindowManager.java9
-rw-r--r--core/java/android/view/WindowManagerGlobal.java12
-rw-r--r--core/java/android/view/WindowManagerPolicy.java56
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java9
-rw-r--r--core/java/android/view/animation/ClipRectTBAnimation.java49
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java5
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java12
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java5
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java3
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java24
-rw-r--r--core/java/android/webkit/IWebViewUpdateService.aidl21
-rw-r--r--core/java/android/webkit/WebView.java12
-rw-r--r--core/java/android/webkit/WebViewClient.java4
-rw-r--r--core/java/android/webkit/WebViewDelegate.java2
-rw-r--r--core/java/android/webkit/WebViewFactory.java35
-rw-r--r--core/java/android/webkit/WebViewProvider.java3
-rw-r--r--core/java/android/webkit/WebViewProviderInfo.java46
-rw-r--r--core/java/android/widget/AbsListView.java6
-rw-r--r--core/java/android/widget/AbsSeekBar.java2
-rw-r--r--core/java/android/widget/Chronometer.java48
-rw-r--r--core/java/android/widget/Editor.java37
-rw-r--r--core/java/android/widget/PopupWindow.java2
-rw-r--r--core/java/android/widget/RemoteViews.java95
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java423
-rw-r--r--core/java/android/widget/SearchView.java55
-rw-r--r--core/java/android/widget/TextView.java13
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java6
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java35
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl3
-rw-r--r--core/java/com/android/internal/app/ISoundTriggerService.aidl5
-rw-r--r--core/java/com/android/internal/app/LocaleHelper.java9
-rw-r--r--core/java/com/android/internal/app/LocalePicker.java2
-rw-r--r--core/java/com/android/internal/app/LocaleStore.java26
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java134
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java15
-rw-r--r--core/java/com/android/internal/app/SuggestedLocaleAdapter.java10
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java238
-rw-r--r--core/java/com/android/internal/inputmethod/LocaleUtils.java142
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java1092
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java24
-rw-r--r--core/java/com/android/internal/policy/DecorView.java62
-rw-r--r--core/java/com/android/internal/policy/DockedDividerUtils.java77
-rw-r--r--core/java/com/android/internal/policy/IShortcutService.aidl29
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl20
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl5
-rw-r--r--core/java/com/android/internal/util/LineBreakBufferedWriter.java2
-rw-r--r--core/java/com/android/internal/util/MessageUtils.java132
-rw-r--r--core/java/com/android/internal/util/Preconditions.java16
-rw-r--r--core/java/com/android/internal/util/Protocol.java1
-rw-r--r--core/java/com/android/internal/util/WakeupMessage.java48
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java2
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl9
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java6
-rw-r--r--core/java/com/android/internal/widget/AlertDialogLayout.java45
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java9
-rw-r--r--core/java/com/android/internal/widget/MediaNotificationView.java64
-rw-r--r--core/java/com/android/server/BootReceiver.java187
-rw-r--r--core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java113
-rw-r--r--core/jni/Android.mk9
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp18
-rw-r--r--core/jni/android/graphics/FontFamily.cpp109
-rw-r--r--core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp12
-rw-r--r--core/jni/android/graphics/Paint.cpp29
-rw-r--r--core/jni/android/graphics/Region.cpp34
-rw-r--r--core/jni/android/graphics/Shader.cpp5
-rw-r--r--core/jni/android/graphics/Utils.cpp4
-rw-r--r--core/jni/android/graphics/Utils.h4
-rw-r--r--core/jni/android_app_ApplicationLoaders.cpp51
-rw-r--r--core/jni/android_app_NativeActivity.cpp8
-rw-r--r--core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp29
-rw-r--r--core/jni/android_media_AudioFormat.h5
-rw-r--r--core/jni/android_media_AudioRecord.cpp241
-rw-r--r--core/jni/android_media_AudioSystem.cpp84
-rw-r--r--core/jni/android_media_AudioTrack.cpp301
-rw-r--r--core/jni/android_net_NetUtils.cpp188
-rw-r--r--core/jni/android_opengl_GLES30.cpp16
-rw-r--r--core/jni/android_os_Debug.cpp13
-rw-r--r--core/jni/android_util_Binder.cpp15
-rw-r--r--core/jni/android_util_jar_StrictJarFile.cpp4
-rw-r--r--core/jni/android_view_DisplayListCanvas.cpp2
-rw-r--r--core/jni/android_view_RenderNodeAnimator.cpp2
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp206
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp4
-rw-r--r--core/res/AndroidManifest.xml85
-rw-r--r--core/res/res/drawable-nodpi/platlogo.xml26
-rw-r--r--core/res/res/drawable-nodpi/stat_sys_adb.xml34
-rw-r--r--core/res/res/layout/app_error_dialog.xml2
-rw-r--r--core/res/res/layout/floating_popup_container.xml4
-rw-r--r--core/res/res/layout/language_picker_item.xml47
-rw-r--r--core/res/res/layout/language_picker_section_header.xml6
-rw-r--r--core/res/res/layout/notification_material_action.xml1
-rw-r--r--core/res/res/layout/notification_material_action_tombstone.xml9
-rw-r--r--core/res/res/layout/notification_template_material_big_media.xml57
-rw-r--r--core/res/res/layout/notification_template_material_media.xml2
-rw-r--r--core/res/res/layout/text_edit_suggestion_container.xml4
-rw-r--r--core/res/res/layout/text_edit_suggestion_container_material.xml6
-rw-r--r--core/res/res/values-af/strings.xml28
-rw-r--r--core/res/res/values-am/strings.xml28
-rw-r--r--core/res/res/values-ar/strings.xml28
-rw-r--r--core/res/res/values-az-rAZ/strings.xml30
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml28
-rw-r--r--core/res/res/values-bg/strings.xml28
-rw-r--r--core/res/res/values-bn-rBD/strings.xml30
-rw-r--r--core/res/res/values-bs-rBA/strings.xml4327
-rw-r--r--core/res/res/values-ca/strings.xml28
-rw-r--r--core/res/res/values-cs/strings.xml28
-rw-r--r--core/res/res/values-da/strings.xml28
-rw-r--r--core/res/res/values-de/strings.xml28
-rw-r--r--core/res/res/values-el/strings.xml42
-rw-r--r--core/res/res/values-en-rAU/strings.xml30
-rw-r--r--core/res/res/values-en-rGB/strings.xml30
-rw-r--r--core/res/res/values-en-rIN/strings.xml30
-rw-r--r--core/res/res/values-es-rUS/strings.xml32
-rw-r--r--core/res/res/values-es/strings.xml28
-rw-r--r--core/res/res/values-et-rEE/strings.xml28
-rw-r--r--core/res/res/values-eu-rES/strings.xml28
-rw-r--r--core/res/res/values-fa/strings.xml30
-rw-r--r--core/res/res/values-fi/strings.xml28
-rw-r--r--core/res/res/values-fr-rCA/strings.xml28
-rw-r--r--core/res/res/values-fr/strings.xml28
-rw-r--r--core/res/res/values-gl-rES/strings.xml28
-rw-r--r--core/res/res/values-gu-rIN/strings.xml28
-rw-r--r--core/res/res/values-hi/strings.xml28
-rw-r--r--core/res/res/values-hr/strings.xml28
-rw-r--r--core/res/res/values-hu/strings.xml28
-rw-r--r--core/res/res/values-hy-rAM/strings.xml28
-rw-r--r--core/res/res/values-in/strings.xml28
-rw-r--r--core/res/res/values-is-rIS/strings.xml28
-rw-r--r--core/res/res/values-it/strings.xml32
-rw-r--r--core/res/res/values-iw/strings.xml28
-rw-r--r--core/res/res/values-ja/strings.xml28
-rw-r--r--core/res/res/values-ka-rGE/strings.xml28
-rw-r--r--core/res/res/values-kk-rKZ/strings.xml28
-rw-r--r--core/res/res/values-km-rKH/strings.xml28
-rw-r--r--core/res/res/values-kn-rIN/strings.xml28
-rw-r--r--core/res/res/values-ko/strings.xml28
-rw-r--r--core/res/res/values-ky-rKG/strings.xml28
-rw-r--r--core/res/res/values-ldrtl-television/config.xml27
-rw-r--r--core/res/res/values-lo-rLA/strings.xml28
-rw-r--r--core/res/res/values-lt/strings.xml28
-rw-r--r--core/res/res/values-lv/strings.xml28
-rw-r--r--core/res/res/values-mk-rMK/strings.xml28
-rw-r--r--core/res/res/values-ml-rIN/strings.xml32
-rw-r--r--core/res/res/values-mn-rMN/strings.xml28
-rw-r--r--core/res/res/values-mr-rIN/strings.xml28
-rw-r--r--core/res/res/values-ms-rMY/strings.xml28
-rw-r--r--core/res/res/values-my-rMM/strings.xml28
-rw-r--r--core/res/res/values-nb/strings.xml28
-rw-r--r--core/res/res/values-ne-rNP/strings.xml28
-rw-r--r--core/res/res/values-nl/strings.xml28
-rw-r--r--core/res/res/values-pa-rIN/strings.xml28
-rw-r--r--core/res/res/values-pl/strings.xml28
-rw-r--r--core/res/res/values-pt-rBR/strings.xml28
-rw-r--r--core/res/res/values-pt-rPT/strings.xml30
-rw-r--r--core/res/res/values-pt/strings.xml28
-rw-r--r--core/res/res/values-ro/strings.xml396
-rw-r--r--core/res/res/values-ru/strings.xml30
-rw-r--r--core/res/res/values-si-rLK/strings.xml28
-rw-r--r--core/res/res/values-sk/strings.xml28
-rw-r--r--core/res/res/values-sl/strings.xml28
-rw-r--r--core/res/res/values-sq-rAL/strings.xml28
-rw-r--r--core/res/res/values-sr/strings.xml28
-rw-r--r--core/res/res/values-sv/strings.xml28
-rw-r--r--core/res/res/values-sw/strings.xml28
-rw-r--r--core/res/res/values-ta-rIN/strings.xml30
-rw-r--r--core/res/res/values-te-rIN/strings.xml28
-rw-r--r--core/res/res/values-television/config.xml5
-rw-r--r--core/res/res/values-th/strings.xml28
-rw-r--r--core/res/res/values-tl/strings.xml28
-rw-r--r--core/res/res/values-tr/strings.xml28
-rw-r--r--core/res/res/values-uk/strings.xml28
-rw-r--r--core/res/res/values-ur-rPK/strings.xml28
-rw-r--r--core/res/res/values-uz-rUZ/strings.xml56
-rw-r--r--core/res/res/values-vi/strings.xml28
-rw-r--r--core/res/res/values-watch/themes_device_defaults.xml1
-rw-r--r--core/res/res/values-zh-rCN/strings.xml28
-rw-r--r--core/res/res/values-zh-rHK/strings.xml28
-rw-r--r--core/res/res/values-zh-rTW/strings.xml28
-rw-r--r--core/res/res/values-zu/strings.xml28
-rw-r--r--core/res/res/values/attrs.xml34
-rw-r--r--core/res/res/values/attrs_manifest.xml45
-rw-r--r--core/res/res/values/config.xml18
-rw-r--r--core/res/res/values/dimens.xml9
-rw-r--r--core/res/res/values/dimens_material.xml3
-rw-r--r--core/res/res/values/public.xml7
-rw-r--r--core/res/res/values/strings.xml44
-rw-r--r--core/res/res/values/styles_holo.xml1
-rw-r--r--core/res/res/values/styles_material.xml2
-rw-r--r--core/res/res/values/symbols.xml24
-rw-r--r--core/tests/coretests/apks/install_jni_lib/Android.mk2
-rw-r--r--core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp2
-rw-r--r--core/tests/coretests/src/android/app/backup/FullBackupTest.java33
-rw-r--r--core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java5
-rw-r--r--core/tests/coretests/src/android/text/method/BackspaceTest.java588
-rw-r--r--core/tests/coretests/src/android/text/method/EditorState.java187
-rw-r--r--core/tests/coretests/src/android/text/method/KeyListenerTestCase.java62
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivity.java43
-rw-r--r--core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java168
-rw-r--r--core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java194
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java745
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java15
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java339
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java487
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java54
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java (renamed from core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java)42
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockClocks.java32
-rw-r--r--core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java16
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java5
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp4
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp4
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk2
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp4
-rw-r--r--core/tests/systemproperties/Android.mk1
-rw-r--r--core/tests/utiltests/Android.mk24
-rw-r--r--core/tests/utiltests/AndroidManifest.xml53
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java (renamed from core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java (renamed from core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java (renamed from core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java (renamed from core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java (renamed from core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java)2
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java (renamed from core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java (renamed from core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java97
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java (renamed from core/tests/coretests/src/com/android/internal/util/PredicatesTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java (renamed from core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java (renamed from core/tests/coretests/src/com/android/internal/util/StateMachineTest.java)0
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java169
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java (renamed from core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java)0
-rw-r--r--docs/html/guide/components/services.jd26
-rw-r--r--docs/html/guide/guide_toc.cs10
-rw-r--r--docs/html/guide/topics/security/index.jd7
-rw-r--r--docs/html/guide/topics/security/security-config.jd539
-rw-r--r--docs/html/preview/behavior-changes.jd2
-rw-r--r--graphics/java/android/graphics/Canvas.java16
-rw-r--r--graphics/java/android/graphics/FontFamily.java13
-rw-r--r--graphics/java/android/graphics/FontListParser.java92
-rw-r--r--graphics/java/android/graphics/Outline.java29
-rw-r--r--graphics/java/android/graphics/Paint.java11
-rw-r--r--graphics/java/android/graphics/Typeface.java39
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java304
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java18
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java20
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java365
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java5
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java35
-rw-r--r--keystore/java/android/security/Credentials.java29
-rw-r--r--keystore/java/android/security/KeyStore.java13
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java8
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java202
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java28
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java8
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java207
-rw-r--r--keystore/java/android/security/keystore/KeyInfo.java26
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java103
-rw-r--r--keystore/java/android/security/keystore/KeymasterUtils.java42
-rw-r--r--keystore/java/android/security/keystore/Utils.java4
-rw-r--r--libs/androidfw/ResourceTypes.cpp29
-rw-r--r--libs/androidfw/tests/ConfigLocale_test.cpp13
-rw-r--r--libs/hwui/Android.mk45
-rw-r--r--libs/hwui/Animator.cpp189
-rw-r--r--libs/hwui/Animator.h65
-rw-r--r--libs/hwui/AnimatorManager.cpp84
-rw-r--r--libs/hwui/AnimatorManager.h7
-rw-r--r--libs/hwui/BakedOpDispatcher.cpp24
-rw-r--r--libs/hwui/BakedOpRenderer.cpp31
-rw-r--r--libs/hwui/BakedOpState.cpp22
-rw-r--r--libs/hwui/BakedOpState.h18
-rw-r--r--libs/hwui/BufferPool.h181
-rw-r--r--libs/hwui/ClipArea.cpp16
-rw-r--r--libs/hwui/DamageAccumulator.cpp4
-rw-r--r--libs/hwui/DeferredDisplayList.h7
-rw-r--r--libs/hwui/DisplayListCanvas.cpp7
-rw-r--r--libs/hwui/DisplayListCanvas.h5
-rw-r--r--libs/hwui/DisplayListOp.h29
-rw-r--r--libs/hwui/FrameBuilder.cpp73
-rw-r--r--libs/hwui/FrameMetricsObserver.h (renamed from libs/hwui/FrameStatsObserver.h)6
-rw-r--r--libs/hwui/FrameMetricsReporter.h65
-rw-r--r--libs/hwui/FrameStatsReporter.h91
-rw-r--r--libs/hwui/GradientCache.cpp4
-rw-r--r--libs/hwui/LayerBuilder.cpp22
-rw-r--r--libs/hwui/LayerBuilder.h2
-rw-r--r--libs/hwui/Matrix.cpp2
-rw-r--r--libs/hwui/Matrix.h27
-rw-r--r--libs/hwui/OpDumper.cpp44
-rw-r--r--libs/hwui/OpDumper.h32
-rw-r--r--libs/hwui/PixelBuffer.cpp10
-rw-r--r--libs/hwui/PixelBuffer.h16
-rw-r--r--libs/hwui/PropertyValuesAnimatorSet.cpp60
-rw-r--r--libs/hwui/PropertyValuesAnimatorSet.h1
-rw-r--r--libs/hwui/RecordedOp.h3
-rw-r--r--libs/hwui/RecordingCanvas.cpp82
-rw-r--r--libs/hwui/RecordingCanvas.h5
-rw-r--r--libs/hwui/Rect.h29
-rw-r--r--libs/hwui/RenderNode.cpp45
-rw-r--r--libs/hwui/RenderNode.h10
-rw-r--r--libs/hwui/RenderProperties.cpp20
-rw-r--r--libs/hwui/Snapshot.h8
-rw-r--r--libs/hwui/Texture.cpp8
-rw-r--r--libs/hwui/font/CacheTexture.h2
-rw-r--r--libs/hwui/font/Font.h1
-rw-r--r--libs/hwui/hwui_static_deps.mk28
-rw-r--r--libs/hwui/renderstate/MeshState.cpp55
-rw-r--r--libs/hwui/renderstate/MeshState.h25
-rw-r--r--libs/hwui/renderstate/OffscreenBufferPool.cpp8
-rw-r--r--libs/hwui/renderstate/OffscreenBufferPool.h2
-rw-r--r--libs/hwui/renderstate/RenderState.cpp21
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp6
-rw-r--r--libs/hwui/renderthread/CanvasContext.h30
-rw-r--r--libs/hwui/renderthread/EglManager.cpp10
-rw-r--r--libs/hwui/renderthread/EglManager.h4
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp30
-rw-r--r--libs/hwui/renderthread/RenderProxy.h6
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp1
-rw-r--r--libs/hwui/tests/unit/BufferPoolTests.cpp102
-rw-r--r--libs/hwui/tests/unit/ClipAreaTests.cpp11
-rw-r--r--libs/hwui/tests/unit/FrameBuilderTests.cpp56
-rw-r--r--libs/hwui/tests/unit/LinearAllocatorTests.cpp13
-rw-r--r--libs/hwui/tests/unit/MatrixTests.cpp35
-rw-r--r--libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp8
-rw-r--r--libs/hwui/tests/unit/OpDumperTests.cpp43
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp41
-rw-r--r--libs/hwui/utils/LinearAllocator.cpp8
-rw-r--r--libs/hwui/utils/LinearAllocator.h45
-rw-r--r--libs/hwui/utils/StringUtils.h2
-rw-r--r--location/java/android/location/GnssClock.java110
-rw-r--r--location/java/android/location/GnssMeasurement.java237
-rw-r--r--location/java/android/location/GnssNavigationMessage.java108
-rw-r--r--location/java/android/location/GnssStatus.java57
-rw-r--r--location/java/android/location/GpsStatus.java21
-rw-r--r--location/java/android/location/IGnssStatusListener.aidl4
-rw-r--r--location/java/android/location/ILocationManager.aidl2
-rw-r--r--location/java/android/location/LocationManager.java96
-rw-r--r--media/java/android/media/AudioDeviceInfo.java7
-rw-r--r--media/java/android/media/AudioFormat.aidl19
-rw-r--r--media/java/android/media/AudioFormat.java100
-rw-r--r--media/java/android/media/AudioManager.java181
-rw-r--r--media/java/android/media/AudioPatch.java7
-rw-r--r--media/java/android/media/AudioRecord.java100
-rw-r--r--media/java/android/media/AudioRecordConfiguration.java73
-rw-r--r--media/java/android/media/AudioRouting.java8
-rw-r--r--media/java/android/media/AudioSystem.java42
-rw-r--r--media/java/android/media/AudioTrack.java149
-rw-r--r--media/java/android/media/ExifInterface.java1724
-rw-r--r--media/java/android/media/IAudioService.aidl4
-rw-r--r--media/java/android/media/ImageReader.java18
-rw-r--r--media/java/android/media/MediaFormat.java23
-rw-r--r--media/java/android/media/MediaMuxer.java4
-rw-r--r--media/java/android/media/MediaPlayer.java82
-rw-r--r--media/java/android/media/MediaRecorder.java24
-rw-r--r--media/java/android/media/RingtoneManager.java36
-rw-r--r--media/java/android/media/audiopolicy/AudioMix.java1
-rw-r--r--media/java/android/media/audiopolicy/AudioMixingRule.java36
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicyConfig.java14
-rw-r--r--media/java/android/media/browse/MediaBrowser.java30
-rw-r--r--media/java/android/media/session/ISession.aidl2
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl4
-rw-r--r--media/java/android/media/session/ISessionController.aidl4
-rw-r--r--media/java/android/media/session/MediaController.java96
-rw-r--r--media/java/android/media/session/MediaSession.java192
-rw-r--r--media/java/android/media/session/PlaybackState.java55
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerDetector.java211
-rw-r--r--media/java/android/media/tv/ITvInputClient.aidl3
-rw-r--r--media/java/android/media/tv/ITvInputManager.aidl5
-rw-r--r--media/java/android/media/tv/ITvInputManagerCallback.aidl4
-rw-r--r--media/java/android/media/tv/ITvInputSession.aidl4
-rw-r--r--media/java/android/media/tv/ITvInputSessionCallback.aidl3
-rw-r--r--media/java/android/media/tv/ITvInputSessionWrapper.java76
-rw-r--r--media/java/android/media/tv/TvContract.java243
-rw-r--r--media/java/android/media/tv/TvInputInfo.java238
-rw-r--r--media/java/android/media/tv/TvInputManager.java230
-rw-r--r--media/java/android/media/tv/TvInputService.java180
-rw-r--r--media/java/android/media/tv/TvRecordingClient.java175
-rw-r--r--media/java/android/media/tv/TvTrackInfo.java44
-rw-r--r--media/java/android/media/tv/TvView.java4
-rw-r--r--media/java/android/service/media/MediaBrowserService.java2
-rw-r--r--media/jni/Android.mk4
-rw-r--r--media/jni/android_media_ExifInterface.cpp23
-rw-r--r--media/jni/android_media_ImageReader.cpp8
-rw-r--r--media/jni/android_media_MediaCrypto.cpp35
-rw-r--r--media/jni/android_media_MediaDrm.cpp35
-rw-r--r--media/jni/android_media_Utils.cpp13
-rw-r--r--media/jni/android_media_Utils.h1
-rw-r--r--media/tests/MediaFrameworkTest/Android.mk2
-rw-r--r--media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpgbin0 -> 105271 bytes
-rw-r--r--media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpgbin0 -> 8610 bytes
-rw-r--r--media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dngbin0 -> 129312 bytes
-rw-r--r--media/tests/MediaFrameworkTest/res/values/exifinterface.xml108
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java5
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java418
-rw-r--r--opengl/java/android/opengl/GLES30.java12
-rw-r--r--packages/DocumentsUI/Android.mk5
-rw-r--r--packages/DocumentsUI/AndroidManifest.xml4
-rw-r--r--packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.pngbin661 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.pngbin549 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.pngbin777 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.pngbin617 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.pngbin883 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable/ic_root_documents.xml (renamed from packages/DocumentsUI/res/drawable/ic_root_home.xml)2
-rw-r--r--packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml29
-rw-r--r--packages/DocumentsUI/res/layout/directory_cluster.xml1
-rw-r--r--packages/DocumentsUI/res/layout/drawer_layout.xml2
-rw-r--r--packages/DocumentsUI/res/layout/fixed_layout.xml5
-rw-r--r--packages/DocumentsUI/res/layout/fragment_directory.xml12
-rw-r--r--packages/DocumentsUI/res/layout/fragment_roots.xml4
-rw-r--r--packages/DocumentsUI/res/layout/item_dir_grid.xml4
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml4
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_list.xml2
-rw-r--r--packages/DocumentsUI/res/layout/item_subdir.xml6
-rw-r--r--packages/DocumentsUI/res/layout/item_subdir_title.xml2
-rw-r--r--packages/DocumentsUI/res/layout/single_pane_layout.xml5
-rw-r--r--packages/DocumentsUI/res/values-af/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-am/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-ar/strings.xml10
-rw-r--r--packages/DocumentsUI/res/values-az-rAZ/strings.xml10
-rw-r--r--packages/DocumentsUI/res/values-b+sr+Latn/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-b+sr+Latn/strings.xml35
-rw-r--r--packages/DocumentsUI/res/values-bg/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-bg/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-bn-rBD/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-bn-rBD/strings.xml33
-rw-r--r--packages/DocumentsUI/res/values-bs-rBA/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-bs-rBA/strings.xml219
-rw-r--r--packages/DocumentsUI/res/values-ca/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ca/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-cs/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-cs/strings.xml38
-rw-r--r--packages/DocumentsUI/res/values-da/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-da/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-de/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-de/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-el/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-el/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-en-rAU/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-en-rAU/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-en-rGB/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-en-rGB/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-en-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-en-rIN/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-es-rUS/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-es-rUS/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-es/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-es/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-et-rEE/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-et-rEE/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-eu-rES/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-eu-rES/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-fa/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-fa/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-fi/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-fi/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-fr-rCA/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-fr-rCA/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-fr/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-fr/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-gl-rES/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-gl-rES/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-gu-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-gu-rIN/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-hi/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-hi/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-hr/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-hr/strings.xml7
-rw-r--r--packages/DocumentsUI/res/values-hu/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-hu/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-hy-rAM/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-hy-rAM/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-in/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-in/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-is-rIS/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-is-rIS/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-it/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-it/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-iw/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-iw/strings.xml38
-rw-r--r--packages/DocumentsUI/res/values-ja/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ja/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-ka-rGE/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ka-rGE/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-kk-rKZ/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-kk-rKZ/strings.xml7
-rw-r--r--packages/DocumentsUI/res/values-km-rKH/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-km-rKH/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-kn-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-kn-rIN/strings.xml33
-rw-r--r--packages/DocumentsUI/res/values-ko/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ko/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-ky-rKG/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ky-rKG/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-ldrtl/config.xml (renamed from packages/DocumentsUI/res/values-ldrtl/dimens.xml)0
-rw-r--r--packages/DocumentsUI/res/values-lo-rLA/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-lo-rLA/strings.xml12
-rw-r--r--packages/DocumentsUI/res/values-lt/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-lt/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-lv/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-lv/strings.xml35
-rw-r--r--packages/DocumentsUI/res/values-mk-rMK/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-mk-rMK/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-ml-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ml-rIN/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-mn-rMN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-mn-rMN/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-mr-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-mr-rIN/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-ms-rMY/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ms-rMY/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-my-rMM/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-my-rMM/strings.xml8
-rw-r--r--packages/DocumentsUI/res/values-nb/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-nb/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-ne-rNP/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ne-rNP/strings.xml10
-rw-r--r--packages/DocumentsUI/res/values-nl/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-nl/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-pa-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-pa-rIN/strings.xml33
-rw-r--r--packages/DocumentsUI/res/values-pl/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-pl/strings.xml38
-rw-r--r--packages/DocumentsUI/res/values-pt-rBR/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-pt-rBR/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-pt-rPT/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-pt-rPT/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-pt/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-pt/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-ro/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ro/strings.xml37
-rw-r--r--packages/DocumentsUI/res/values-ru/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ru/strings.xml38
-rw-r--r--packages/DocumentsUI/res/values-si-rLK/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-si-rLK/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-sk/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-sk/strings.xml38
-rw-r--r--packages/DocumentsUI/res/values-sl/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-sl/strings.xml8
-rw-r--r--packages/DocumentsUI/res/values-sq-rAL/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-sq-rAL/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-sr/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-sr/strings.xml35
-rw-r--r--packages/DocumentsUI/res/values-sv/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-sv/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-sw/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-sw/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-sw720dp-land/config.xml (renamed from packages/DocumentsUI/res/values-az-rAZ/config.xml)11
-rw-r--r--packages/DocumentsUI/res/values-sw720dp-land/dimens.xml2
-rw-r--r--packages/DocumentsUI/res/values-ta-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ta-rIN/strings.xml33
-rw-r--r--packages/DocumentsUI/res/values-te-rIN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-te-rIN/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-th/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-th/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-tl/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-tl/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-tr/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-tr/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-uk/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-uk/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-ur-rPK/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-ur-rPK/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-uz-rUZ/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-uz-rUZ/strings.xml34
-rw-r--r--packages/DocumentsUI/res/values-vi/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-vi/strings.xml6
-rw-r--r--packages/DocumentsUI/res/values-zh-rCN/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-zh-rCN/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values-zh-rHK/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-zh-rHK/strings.xml9
-rw-r--r--packages/DocumentsUI/res/values-zh-rTW/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-zh-rTW/strings.xml5
-rw-r--r--packages/DocumentsUI/res/values-zu/config.xml20
-rw-r--r--packages/DocumentsUI/res/values-zu/strings.xml32
-rw-r--r--packages/DocumentsUI/res/values/colors.xml12
-rw-r--r--packages/DocumentsUI/res/values/config.xml4
-rw-r--r--packages/DocumentsUI/res/values/dimens.xml15
-rw-r--r--packages/DocumentsUI/res/values/strings.xml9
-rw-r--r--packages/DocumentsUI/res/values/styles.xml1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java207
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java11
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java73
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java22
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DrawerController.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Events.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java78
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/LoadRootTask.java (renamed from packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java)4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Metrics.java173
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/NavigationView.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java142
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java9
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/PickFragment.java18
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java114
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java (renamed from packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java)143
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java65
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java88
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsList.java63
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java (renamed from packages/DocumentsUI/src/com/android/documentsui/SearchManager.java)79
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Shared.java85
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Snackbars.java11
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/State.java55
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java837
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java24
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java561
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java122
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java13
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java15
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java9
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java30
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java309
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java101
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java8
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java68
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java89
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java321
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java15
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java31
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java8
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/Job.java43
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java36
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java45
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java170
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java3
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java125
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java204
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java166
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java55
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java145
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java52
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java393
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java177
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java74
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java179
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java50
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java88
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java228
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java3
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java117
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java30
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java3
-rw-r--r--packages/ExternalStorageProvider/res/values-af/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-am/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ar/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-bg/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-bs-rBA/strings.xml (renamed from packages/DocumentsUI/res/values-ar/config.xml)6
-rw-r--r--packages/ExternalStorageProvider/res/values-ca/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-cs/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-da/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-de/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-el/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-en-rAU/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-en-rGB/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-en-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-es-rUS/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-es/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-et-rEE/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-eu-rES/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-fa/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-fi/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-fr/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-gl-rES/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-hi/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-hr/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-hu/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-in/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-is-rIS/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-it/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-iw/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ja/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-km-rKH/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ko/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-lt/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-lv/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-my-rMM/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-nb/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-nl/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-pl/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-pt/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ro/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ru/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-si-rLK/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-sk/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-sl/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-sr/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-sv/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-sw/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-te-rIN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-th/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-tl/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-tr/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-uk/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-vi/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values-zu/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/res/values/strings.xml4
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java6
-rw-r--r--packages/Keyguard/res/values-h560dp/dimens.xml2
-rw-r--r--packages/Keyguard/res/values-h650dp/dimens.xml2
-rw-r--r--packages/Keyguard/res/values-sw600dp-land/dimens.xml2
-rw-r--r--packages/Keyguard/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/Keyguard/res/values-sw720dp/dimens.xml2
-rw-r--r--packages/Keyguard/res/values/dimens.xml4
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java11
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java7
-rw-r--r--packages/MtpDocumentsProvider/res/values/strings.xml4
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java2
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java248
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java416
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java294
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java28
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java33
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java125
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java45
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java77
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java45
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java30
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java42
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java (renamed from media/mca/effect/java/android/media/effect/package-info.java)15
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java28
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java601
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java220
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java7
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java42
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java38
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java4
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java27
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java135
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java8
-rw-r--r--packages/SettingsLib/res/layout/usage_bottom_label.xml20
-rw-r--r--packages/SettingsLib/res/layout/usage_side_label.xml20
-rw-r--r--packages/SettingsLib/res/layout/usage_view.xml87
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-az-rAZ/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-bn-rBD/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-bs-rBA/arrays.xml161
-rw-r--r--packages/SettingsLib/res/values-bs-rBA/strings.xml294
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-et-rEE/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-eu-rES/strings.xml29
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-gl-rES/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-gu-rIN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-hy-rAM/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-is-rIS/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ka-rGE/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-kk-rKZ/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-km-rKH/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-kn-rIN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ky-rKG/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-lo-rLA/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-mk-rMK/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-ml-rIN/strings.xml29
-rw-r--r--packages/SettingsLib/res/values-mn-rMN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-mr-rIN/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-ms-rMY/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-my-rMM/strings.xml27
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-ne-rNP/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-pa-rIN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ro/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml47
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-si-rLK/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-sq-rAL/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ta-rIN/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-te-rIN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-ur-rPK/strings.xml40
-rw-r--r--packages/SettingsLib/res/values-uz-rUZ/strings.xml44
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml31
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml25
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml40
-rw-r--r--packages/SettingsLib/res/values/arrays.xml22
-rw-r--r--packages/SettingsLib/res/values/attrs.xml8
-rw-r--r--packages/SettingsLib/res/values/colors.xml2
-rw-r--r--packages/SettingsLib/res/values/dimens.xml14
-rw-r--r--packages/SettingsLib/res/values/strings.xml55
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java202
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java33
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java249
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java119
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java7
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java310
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java40
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/Shell/res/values-af/strings.xml10
-rw-r--r--packages/Shell/res/values-am/strings.xml10
-rw-r--r--packages/Shell/res/values-ar/strings.xml10
-rw-r--r--packages/Shell/res/values-az-rAZ/strings.xml10
-rw-r--r--packages/Shell/res/values-b+sr+Latn/strings.xml10
-rw-r--r--packages/Shell/res/values-bg/strings.xml10
-rw-r--r--packages/Shell/res/values-bn-rBD/strings.xml10
-rw-r--r--packages/Shell/res/values-bs-rBA/strings.xml54
-rw-r--r--packages/Shell/res/values-ca/strings.xml10
-rw-r--r--packages/Shell/res/values-cs/strings.xml10
-rw-r--r--packages/Shell/res/values-da/strings.xml10
-rw-r--r--packages/Shell/res/values-de/strings.xml10
-rw-r--r--packages/Shell/res/values-el/strings.xml10
-rw-r--r--packages/Shell/res/values-en-rAU/strings.xml10
-rw-r--r--packages/Shell/res/values-en-rGB/strings.xml10
-rw-r--r--packages/Shell/res/values-en-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-es-rUS/strings.xml10
-rw-r--r--packages/Shell/res/values-es/strings.xml10
-rw-r--r--packages/Shell/res/values-et-rEE/strings.xml10
-rw-r--r--packages/Shell/res/values-eu-rES/strings.xml10
-rw-r--r--packages/Shell/res/values-fa/strings.xml10
-rw-r--r--packages/Shell/res/values-fi/strings.xml10
-rw-r--r--packages/Shell/res/values-fr-rCA/strings.xml10
-rw-r--r--packages/Shell/res/values-fr/strings.xml10
-rw-r--r--packages/Shell/res/values-gl-rES/strings.xml10
-rw-r--r--packages/Shell/res/values-gu-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-hi/strings.xml10
-rw-r--r--packages/Shell/res/values-hr/strings.xml10
-rw-r--r--packages/Shell/res/values-hu/strings.xml10
-rw-r--r--packages/Shell/res/values-hy-rAM/strings.xml10
-rw-r--r--packages/Shell/res/values-in/strings.xml10
-rw-r--r--packages/Shell/res/values-is-rIS/strings.xml10
-rw-r--r--packages/Shell/res/values-it/strings.xml10
-rw-r--r--packages/Shell/res/values-iw/strings.xml10
-rw-r--r--packages/Shell/res/values-ja/strings.xml10
-rw-r--r--packages/Shell/res/values-ka-rGE/strings.xml10
-rw-r--r--packages/Shell/res/values-kk-rKZ/strings.xml10
-rw-r--r--packages/Shell/res/values-km-rKH/strings.xml10
-rw-r--r--packages/Shell/res/values-kn-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-ko/strings.xml10
-rw-r--r--packages/Shell/res/values-ky-rKG/strings.xml10
-rw-r--r--packages/Shell/res/values-lo-rLA/strings.xml10
-rw-r--r--packages/Shell/res/values-lt/strings.xml10
-rw-r--r--packages/Shell/res/values-lv/strings.xml10
-rw-r--r--packages/Shell/res/values-mk-rMK/strings.xml10
-rw-r--r--packages/Shell/res/values-ml-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-mn-rMN/strings.xml10
-rw-r--r--packages/Shell/res/values-mr-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-ms-rMY/strings.xml10
-rw-r--r--packages/Shell/res/values-my-rMM/strings.xml10
-rw-r--r--packages/Shell/res/values-nb/strings.xml10
-rw-r--r--packages/Shell/res/values-ne-rNP/strings.xml10
-rw-r--r--packages/Shell/res/values-nl/strings.xml10
-rw-r--r--packages/Shell/res/values-pa-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-pl/strings.xml10
-rw-r--r--packages/Shell/res/values-pt-rBR/strings.xml10
-rw-r--r--packages/Shell/res/values-pt-rPT/strings.xml10
-rw-r--r--packages/Shell/res/values-pt/strings.xml10
-rw-r--r--packages/Shell/res/values-ro/strings.xml10
-rw-r--r--packages/Shell/res/values-ru/strings.xml10
-rw-r--r--packages/Shell/res/values-si-rLK/strings.xml10
-rw-r--r--packages/Shell/res/values-sk/strings.xml10
-rw-r--r--packages/Shell/res/values-sl/strings.xml10
-rw-r--r--packages/Shell/res/values-sq-rAL/strings.xml10
-rw-r--r--packages/Shell/res/values-sr/strings.xml10
-rw-r--r--packages/Shell/res/values-sv/strings.xml10
-rw-r--r--packages/Shell/res/values-sw/strings.xml10
-rw-r--r--packages/Shell/res/values-ta-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-te-rIN/strings.xml10
-rw-r--r--packages/Shell/res/values-th/strings.xml10
-rw-r--r--packages/Shell/res/values-tl/strings.xml10
-rw-r--r--packages/Shell/res/values-tr/strings.xml10
-rw-r--r--packages/Shell/res/values-uk/strings.xml10
-rw-r--r--packages/Shell/res/values-ur-rPK/strings.xml10
-rw-r--r--packages/Shell/res/values-uz-rUZ/strings.xml10
-rw-r--r--packages/Shell/res/values-vi/strings.xml10
-rw-r--r--packages/Shell/res/values-zh-rCN/strings.xml10
-rw-r--r--packages/Shell/res/values-zh-rHK/strings.xml10
-rw-r--r--packages/Shell/res/values-zh-rTW/strings.xml10
-rw-r--r--packages/Shell/res/values-zu/strings.xml10
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java316
-rw-r--r--packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java11
-rw-r--r--packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java265
-rw-r--r--packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java4
-rw-r--r--packages/SystemUI/Android.mk23
-rw-r--r--packages/SystemUI/AndroidManifest.xml6
-rw-r--r--packages/SystemUI/res/drawable-nodpi/icon.xml35
-rw-r--r--packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_night_mode.xml (renamed from packages/SystemUI/res/drawable/ic_colorize.xml)2
-rw-r--r--packages/SystemUI/res/drawable/ic_night_mode_disabled.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_pause_white_24dp.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_data_saver.xml32
-rw-r--r--packages/SystemUI/res/drawable/tv_pip_button_focused.xml (renamed from packages/DocumentsUI/res/values-af/config.xml)18
-rw-r--r--packages/SystemUI/res/drawable/tv_pip_close_button.xml26
-rw-r--r--packages/SystemUI/res/drawable/tv_pip_full_button.xml26
-rw-r--r--packages/SystemUI/res/drawable/tv_pip_outline.xml (renamed from packages/DocumentsUI/res/values-am/config.xml)14
-rw-r--r--packages/SystemUI/res/drawable/tv_pip_pause_button.xml26
-rw-r--r--packages/SystemUI/res/drawable/tv_pip_play_button.xml26
-rw-r--r--packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml20
-rw-r--r--packages/SystemUI/res/layout/battery_detail.xml113
-rw-r--r--packages/SystemUI/res/layout/calibrate_sliders.xml (renamed from packages/SystemUI/res/layout/preference_matrix.xml)7
-rw-r--r--packages/SystemUI/res/layout/docked_stack_divider.xml1
-rw-r--r--packages/SystemUI/res/layout/navigation_layout.xml20
-rw-r--r--packages/SystemUI/res/layout/navigation_layout_rot90.xml20
-rw-r--r--packages/SystemUI/res/layout/night_mode_settings.xml (renamed from packages/SystemUI/res/layout/color_matrix_settings.xml)0
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml56
-rw-r--r--packages/SystemUI/res/layout/notification_settings_icon_row.xml39
-rw-r--r--packages/SystemUI/res/layout/qs_customize_panel.xml48
-rw-r--r--packages/SystemUI/res/layout/qs_detail.xml63
-rw-r--r--packages/SystemUI/res/layout/qs_detail_buttons.xml42
-rw-r--r--packages/SystemUI/res/layout/qs_detail_header.xml1
-rw-r--r--packages/SystemUI/res/layout/qs_paged_page.xml4
-rw-r--r--packages/SystemUI/res/layout/qs_paged_tile_layout.xml38
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml13
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml119
-rw-r--r--packages/SystemUI/res/layout/recents_on_tv.xml20
-rw-r--r--packages/SystemUI/res/layout/recents_task_view_header.xml53
-rw-r--r--packages/SystemUI/res/layout/recents_task_view_header_overlay.xml9
-rw-r--r--packages/SystemUI/res/layout/remote_input.xml1
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml35
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml6
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_row.xml13
-rw-r--r--packages/SystemUI/res/layout/tuner_zen_mode_panel.xml48
-rw-r--r--packages/SystemUI/res/layout/tv_pip_menu.xml109
-rw-r--r--packages/SystemUI/res/layout/tv_pip_onboarding.xml43
-rw-r--r--packages/SystemUI/res/layout/tv_pip_overlay.xml43
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml42
-rw-r--r--packages/SystemUI/res/layout/volume_dialog_row.xml18
-rw-r--r--packages/SystemUI/res/layout/volume_zen_footer.xml4
-rw-r--r--packages/SystemUI/res/values-af/strings.xml90
-rw-r--r--packages/SystemUI/res/values-am/strings.xml90
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml77
-rw-r--r--packages/SystemUI/res/values-az-rAZ/strings.xml77
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml90
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml90
-rw-r--r--packages/SystemUI/res/values-bn-rBD/strings.xml77
-rw-r--r--packages/SystemUI/res/values-bs-rBA/strings.xml1452
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml90
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml90
-rw-r--r--packages/SystemUI/res/values-da/strings.xml90
-rw-r--r--packages/SystemUI/res/values-de/strings.xml90
-rw-r--r--packages/SystemUI/res/values-el/strings.xml90
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml79
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml79
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml79
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml90
-rw-r--r--packages/SystemUI/res/values-es/strings.xml91
-rw-r--r--packages/SystemUI/res/values-et-rEE/strings.xml77
-rw-r--r--packages/SystemUI/res/values-eu-rES/strings.xml90
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml77
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml90
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml90
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml90
-rw-r--r--packages/SystemUI/res/values-gl-rES/strings.xml90
-rw-r--r--packages/SystemUI/res/values-gu-rIN/strings.xml77
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml77
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml78
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml77
-rw-r--r--packages/SystemUI/res/values-hy-rAM/strings.xml90
-rw-r--r--packages/SystemUI/res/values-in/strings.xml90
-rw-r--r--packages/SystemUI/res/values-is-rIS/strings.xml90
-rw-r--r--packages/SystemUI/res/values-it/strings.xml90
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml90
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml90
-rw-r--r--packages/SystemUI/res/values-ka-rGE/strings.xml92
-rw-r--r--packages/SystemUI/res/values-kk-rKZ/strings.xml91
-rw-r--r--packages/SystemUI/res/values-km-rKH/strings.xml77
-rw-r--r--packages/SystemUI/res/values-kn-rIN/strings.xml77
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml77
-rw-r--r--packages/SystemUI/res/values-ky-rKG/strings.xml92
-rw-r--r--packages/SystemUI/res/values-lo-rLA/strings.xml79
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml90
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml90
-rw-r--r--packages/SystemUI/res/values-mk-rMK/strings.xml77
-rw-r--r--packages/SystemUI/res/values-ml-rIN/strings.xml77
-rw-r--r--packages/SystemUI/res/values-mn-rMN/strings.xml90
-rw-r--r--packages/SystemUI/res/values-mr-rIN/strings.xml90
-rw-r--r--packages/SystemUI/res/values-ms-rMY/strings.xml90
-rw-r--r--packages/SystemUI/res/values-my-rMM/strings.xml79
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml90
-rw-r--r--packages/SystemUI/res/values-ne-rNP/strings.xml80
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml77
-rw-r--r--packages/SystemUI/res/values-pa-rIN/strings.xml77
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml92
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml91
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml90
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml91
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml126
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml90
-rw-r--r--packages/SystemUI/res/values-si-rLK/strings.xml77
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml90
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml79
-rw-r--r--packages/SystemUI/res/values-sq-rAL/strings.xml77
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml90
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml90
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml77
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/config.xml3
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml6
-rw-r--r--packages/SystemUI/res/values-sw600dp/styles.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-ta-rIN/strings.xml77
-rw-r--r--packages/SystemUI/res/values-te-rIN/strings.xml77
-rw-r--r--packages/SystemUI/res/values-th/strings.xml92
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml90
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml90
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml90
-rw-r--r--packages/SystemUI/res/values-ur-rPK/strings.xml90
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml116
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml78
-rw-r--r--packages/SystemUI/res/values-w550dp-land/config.xml4
-rw-r--r--packages/SystemUI/res/values-w550dp-land/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml90
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml90
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml90
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml90
-rw-r--r--packages/SystemUI/res/values/attrs.xml1
-rw-r--r--packages/SystemUI/res/values/colors.xml7
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml69
-rw-r--r--packages/SystemUI/res/values/dimens_tv.xml5
-rw-r--r--packages/SystemUI/res/values/ids.xml10
-rw-r--r--packages/SystemUI/res/values/strings.xml166
-rw-r--r--packages/SystemUI/res/values/strings_tv.xml4
-rw-r--r--packages/SystemUI/res/values/styles.xml2
-rw-r--r--packages/SystemUI/res/values/values_tv.xml4
-rw-r--r--packages/SystemUI/res/xml/color_and_appearance.xml30
-rw-r--r--packages/SystemUI/res/xml/night_mode.xml47
-rw-r--r--packages/SystemUI/res/xml/tuner_prefs.xml104
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/EventLogConstants.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/EventLogTags.logtags10
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java216
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainer.java177
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetail.java287
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSIconView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java267
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java248
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java112
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/Task.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java193
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java102
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java321
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java231
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java176
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java177
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java222
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java233
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java130
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java220
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java148
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java341
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java126
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java316
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java237
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java285
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java193
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java250
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java90
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java183
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java519
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java481
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java90
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java219
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java341
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java203
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java141
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java341
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java150
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java273
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java10
-rw-r--r--packages/SystemUI/tests/Android.mk7
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml2
l---------packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java188
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java9
-rw-r--r--preloaded-classes1464
-rw-r--r--proto/jarjar-rules.txt3
-rw-r--r--proto/src/metrics_constants.proto129
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp160
-rw-r--r--services/accessibility/Android.mk2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java20
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java58
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java23
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java119
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java560
-rw-r--r--services/backup/java/com/android/server/backup/Trampoline.java2
-rw-r--r--services/core/java/com/android/server/AppOpsService.java159
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java26
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java137
-rw-r--r--services/core/java/com/android/server/HardwarePropertiesManagerService.java99
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java216
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java10
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java73
-rw-r--r--services/core/java/com/android/server/MountService.java5
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java2
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java18
-rw-r--r--services/core/java/com/android/server/PersistentDataBlockService.java18
-rw-r--r--services/core/java/com/android/server/RecoverySystemService.java214
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java218
-rw-r--r--services/core/java/com/android/server/SystemConfig.java46
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java130
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java328
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java106
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java196
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java161
-rw-r--r--services/core/java/com/android/server/am/ActivityStartInterceptor.java52
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java60
-rw-r--r--services/core/java/com/android/server/am/AppErrorDialog.java10
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java16
-rw-r--r--services/core/java/com/android/server/am/AppNotRespondingDialog.java10
-rw-r--r--services/core/java/com/android/server/am/RecentTasks.java81
-rw-r--r--services/core/java/com/android/server/am/TaskPersister.java120
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java123
-rw-r--r--services/core/java/com/android/server/am/UserController.java48
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java80
-rw-r--r--services/core/java/com/android/server/audio/RecordingActivityMonitor.java51
-rw-r--r--services/core/java/com/android/server/connectivity/MetricsLoggerService.java177
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkDiagnostics.java90
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java1
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java246
-rw-r--r--services/core/java/com/android/server/content/SyncOperation.java100
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java7
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java66
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java8
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java4
-rw-r--r--services/core/java/com/android/server/firewall/IntentFirewall.java2
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java597
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java27
-rw-r--r--services/core/java/com/android/server/job/JobStore.java245
-rw-r--r--services/core/java/com/android/server/job/controllers/AppIdleController.java59
-rw-r--r--services/core/java/com/android/server/job/controllers/BatteryController.java45
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java37
-rw-r--r--services/core/java/com/android/server/job/controllers/ContentObserverController.java207
-rw-r--r--services/core/java/com/android/server/job/controllers/IdleController.java45
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java494
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java17
-rw-r--r--services/core/java/com/android/server/job/controllers/TimeController.java138
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java67
-rw-r--r--services/core/java/com/android/server/location/GnssStatusListenerHelper.java6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java119
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java3
-rw-r--r--services/core/java/com/android/server/net/IpConfigStore.java6
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java302
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java21
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsAccess.java8
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java28
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsObservers.java493
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsRecorder.java86
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java135
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java10
-rw-r--r--services/core/java/com/android/server/notification/ImportanceExtractor.java (renamed from services/core/java/com/android/server/notification/TopicImportanceExtractor.java)7
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java36
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java134
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java77
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java5
-rw-r--r--services/core/java/com/android/server/notification/PriorityExtractor.java (renamed from services/core/java/com/android/server/notification/TopicPriorityExtractor.java)7
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java23
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java286
-rw-r--r--services/core/java/com/android/server/notification/ScheduleCalendar.java30
-rw-r--r--services/core/java/com/android/server/notification/ScheduleConditionProvider.java33
-rw-r--r--services/core/java/com/android/server/notification/VisibilityExtractor.java (renamed from services/core/java/com/android/server/notification/TopicVisibilityExtractor.java)10
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java36
-rw-r--r--services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java3
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java16
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java89
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java1376
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java153
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java20
-rw-r--r--services/core/java/com/android/server/pm/Settings.java95
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java88
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java2
-rw-r--r--services/core/java/com/android/server/policy/GlobalActions.java5
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java233
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java22
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java23
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java164
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java77
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java81
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java118
-rw-r--r--services/core/java/com/android/server/twilight/TwilightManager.java1
-rw-r--r--services/core/java/com/android/server/twilight/TwilightService.java214
-rw-r--r--services/core/java/com/android/server/twilight/TwilightState.java57
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java512
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateService.java257
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java77
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java22
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java181
-rw-r--r--services/core/java/com/android/server/wm/AppWindowAnimator.java7
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java51
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java35
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java52
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java255
-rw-r--r--services/core/java/com/android/server/wm/DragState.java231
-rw-r--r--services/core/java/com/android/server/wm/Session.java17
-rw-r--r--services/core/java/com/android/server/wm/Task.java65
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java421
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java462
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java150
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java362
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java37
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java41
-rw-r--r--services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java (renamed from core/java/android/view/animation/ClipRectLRAnimation.java)8
-rw-r--r--services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java86
-rw-r--r--services/core/jni/Android.mk1
-rw-r--r--services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp (renamed from core/jni/android_os_HardwarePropertiesManager.cpp)12
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp2
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp1016
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java557
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java112
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java101
-rw-r--r--services/java/com/android/server/SystemServer.java37
-rw-r--r--services/net/java/android/net/dhcp/DhcpClient.java102
-rw-r--r--services/net/java/android/net/ip/IpManager.java591
-rw-r--r--services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml2
-rw-r--r--services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml5
-rw-r--r--services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java111
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java181
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobStoreTest.java99
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java634
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java)439
-rw-r--r--services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java36
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java202
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java1
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java765
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java79
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java4
-rw-r--r--telecomm/java/android/telecom/Conference.java10
-rw-r--r--telecomm/java/android/telecom/Connection.java32
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java18
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java16
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java19
-rw-r--r--telecomm/java/android/telecom/DisconnectCause.java2
-rw-r--r--telecomm/java/android/telecom/Log.java35
-rw-r--r--telecomm/java/android/telecom/RemoteConnection.java23
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java7
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java43
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl7
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java44
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java243
-rw-r--r--telephony/java/com/android/ims/ImsCallProfile.java3
-rw-r--r--telephony/java/com/android/ims/ImsReasonInfo.java31
-rw-r--r--telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl29
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl32
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java48
-rw-r--r--test-runner/src/android/test/mock/MockContext.java5
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java22
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java9
-rw-r--r--tests/BatteryWaster/res/layout/battery_waster.xml3
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk2
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp3
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp2
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java91
-rw-r--r--tests/SoundTriggerTestApp/Android.mk1
-rw-r--r--tests/SoundTriggerTestApp/AndroidManifest.xml14
-rw-r--r--tests/SoundTriggerTestApp/res/layout/main.xml64
-rw-r--r--tests/SoundTriggerTestApp/res/values/strings.xml14
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java11
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java206
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java195
-rw-r--r--tests/UiBench/res/layout/activity_transition.xml17
-rw-r--r--tests/UiBench/src/com/android/test/uibench/ActivityTransition.java9
-rw-r--r--tests/touchlag/Android.mk2
-rw-r--r--tests/touchlag/touchlag.cpp8
-rw-r--r--tools/aapt/Resource.cpp10
-rw-r--r--tools/aapt/ResourceTable.cpp77
-rw-r--r--tools/aapt/ResourceTable.h12
-rw-r--r--tools/aapt2/Android.mk25
-rw-r--r--tools/aapt2/Debug.cpp41
-rw-r--r--tools/aapt2/Debug.h6
-rw-r--r--tools/aapt2/Format.proto210
-rw-r--r--tools/aapt2/Main.cpp5
-rw-r--r--tools/aapt2/ResourceParser.cpp46
-rw-r--r--tools/aapt2/ResourceParser.h10
-rw-r--r--tools/aapt2/ResourceParser_test.cpp60
-rw-r--r--tools/aapt2/ResourceTable.cpp145
-rw-r--r--tools/aapt2/ResourceTable.h139
-rw-r--r--tools/aapt2/ResourceTable_test.cpp44
-rw-r--r--tools/aapt2/ResourceUtils.cpp4
-rw-r--r--tools/aapt2/ResourceUtils.h3
-rw-r--r--tools/aapt2/ResourceUtils_test.cpp2
-rw-r--r--tools/aapt2/ResourceValues.cpp5
-rw-r--r--tools/aapt2/ResourceValues.h10
-rw-r--r--tools/aapt2/SdkConstants_test.cpp38
-rw-r--r--tools/aapt2/ValueVisitor.h18
-rw-r--r--tools/aapt2/compile/Compile.cpp194
-rw-r--r--tools/aapt2/compile/IdAssigner.cpp10
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.cpp50
-rw-r--r--tools/aapt2/dump/Dump.cpp139
-rw-r--r--tools/aapt2/flatten/Archive.h8
-rw-r--r--tools/aapt2/flatten/FileExportWriter.h67
-rw-r--r--tools/aapt2/flatten/FileExportWriter_test.cpp51
-rw-r--r--tools/aapt2/flatten/ResourceTypeExtensions.h202
-rw-r--r--tools/aapt2/flatten/TableFlattener.cpp406
-rw-r--r--tools/aapt2/flatten/TableFlattener.h15
-rw-r--r--tools/aapt2/flatten/TableFlattener_test.cpp89
-rw-r--r--tools/aapt2/java/JavaClassGenerator.cpp14
-rw-r--r--tools/aapt2/link/AutoVersioner.cpp37
-rw-r--r--tools/aapt2/link/AutoVersioner_test.cpp14
-rw-r--r--tools/aapt2/link/Link.cpp715
-rw-r--r--tools/aapt2/link/Linkers.h2
-rw-r--r--tools/aapt2/link/ProductFilter.cpp118
-rw-r--r--tools/aapt2/link/ProductFilter.h49
-rw-r--r--tools/aapt2/link/ProductFilter_test.cpp136
-rw-r--r--tools/aapt2/link/ReferenceLinker.cpp2
-rw-r--r--tools/aapt2/link/TableMerger.cpp54
-rw-r--r--tools/aapt2/link/TableMerger.h30
-rw-r--r--tools/aapt2/link/TableMerger_test.cpp59
-rw-r--r--tools/aapt2/process/IResourceTableConsumer.h1
-rw-r--r--tools/aapt2/process/SymbolTable.cpp10
-rw-r--r--tools/aapt2/proto/ProtoHelpers.cpp137
-rw-r--r--tools/aapt2/proto/ProtoHelpers.h52
-rw-r--r--tools/aapt2/proto/ProtoSerialize.h77
-rw-r--r--tools/aapt2/proto/TableProtoDeserializer.cpp511
-rw-r--r--tools/aapt2/proto/TableProtoSerializer.cpp319
-rw-r--r--tools/aapt2/proto/TableProtoSerializer_test.cpp133
-rw-r--r--tools/aapt2/split/TableSplitter.cpp264
-rw-r--r--tools/aapt2/split/TableSplitter.h78
-rw-r--r--tools/aapt2/split/TableSplitter_test.cpp107
-rw-r--r--tools/aapt2/test/Builders.h12
-rw-r--r--tools/aapt2/test/Common.h27
-rw-r--r--tools/aapt2/test/Context.h4
-rw-r--r--tools/aapt2/unflatten/BinaryResourceParser.cpp432
-rw-r--r--tools/aapt2/unflatten/BinaryResourceParser.h27
-rw-r--r--tools/aapt2/unflatten/FileExportHeaderReader.h159
-rw-r--r--tools/aapt2/unflatten/FileExportHeaderReader_test.cpp58
-rw-r--r--tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml10
-rw-r--r--tools/layoutlib/.idea/misc.xml2
-rw-r--r--tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml2
-rw-r--r--tools/layoutlib/Android.mk2
-rw-r--r--tools/layoutlib/bridge/Android.mk3
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeResources.java3
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java37
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java85
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java38
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java321
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java27
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java370
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java13
-rw-r--r--tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java757
-rw-r--r--tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java6
-rw-r--r--tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java37
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java5
-rw-r--r--tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java44
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java11
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java18
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java17
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java2
-rw-r--r--tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/tests/Android.mk3
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java8
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java3
-rw-r--r--tools/layoutlib/create/Android.mk2
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java11
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java19
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java55
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java1
-rw-r--r--tools/layoutlib/create/tests/Android.mk2
-rw-r--r--wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java6
-rw-r--r--wifi/java/android/net/wifi/RttManager.java16
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java34
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java94
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java229
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java25
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java121
-rw-r--r--wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java15
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanEventListener.java2
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanManager.java2
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanSession.java2
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanSessionListener.java2
1782 files changed, 72713 insertions, 36472 deletions
diff --git a/Android.mk b/Android.mk
index 6ec434cfbf54..2ee7600d3288 100644
--- a/Android.mk
+++ b/Android.mk
@@ -194,6 +194,8 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/ICaptivePortal.aidl \
core/java/android/net/IConnectivityManager.aidl \
+ core/java/android/net/IConnectivityMetricsLogger.aidl \
+ core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -215,6 +217,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IBatteryPropertiesRegistrar.aidl \
core/java/android/os/ICancellationSignal.aidl \
core/java/android/os/IDeviceIdleController.aidl \
+ core/java/android/os/IHardwarePropertiesManager.aidl \
core/java/android/os/IMaintenanceActivityListener.aidl \
core/java/android/os/IMessenger.aidl \
core/java/android/os/INetworkActivityListener.aidl \
@@ -222,6 +225,8 @@ LOCAL_SRC_FILES += \
core/java/android/os/IPermissionController.aidl \
core/java/android/os/IProcessInfoService.aidl \
core/java/android/os/IPowerManager.aidl \
+ core/java/android/os/IRecoverySystem.aidl \
+ core/java/android/os/IRecoverySystemProgressListener.aidl \
core/java/android/os/IRemoteCallback.aidl \
core/java/android/os/ISchedulingPolicyService.aidl \
core/java/android/os/IUpdateLock.aidl \
@@ -306,6 +311,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
core/java/com/android/internal/policy/IKeyguardService.aidl \
core/java/com/android/internal/policy/IKeyguardStateCallback.aidl \
+ core/java/com/android/internal/policy/IShortcutService.aidl \
core/java/com/android/internal/os/IDropBoxManagerService.aidl \
core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl \
core/java/com/android/internal/os/IResultReceiver.aidl \
@@ -455,7 +461,7 @@ LOCAL_INTERMEDIATE_SOURCES := \
$(framework_res_source_path)/com/android/internal/R.java
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp core-junit bouncycastle ext
+LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs conscrypt okhttp core-junit bouncycastle ext
LOCAL_STATIC_JAVA_LIBRARIES := framework-protos
LOCAL_MODULE := framework
diff --git a/api/current.txt b/api/current.txt
index 8884a01e8da6..f1647d04eaf6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -101,7 +101,6 @@ package android {
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
- field public static final java.lang.String READ_WRITE_CONTACT_METADATA = "android.permission.READ_WRITE_CONTACT_METADATA";
field public static final java.lang.String REBOOT = "android.permission.REBOOT";
field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
@@ -198,7 +197,6 @@ package android {
public static final class R.attr {
ctor public R.attr();
- field public static final int abiOverride = 16844054; // 0x1010516
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -301,6 +299,7 @@ package android {
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -338,6 +337,7 @@ package android {
field public static final int calendarViewStyle = 16843613; // 0x101035d
field public static final int canControlMagnification = 16844040; // 0x1010508
field public static final int canPerformGestures = 16844046; // 0x101050e
+ field public static final int canRecord = 16844061; // 0x101051d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -423,6 +423,7 @@ package android {
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
field public static final int controlY2 = 16843775; // 0x10103ff
+ field public static final int countDown = 16844060; // 0x101051c
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
@@ -1358,6 +1359,7 @@ package android {
field public static final int trimPathEnd = 16843785; // 0x1010409
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
+ field public static final int tunerCount = 16844062; // 0x101051e
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1365,6 +1367,7 @@ package android {
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
+ field public static final int use32bitAbi = 16844054; // 0x1010516
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
@@ -1376,6 +1379,7 @@ package android {
field public static final int valueType = 16843488; // 0x10102e0
field public static final int variablePadding = 16843157; // 0x1010195
field public static final int vendor = 16843751; // 0x10103e7
+ field public static final int version = 16844058; // 0x101051a
field public static final int versionCode = 16843291; // 0x101021b
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -2661,6 +2665,7 @@ package android.accessibilityservice {
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
}
@@ -4877,7 +4882,6 @@ package android.app {
method public android.graphics.drawable.Icon getLargeIcon();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
- method public android.app.Notification.Topic getTopic();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4903,6 +4907,7 @@ package android.app {
field public static final int DEFAULT_VIBRATE = 2; // 0x2
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_COUNTS_DOWN = "android.chronometerCountsDown";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
@@ -4941,7 +4946,6 @@ package android.app {
field public static final int PRIORITY_MAX = 2; // 0x2
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
- field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
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
@@ -5045,16 +5049,17 @@ package android.app {
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.widget.RemoteViews createBigContentView();
+ method public android.widget.RemoteViews createContentView();
+ method public android.widget.RemoteViews createHeadsUpContentView();
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
- method public android.widget.RemoteViews makeBigContentView();
- method public android.widget.RemoteViews makeContentView();
- method public android.widget.RemoteViews makeHeadsUpContentView();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
+ method public android.app.Notification.Builder setChronometerCountsDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
@@ -5093,7 +5098,6 @@ package android.app {
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 setTopic(android.app.Notification.Topic);
method public android.app.Notification.Builder setUsesChronometer(boolean);
method public android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
@@ -5131,6 +5135,16 @@ package android.app {
method public android.app.PendingIntent getReplyPendingIntent();
}
+ public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
+ ctor public Notification.DecoratedCustomViewStyle();
+ ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
+ }
+
+ public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+ ctor public Notification.DecoratedMediaCustomViewStyle();
+ ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+ }
+
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
@@ -5161,16 +5175,6 @@ package android.app {
field protected android.app.Notification.Builder mBuilder;
}
- public static class Notification.Topic implements android.os.Parcelable {
- ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
- method public android.app.Notification.Topic clone();
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.CharSequence getLabel();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
- }
-
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
@@ -5225,6 +5229,7 @@ package android.app {
public class NotificationManager {
method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+ method public boolean areNotificationsEnabled();
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5232,6 +5237,7 @@ package android.app {
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
+ method public int getImportance();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -5716,6 +5722,7 @@ package android.app {
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
+ method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
method public boolean isWallpaperSettingAllowed();
@@ -5826,9 +5833,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 deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
- method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
@@ -5883,6 +5888,7 @@ package android.app.admin {
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
+ method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
@@ -5926,7 +5932,7 @@ package android.app.admin {
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
method public void setOrganizationName(android.content.ComponentName, java.lang.String);
- method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
+ method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -8002,6 +8008,7 @@ package android.content {
method public final int getColor(int);
method public final android.content.res.ColorStateList getColorStateList(int);
method public abstract android.content.ContentResolver getContentResolver();
+ method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8194,6 +8201,7 @@ package android.content {
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -8465,6 +8473,7 @@ package android.content {
field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
+ field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
@@ -8510,6 +8519,7 @@ package android.content {
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -8529,7 +8539,6 @@ package android.content {
field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
- field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
@@ -9397,6 +9406,7 @@ package android.content.pm {
field public int flags;
field public java.lang.String name;
field public int reqGlEsVersion;
+ field public int version;
}
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -9675,6 +9685,7 @@ package android.content.pm {
method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
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 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);
@@ -9778,6 +9789,8 @@ 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_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";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -11939,6 +11952,8 @@ package android.graphics {
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -12966,12 +12981,10 @@ package android.graphics.drawable {
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
@@ -13194,8 +13207,8 @@ package android.hardware {
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void unlock();
- field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
- field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+ field public static final deprecated java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+ field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -19157,11 +19170,10 @@ package android.location {
method public double getDriftInNsPerSec();
method public double getDriftUncertaintyInNsPerSec();
method public long getFullBiasInNs();
+ method public int getHardwareClockDiscontinuityCount();
method public short getLeapSecond();
method public long getTimeInNs();
- method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
- method public byte getType();
method public boolean hasBiasInNs();
method public boolean hasBiasUncertaintyInNs();
method public boolean hasDriftInNsPerSec();
@@ -19183,21 +19195,14 @@ package android.location {
method public void setDriftInNsPerSec(double);
method public void setDriftUncertaintyInNsPerSec(double);
method public void setFullBiasInNs(long);
+ method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
- method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
- method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
- field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
- field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
- public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
- }
-
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
@@ -19213,23 +19218,22 @@ package android.location {
method public double getCn0InDbHz();
method public double getCodePhaseInChips();
method public double getCodePhaseUncertaintyInChips();
+ method public byte getConstellationType();
method public double getDopplerShiftInHz();
method public double getDopplerShiftUncertaintyInHz();
method public double getElevationInDeg();
method public double getElevationUncertaintyInDeg();
method public byte getLossOfLock();
method public byte getMultipathIndicator();
- method public byte getPrn();
method public double getPseudorangeInMeters();
- method public double getPseudorangeRateCarrierInMetersPerSec();
- method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedGpsTowInNs();
- method public long getReceivedGpsTowUncertaintyInNs();
+ method public long getReceivedSvTimeInNs();
+ method public long getReceivedSvTimeUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
+ method public short getSvid();
method public short getTimeFromLastBitInMs();
method public double getTimeOffsetInNs();
method public boolean hasAzimuthInDeg();
@@ -19283,23 +19287,22 @@ package android.location {
method public void setCn0InDbHz(double);
method public void setCodePhaseInChips(double);
method public void setCodePhaseUncertaintyInChips(double);
+ method public void setConstellationType(byte);
method public void setDopplerShiftInHz(double);
method public void setDopplerShiftUncertaintyInHz(double);
method public void setElevationInDeg(double);
method public void setElevationUncertaintyInDeg(double);
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
- method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateCarrierInMetersPerSec(double);
- method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedGpsTowInNs(long);
- method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setReceivedSvTimeInNs(long);
+ method public void setReceivedSvTimeUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
+ method public void setSvid(short);
method public void setTimeFromLastBitInMs(short);
method public void setTimeOffsetInNs(double);
method public void setUsedInFix(boolean);
@@ -19354,25 +19357,30 @@ package android.location {
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
- method public byte getPrn();
method public short getStatus();
method public short getSubmessageId();
- method public byte getType();
+ method public short getSvid();
+ method public short getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
method public void setMessageId(short);
- method public void setPrn(byte);
method public void setStatus(short);
method public void setSubmessageId(short);
- method public void setType(byte);
+ method public void setSvid(short);
+ method public void setType(short);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
- field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
- field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
- field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
- field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
+ field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
+ field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
+ field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
+ field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
+ field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
+ field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
@@ -19407,21 +19415,24 @@ package android.location {
public final class GnssStatus {
method public float getAzimuth(int);
- method public int getConstellationType(int);
+ method public byte getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
- method public int getPrn(int);
method public float getSnr(int);
+ method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final int CONSTELLATION_GALILEO = 6; // 0x6
- field public static final int CONSTELLATION_GLONASS = 3; // 0x3
- field public static final int CONSTELLATION_GPS = 1; // 0x1
- field public static final int CONSTELLATION_QZSS = 4; // 0x4
- field public static final int CONSTELLATION_SBAS = 2; // 0x2
- field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final byte CONSTELLATION_GPS = 1; // 0x1
+ field public static final byte CONSTELLATION_QZSS = 4; // 0x4
+ field public static final byte CONSTELLATION_SBAS = 2; // 0x2
+ field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
}
public abstract class GnssStatusCallback {
@@ -19679,6 +19690,7 @@ package android.media {
field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+ field public static final int TYPE_BUS = 21; // 0x15
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_FM = 14; // 0xe
field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -19696,12 +19708,14 @@ package android.media {
field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
}
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
+ method public int describeContents();
method public int getChannelCount();
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -19743,6 +19757,7 @@ package android.media {
field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+ field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DTS = 7; // 0x7
@@ -19753,6 +19768,7 @@ package android.media {
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
+ field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
}
public static class AudioFormat.Builder {
@@ -20006,6 +20022,7 @@ package android.media {
public abstract interface AudioRouting {
method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
+ method public abstract android.media.AudioDeviceInfo getRoutedDevice();
method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -20186,6 +20203,8 @@ package android.media {
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+ ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public java.lang.String getAttribute(java.lang.String);
method public double getAttributeDouble(java.lang.String, double);
@@ -20207,6 +20226,10 @@ package android.media {
field public static final java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_DATETIME = "DateTime";
field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+ field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
field public static final java.lang.String TAG_FLASH = "Flash";
field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
@@ -20222,9 +20245,12 @@ package android.media {
field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
field public static final java.lang.String TAG_MAKE = "Make";
+ field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
field public static final java.lang.String TAG_MODEL = "Model";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+ field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
@@ -20965,6 +20991,7 @@ package android.media {
field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+ field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
field public static final java.lang.String KEY_PRIORITY = "priority";
field public static final java.lang.String KEY_PROFILE = "profile";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -21173,6 +21200,7 @@ package android.media {
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;
+ method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
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;
@@ -22539,6 +22567,10 @@ package android.media.session {
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -22572,7 +22604,6 @@ package android.media.session {
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22587,6 +22618,10 @@ package android.media.session {
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onPrepare();
+ 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 onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -22643,6 +22678,10 @@ package android.media.session {
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
@@ -22651,7 +22690,6 @@ package android.media.session {
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
- field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22727,6 +22765,10 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final boolean isChannelUri(android.net.Uri);
+ method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+ method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+ method public static final boolean isProgramUri(android.net.Uri);
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
@@ -22818,7 +22860,8 @@ package android.media.tv {
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_NUMBER = "episode_number";
+ 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";
@@ -22828,7 +22871,9 @@ package android.media.tv {
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_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ 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_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -22844,6 +22889,7 @@ package android.media.tv {
public static final class TvContract.Programs.Genres {
method public static java.lang.String[] decode(java.lang.String);
method public static java.lang.String encode(java.lang.String...);
+ method public static boolean isCanonical(java.lang.String);
field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
field public static final java.lang.String ARTS = "ARTS";
field public static final java.lang.String COMEDY = "COMEDY";
@@ -22870,8 +22916,9 @@ package android.media.tv {
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_NUMBER = "episode_number";
+ 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";
@@ -22884,7 +22931,8 @@ package android.media.tv {
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_NUMBER = "season_number";
+ 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";
@@ -22907,7 +22955,9 @@ package android.media.tv {
method public android.content.pm.ServiceInfo getServiceInfo();
method public int getTunerCount();
method public int getType();
+ method public boolean isHidden(android.content.Context);
method public boolean isPassthroughInput();
+ method public java.lang.CharSequence loadCustomLabel(android.content.Context);
method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
method public java.lang.CharSequence loadLabel(android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
@@ -22943,13 +22993,13 @@ package android.media.tv {
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_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 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
field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
- field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
- field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
- field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+ field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+ field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -22969,7 +23019,7 @@ package android.media.tv {
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
method public void onInputUpdated(java.lang.String);
- method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
+ method public void onTvInputInfoUpdated(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22977,7 +23027,7 @@ package android.media.tv {
method public final android.os.IBinder onBind(android.content.Intent);
method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
- method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
+ method public static final void updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -22992,14 +23042,13 @@ package android.media.tv {
public static abstract class TvInputService.RecordingSession {
ctor public TvInputService.RecordingSession(android.content.Context);
- method public void notifyConnected();
method public void notifyError(int);
- method public void notifyRecordingStarted();
method public void notifyRecordingStopped(android.net.Uri);
- method public abstract void onConnect(android.net.Uri);
- method public abstract void onDisconnect();
- method public abstract void onStartRecording();
+ method public void notifyTuned();
+ method public abstract void onRelease();
+ method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
+ method public abstract void onTune(android.net.Uri);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23042,19 +23091,19 @@ package android.media.tv {
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
- method public void connect(java.lang.String, android.net.Uri);
- method public void disconnect();
- method public void startRecording();
+ method public void release();
+ method public void startRecording(android.net.Uri);
method public void stopRecording();
+ method public void tune(java.lang.String, android.net.Uri);
}
public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
- method public void onConnected();
- method public void onDisconnected();
+ method public void onConnectionFailed(java.lang.String);
+ method public void onDisconnected(java.lang.String);
method public void onError(int);
- method public void onRecordingStarted();
method public void onRecordingStopped(android.net.Uri);
+ method public void onTuned();
}
public final class TvTrackInfo implements android.os.Parcelable {
@@ -23066,6 +23115,7 @@ package android.media.tv {
method public final java.lang.String getId();
method public final java.lang.String getLanguage();
method public final int getType();
+ method public final byte getVideoActiveFormatDescription();
method public final float getVideoFrameRate();
method public final int getVideoHeight();
method public final float getVideoPixelAspectRatio();
@@ -23085,6 +23135,7 @@ package android.media.tv {
method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+ method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float);
@@ -23472,6 +23523,17 @@ package android.net {
method public abstract void onNetworkActive();
}
+ public class ConnectivityMetricsEvent implements android.os.Parcelable {
+ ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+ field public final int componentTag;
+ field public final android.os.Parcelable data;
+ field public final int eventTag;
+ field public final long timestamp;
+ }
+
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -26824,6 +26886,7 @@ package android.opengl {
method public static void glProgramBinary(int, int, java.nio.Buffer, int);
method public static void glProgramParameteri(int, int, int);
method public static void glReadBuffer(int);
+ method public static void glReadPixels(int, int, int, int, int, int, int);
method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
method public static void glResumeTransformFeedback();
method public static void glSamplerParameterf(int, int, float);
@@ -28409,6 +28472,10 @@ package android.os {
ctor public DeadObjectException(java.lang.String);
}
+ public class DeadSystemException extends android.os.DeadObjectException {
+ ctor public DeadSystemException();
+ }
+
public final class Debug {
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
@@ -28566,7 +28633,6 @@ package android.os {
field public static java.lang.String DIRECTORY_DCIM;
field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
- field public static java.lang.String DIRECTORY_HOME;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -29042,7 +29108,6 @@ package android.os {
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -29062,6 +29127,7 @@ package android.os {
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
+ method public static boolean isApplicationUid(int);
method public static final void killProcess(int);
method public static final int myPid();
method public static final int myTid();
@@ -29242,6 +29308,7 @@ package android.os {
public final class UserHandle implements android.os.Parcelable {
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
+ method public static android.os.UserHandle getUserHandleForUid(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -29355,11 +29422,27 @@ package android.os.storage {
public class StorageManager {
method public java.lang.String getMountedObbPath(java.lang.String);
+ method public android.os.storage.StorageVolume getPrimaryVolume();
+ method public android.os.storage.StorageVolume[] getVolumeList();
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
}
+ public class StorageVolume implements android.os.Parcelable {
+ method public android.content.Intent createAccessIntent(java.lang.String);
+ method public int describeContents();
+ method public java.lang.String getDescription(android.content.Context);
+ method public java.lang.String getState();
+ method public java.lang.String getUuid();
+ method public boolean isEmulated();
+ method public boolean isPrimary();
+ method public boolean isRemovable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.storage.StorageVolume> CREATOR;
+ field public static final java.lang.String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
+ }
+
}
package android.preference {
@@ -29474,6 +29557,7 @@ package android.preference {
method protected int getPersistedInt(int);
method protected long getPersistedLong(long);
method protected java.lang.String getPersistedString(java.lang.String);
+ method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
method public android.preference.PreferenceManager getPreferenceManager();
method public android.content.SharedPreferences getSharedPreferences();
method public boolean getShouldDisableView();
@@ -29508,6 +29592,7 @@ package android.preference {
method protected boolean persistInt(int);
method protected boolean persistLong(long);
method protected boolean persistString(java.lang.String);
+ method public boolean persistStringSet(java.util.Set<java.lang.String>);
method public void restoreHierarchyState(android.os.Bundle);
method public void saveHierarchyState(android.os.Bundle);
method public void setDefaultValue(java.lang.Object);
@@ -31459,6 +31544,8 @@ package android.provider {
}
protected static abstract interface ContactsContract.PhoneLookupColumns {
+ field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String DATA_ID = "data_id";
field public static final java.lang.String LABEL = "label";
field public static final java.lang.String NORMALIZED_NUMBER = "normalized_number";
field public static final java.lang.String NUMBER = "number";
@@ -31722,6 +31809,7 @@ package android.provider {
method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+ method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
@@ -31742,7 +31830,7 @@ package android.provider {
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
- method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+ method public void removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -32142,10 +32230,10 @@ package android.provider {
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
- field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34046,6 +34134,7 @@ package android.security.keystore {
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+ method public byte[] getAttestationChallenge();
method public java.lang.String[] getBlockModes();
method public java.util.Date getCertificateNotAfter();
method public java.util.Date getCertificateNotBefore();
@@ -34062,14 +34151,17 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyGenParameterSpec.Builder {
ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
method public android.security.keystore.KeyGenParameterSpec build();
method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
@@ -34077,6 +34169,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -34085,6 +34178,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34102,8 +34196,10 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isInsideSecureHardware();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -34164,8 +34260,10 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyProtection.Builder {
@@ -34174,6 +34272,7 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -34181,6 +34280,7 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34477,10 +34577,11 @@ package android.service.notification {
method public int getSuppressedVisualEffects();
method public boolean isAmbient();
method public boolean matchesInterruptionFilter();
- field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
- field public static final int IMPORTANCE_HIGH = 3; // 0x3
- field public static final int IMPORTANCE_LOW = 1; // 0x1
- field public static final int IMPORTANCE_MAX = 4; // 0x4
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
field public static final int IMPORTANCE_NONE = 0; // 0x0
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}
@@ -34551,6 +34652,7 @@ package android.service.quicksettings {
method public final void startActivityAndCollapse(android.content.Intent);
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
@@ -36041,6 +36143,7 @@ package android.telecom {
method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public final java.util.Collection<android.telecom.Conference> getAllConferences();
method public final java.util.Collection<android.telecom.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
@@ -36317,6 +36420,7 @@ package android.telecom {
public class TelecomManager {
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
+ method public android.content.Intent createManageBlockedNumbersIntent();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
method public java.lang.String getDefaultDialerPackage();
@@ -36409,9 +36513,11 @@ package android.telecom {
package android.telephony {
public class CarrierConfigManager {
+ method public android.os.PersistableBundle getConfig(int);
method public android.os.PersistableBundle getConfig();
- method public android.os.PersistableBundle getConfigForSubId(int);
- method public void notifyConfigChangedForSubId(int);
+ method public deprecated android.os.PersistableBundle getConfigForSubId(int);
+ method public void notifyConfigChanged(int);
+ method public deprecated void notifyConfigChangedForSubId(int);
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
field public static final java.lang.String BOOL_ALLOW_VIDEO_PAUSE = "bool_allow_video_pause";
@@ -37049,12 +37155,18 @@ package android.telephony {
method public int getVoiceNetworkType(int);
method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
+ method public boolean hasCarrierPrivileges(int);
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
+ method public boolean iccCloseLogicalChannel(int, int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+ method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+ method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+ method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
method public boolean isNetworkRoaming(int);
@@ -37065,10 +37177,13 @@ package android.telephony {
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+ method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
+ method public boolean setOperatorBrandOverride(int, java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
+ method public boolean setPreferredNetworkTypeToGlobal(int);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
@@ -37597,6 +37712,7 @@ package android.test.mock {
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -37782,6 +37898,7 @@ package android.test.mock {
method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
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 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);
@@ -40662,6 +40779,21 @@ package android.view {
method public static android.view.FocusFinder getInstance();
}
+ public final class FrameMetrics {
+ ctor public FrameMetrics(android.view.FrameMetrics);
+ method public long getMetric(int);
+ field public static final int ANIMATION_DURATION = 2; // 0x2
+ field public static final int COMMAND_ISSUE_DURATION = 6; // 0x6
+ field public static final int DRAW_DURATION = 4; // 0x4
+ field public static final int FIRST_DRAW_FRAME = 9; // 0x9
+ field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 3; // 0x3
+ field public static final int SWAP_BUFFERS_DURATION = 7; // 0x7
+ field public static final int SYNC_DURATION = 5; // 0x5
+ field public static final int TOTAL_DURATION = 8; // 0x8
+ field public static final int UNKNOWN_DELAY_DURATION = 0; // 0x0
+ }
+
public abstract class FrameStats {
ctor public FrameStats();
method public final long getEndTimeNano();
@@ -43165,6 +43297,7 @@ package android.view {
ctor public Window(android.content.Context);
method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void addFlags(int);
+ method public final void addFrameMetricsListener(android.view.Window.FrameMetricsListener, android.os.Handler);
method public void clearFlags(int);
method public abstract void closeAllPanels();
method public abstract void closePanel(int);
@@ -43216,6 +43349,7 @@ package android.view {
method public abstract boolean performContextMenuIdentifierAction(int, int);
method public abstract boolean performPanelIdentifierAction(int, int, int);
method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
+ method public final void removeFrameMetricsListener(android.view.Window.FrameMetricsListener);
method public boolean requestFeature(int);
method public abstract void restoreHierarchyState(android.os.Bundle);
method public abstract android.os.Bundle saveHierarchyState();
@@ -43341,6 +43475,10 @@ package android.view {
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static abstract interface Window.FrameMetricsListener {
+ method public abstract void onMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+ }
+
public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
}
@@ -43949,6 +44087,7 @@ package android.view.accessibility {
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
}
@@ -44288,6 +44427,7 @@ package android.view.inputmethod {
method public int getCursorCapsMode(int);
method public android.text.Editable getEditable();
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44451,6 +44591,7 @@ package android.view.inputmethod {
method public abstract boolean finishComposingText();
method public abstract int getCursorCapsMode(int);
method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public abstract android.os.Handler getHandler();
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44482,6 +44623,7 @@ package android.view.inputmethod {
method public boolean finishComposingText();
method public int getCursorCapsMode(int);
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -45988,7 +46130,9 @@ package android.widget {
method public long getBase();
method public java.lang.String getFormat();
method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
+ method public boolean isCountDown();
method public void setBase(long);
+ method public void setCountDown(boolean);
method public void setFormat(java.lang.String);
method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
method public void start();
@@ -47080,6 +47224,7 @@ package android.widget {
method public void setChar(int, java.lang.String, char);
method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
method public void setChronometer(int, long, java.lang.String, boolean);
+ method public void setChronometerCountsDown(int, boolean);
method public void setContentDescription(int, java.lang.CharSequence);
method public void setDisplayedChild(int, int);
method public void setDouble(int, java.lang.String, double);
@@ -51451,7 +51596,6 @@ package java.lang.reflect {
method public static int getLength(java.lang.Object);
method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
- method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -52127,7 +52271,6 @@ package java.net {
public class InetAddress implements java.io.Serializable {
method public byte[] getAddress();
- method public byte[] getAddressInternal();
method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
@@ -52401,7 +52544,7 @@ package java.net {
method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
method protected abstract void create(boolean) throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
+ method protected java.io.FileDescriptor getFileDescriptor();
method protected java.net.InetAddress getInetAddress();
method protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
method protected int getLocalPort();
@@ -52943,10 +53086,6 @@ package java.nio {
package java.nio.channels {
- public class AcceptPendingException extends java.lang.IllegalStateException {
- ctor public AcceptPendingException();
- }
-
public class AlreadyBoundException extends java.lang.IllegalStateException {
ctor public AlreadyBoundException();
}
@@ -52955,68 +53094,10 @@ package java.nio.channels {
ctor public AlreadyConnectedException();
}
- public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
- method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- }
-
- public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
- method public abstract void close() throws java.io.IOException;
- }
-
- public abstract class AsynchronousChannelGroup {
- ctor protected AsynchronousChannelGroup(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public abstract boolean isShutdown();
- method public abstract boolean isTerminated();
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void shutdown();
- method public abstract void shutdownNow() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withCachedThreadPool(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withFixedThreadPool(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withThreadPool(java.util.concurrent.ExecutorService) throws java.io.IOException;
- }
-
public class AsynchronousCloseException extends java.nio.channels.ClosedChannelException {
ctor public AsynchronousCloseException();
}
- public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
- method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
- method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- }
-
- public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
- method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
- method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- }
-
public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
}
@@ -53033,9 +53114,7 @@ package java.nio.channels {
method public static java.nio.channels.ReadableByteChannel newChannel(java.io.InputStream);
method public static java.nio.channels.WritableByteChannel newChannel(java.io.OutputStream);
method public static java.io.InputStream newInputStream(java.nio.channels.ReadableByteChannel);
- method public static java.io.InputStream newInputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
- method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
@@ -53054,16 +53133,11 @@ package java.nio.channels {
ctor public ClosedSelectorException();
}
- public abstract interface CompletionHandler {
- method public abstract void completed(V, A);
- method public abstract void failed(java.lang.Throwable, A);
- }
-
public class ConnectionPendingException extends java.lang.IllegalStateException {
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -53142,40 +53216,14 @@ package java.nio.channels {
ctor public IllegalBlockingModeException();
}
- public class IllegalChannelGroupException extends java.lang.IllegalArgumentException {
- ctor public IllegalChannelGroupException();
- }
-
public class IllegalSelectorException extends java.lang.IllegalArgumentException {
ctor public IllegalSelectorException();
}
- public class InterruptedByTimeoutException extends java.io.IOException {
- ctor public InterruptedByTimeoutException();
- }
-
public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
public abstract interface NetworkChannel implements java.nio.channels.Channel {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -53225,10 +53273,6 @@ package java.nio.channels {
method public final int validOps();
}
- public class ReadPendingException extends java.lang.IllegalStateException {
- ctor public ReadPendingException();
- }
-
public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
}
@@ -53306,10 +53350,6 @@ package java.nio.channels {
method public final int validOps();
}
- public class ShutdownChannelGroupException extends java.lang.IllegalStateException {
- ctor public ShutdownChannelGroupException();
- }
-
public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
@@ -53345,10 +53385,6 @@ package java.nio.channels {
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
}
- public class WritePendingException extends java.lang.IllegalStateException {
- ctor public WritePendingException();
- }
-
}
package java.nio.channels.spi {
@@ -53395,15 +53431,6 @@ package java.nio.channels.spi {
method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
}
- public abstract class AsynchronousChannelProvider {
- ctor protected AsynchronousChannelProvider();
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel openAsynchronousSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.spi.AsynchronousChannelProvider provider();
- }
-
public abstract class SelectorProvider {
ctor protected SelectorProvider();
method public java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
@@ -54218,7 +54245,6 @@ package java.security {
public abstract class Signature extends java.security.SignatureSpi {
ctor protected Signature(java.lang.String);
method public final java.lang.String getAlgorithm();
- method public java.security.SignatureSpi getCurrentSpi();
method public static java.security.Signature getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
method public static java.security.Signature getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.Signature getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
@@ -56758,13 +56784,11 @@ package java.text {
method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
method public java.lang.String getInternationalCurrencySymbol();
method public char getMinusSign();
- method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
method public java.lang.String getNaN();
method public char getPatternSeparator();
method public char getPerMill();
method public char getPercent();
- method public java.lang.String getPercentString();
method public char getZeroDigit();
method public void setCurrency(java.util.Currency);
method public void setCurrencySymbol(java.lang.String);
@@ -58017,8 +58041,11 @@ package java.util {
method public static boolean equals(java.lang.Object, java.lang.Object);
method public static int hash(java.lang.Object...);
method public static int hashCode(java.lang.Object);
+ method public static boolean isNull(java.lang.Object);
+ method public static boolean nonNull(java.lang.Object);
method public static T requireNonNull(T);
method public static T requireNonNull(T, java.lang.String);
+ method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
method public static java.lang.String toString(java.lang.Object);
method public static java.lang.String toString(java.lang.Object, java.lang.String);
}
@@ -59723,6 +59750,217 @@ package java.util.concurrent.locks {
}
+package java.util.function {
+
+ public abstract interface BiConsumer {
+ method public abstract void accept(T, U);
+ method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
+ }
+
+ public abstract interface BiFunction {
+ method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
+ method public abstract R apply(T, U);
+ }
+
+ public abstract interface BiPredicate {
+ method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
+ method public default java.util.function.BiPredicate<T, U> negate();
+ method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
+ method public abstract boolean test(T, U);
+ }
+
+ public abstract interface BinaryOperator implements java.util.function.BiFunction {
+ method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
+ method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
+ }
+
+ public abstract interface BooleanSupplier {
+ method public abstract boolean getAsBoolean();
+ }
+
+ public abstract interface Consumer {
+ method public abstract void accept(T);
+ method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
+ }
+
+ public abstract interface DoubleBinaryOperator {
+ method public abstract double applyAsDouble(double, double);
+ }
+
+ public abstract interface DoubleConsumer {
+ method public abstract void accept(double);
+ method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
+ }
+
+ public abstract interface DoubleFunction {
+ method public abstract R apply(double);
+ }
+
+ public abstract interface DoublePredicate {
+ method public default java.util.function.DoublePredicate and(java.util.function.DoublePredicate);
+ method public default java.util.function.DoublePredicate negate();
+ method public default java.util.function.DoublePredicate or(java.util.function.DoublePredicate);
+ method public abstract boolean test(double);
+ }
+
+ public abstract interface DoubleSupplier {
+ method public abstract double getAsDouble();
+ }
+
+ public abstract interface DoubleToIntFunction {
+ method public abstract int applyAsInt(double);
+ }
+
+ public abstract interface DoubleToLongFunction {
+ method public abstract long applyAsLong(double);
+ }
+
+ public abstract interface DoubleUnaryOperator {
+ method public default java.util.function.DoubleUnaryOperator andThen(java.util.function.DoubleUnaryOperator);
+ method public abstract double applyAsDouble(double);
+ method public default java.util.function.DoubleUnaryOperator compose(java.util.function.DoubleUnaryOperator);
+ method public static java.util.function.DoubleUnaryOperator identity();
+ }
+
+ public abstract interface Function {
+ method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
+ method public abstract R apply(T);
+ method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
+ method public static java.util.function.Function<T, T> identity();
+ }
+
+ public abstract interface IntBinaryOperator {
+ method public abstract int applyAsInt(int, int);
+ }
+
+ public abstract interface IntConsumer {
+ method public abstract void accept(int);
+ method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
+ }
+
+ public abstract interface IntFunction {
+ method public abstract R apply(int);
+ }
+
+ public abstract interface IntPredicate {
+ method public default java.util.function.IntPredicate and(java.util.function.IntPredicate);
+ method public default java.util.function.IntPredicate negate();
+ method public default java.util.function.IntPredicate or(java.util.function.IntPredicate);
+ method public abstract boolean test(int);
+ }
+
+ public abstract interface IntSupplier {
+ method public abstract int getAsInt();
+ }
+
+ public abstract interface IntToDoubleFunction {
+ method public abstract double applyAsDouble(int);
+ }
+
+ public abstract interface IntToLongFunction {
+ method public abstract long applyAsLong(int);
+ }
+
+ public abstract interface IntUnaryOperator {
+ method public default java.util.function.IntUnaryOperator andThen(java.util.function.IntUnaryOperator);
+ method public abstract int applyAsInt(int);
+ method public default java.util.function.IntUnaryOperator compose(java.util.function.IntUnaryOperator);
+ method public static java.util.function.IntUnaryOperator identity();
+ }
+
+ public abstract interface LongBinaryOperator {
+ method public abstract long applyAsLong(long, long);
+ }
+
+ public abstract interface LongConsumer {
+ method public abstract void accept(long);
+ method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
+ }
+
+ public abstract interface LongFunction {
+ method public abstract R apply(long);
+ }
+
+ public abstract interface LongPredicate {
+ method public default java.util.function.LongPredicate and(java.util.function.LongPredicate);
+ method public default java.util.function.LongPredicate negate();
+ method public default java.util.function.LongPredicate or(java.util.function.LongPredicate);
+ method public abstract boolean test(long);
+ }
+
+ public abstract interface LongSupplier {
+ method public abstract long getAsLong();
+ }
+
+ public abstract interface LongToDoubleFunction {
+ method public abstract double applyAsDouble(long);
+ }
+
+ public abstract interface LongToIntFunction {
+ method public abstract int applyAsInt(long);
+ }
+
+ public abstract interface LongUnaryOperator {
+ method public default java.util.function.LongUnaryOperator andThen(java.util.function.LongUnaryOperator);
+ method public abstract long applyAsLong(long);
+ method public default java.util.function.LongUnaryOperator compose(java.util.function.LongUnaryOperator);
+ method public static java.util.function.LongUnaryOperator identity();
+ }
+
+ public abstract interface ObjDoubleConsumer {
+ method public abstract void accept(T, double);
+ }
+
+ public abstract interface ObjIntConsumer {
+ method public abstract void accept(T, int);
+ }
+
+ public abstract interface ObjLongConsumer {
+ method public abstract void accept(T, long);
+ }
+
+ public abstract interface Predicate {
+ method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
+ method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
+ method public default java.util.function.Predicate<T> negate();
+ method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
+ method public abstract boolean test(T);
+ }
+
+ public abstract interface Supplier {
+ method public abstract T get();
+ }
+
+ public abstract interface ToDoubleBiFunction {
+ method public abstract double applyAsDouble(T, U);
+ }
+
+ public abstract interface ToDoubleFunction {
+ method public abstract double applyAsDouble(T);
+ }
+
+ public abstract interface ToIntBiFunction {
+ method public abstract int applyAsInt(T, U);
+ }
+
+ public abstract interface ToIntFunction {
+ method public abstract int applyAsInt(T);
+ }
+
+ public abstract interface ToLongBiFunction {
+ method public abstract long applyAsLong(T, U);
+ }
+
+ public abstract interface ToLongFunction {
+ method public abstract long applyAsLong(T);
+ }
+
+ public abstract interface UnaryOperator implements java.util.function.Function {
+ method public static java.util.function.UnaryOperator<T> identity();
+ }
+
+}
+
package java.util.jar {
public class Attributes implements java.lang.Cloneable java.util.Map {
@@ -62457,14 +62695,6 @@ package javax.security.auth {
method public abstract boolean isDestroyed();
}
- public abstract deprecated class Policy {
- ctor protected Policy();
- method public abstract java.security.PermissionCollection getPermissions(javax.security.auth.Subject, java.security.CodeSource);
- method public static javax.security.auth.Policy getPolicy();
- method public abstract void refresh();
- method public static void setPolicy(javax.security.auth.Policy);
- }
-
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
method public boolean equals(java.lang.Object);
@@ -62529,43 +62759,6 @@ package javax.security.auth.callback {
package javax.security.auth.login {
- public class AppConfigurationEntry {
- ctor public AppConfigurationEntry(java.lang.String, javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag, java.util.Map<java.lang.String, ?>);
- method public javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag getControlFlag();
- method public java.lang.String getLoginModuleName();
- method public java.util.Map<java.lang.String, ?> getOptions();
- }
-
- public static class AppConfigurationEntry.LoginModuleControlFlag {
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag OPTIONAL;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag REQUIRED;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag REQUISITE;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag SUFFICIENT;
- }
-
- public abstract class Configuration {
- ctor protected Configuration();
- method public abstract javax.security.auth.login.AppConfigurationEntry[] getAppConfigurationEntry(java.lang.String);
- method public static javax.security.auth.login.Configuration getConfiguration();
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters) throws java.security.NoSuchAlgorithmException;
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters, java.security.Provider) throws java.security.NoSuchAlgorithmException;
- method public javax.security.auth.login.Configuration.Parameters getParameters();
- method public java.security.Provider getProvider();
- method public java.lang.String getType();
- method public void refresh();
- method public static void setConfiguration(javax.security.auth.login.Configuration);
- }
-
- public static abstract interface Configuration.Parameters {
- }
-
- public abstract class ConfigurationSpi {
- ctor public ConfigurationSpi();
- method protected abstract javax.security.auth.login.AppConfigurationEntry[] engineGetAppConfigurationEntry(java.lang.String);
- method protected void engineRefresh();
- }
-
public class LoginException extends java.security.GeneralSecurityException {
ctor public LoginException();
ctor public LoginException(java.lang.String);
diff --git a/api/removed.txt b/api/removed.txt
index 0bf659438340..50a24f6dfd93 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -9,6 +9,8 @@ package android.app {
package android.app.admin {
public class DevicePolicyManager {
+ method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+ method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
}
@@ -35,7 +37,7 @@ package android.database {
package android.media {
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
ctor public AudioFormat();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index cb6bf51ea6e5..61a8953516c8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -169,7 +169,6 @@ package android {
field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
- field public static final java.lang.String READ_WRITE_CONTACT_METADATA = "android.permission.READ_WRITE_CONTACT_METADATA";
field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
field public static final java.lang.String REBOOT = "android.permission.REBOOT";
field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
@@ -293,7 +292,6 @@ package android {
public static final class R.attr {
ctor public R.attr();
- field public static final int abiOverride = 16844054; // 0x1010516
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -396,6 +394,7 @@ package android {
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -433,6 +432,7 @@ package android {
field public static final int calendarViewStyle = 16843613; // 0x101035d
field public static final int canControlMagnification = 16844040; // 0x1010508
field public static final int canPerformGestures = 16844046; // 0x101050e
+ field public static final int canRecord = 16844061; // 0x101051d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -518,6 +518,7 @@ package android {
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
field public static final int controlY2 = 16843775; // 0x10103ff
+ field public static final int countDown = 16844060; // 0x101051c
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
@@ -1457,6 +1458,7 @@ package android {
field public static final int trimPathEnd = 16843785; // 0x1010409
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
+ field public static final int tunerCount = 16844062; // 0x101051e
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1464,6 +1466,7 @@ package android {
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
+ field public static final int use32bitAbi = 16844054; // 0x1010516
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
@@ -1475,6 +1478,7 @@ package android {
field public static final int valueType = 16843488; // 0x10102e0
field public static final int variablePadding = 16843157; // 0x1010195
field public static final int vendor = 16843751; // 0x10103e7
+ field public static final int version = 16844058; // 0x101051a
field public static final int versionCode = 16843291; // 0x101021b
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -2763,6 +2767,7 @@ package android.accessibilityservice {
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
}
@@ -5009,7 +5014,6 @@ package android.app {
method public android.graphics.drawable.Icon getLargeIcon();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
- method public android.app.Notification.Topic getTopic();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -5035,6 +5039,7 @@ package android.app {
field public static final int DEFAULT_VIBRATE = 2; // 0x2
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_COUNTS_DOWN = "android.chronometerCountsDown";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
@@ -5073,7 +5078,6 @@ package android.app {
field public static final int PRIORITY_MAX = 2; // 0x2
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
- field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
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
@@ -5177,16 +5181,17 @@ package android.app {
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.widget.RemoteViews createBigContentView();
+ method public android.widget.RemoteViews createContentView();
+ method public android.widget.RemoteViews createHeadsUpContentView();
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
- method public android.widget.RemoteViews makeBigContentView();
- method public android.widget.RemoteViews makeContentView();
- method public android.widget.RemoteViews makeHeadsUpContentView();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
+ method public android.app.Notification.Builder setChronometerCountsDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
@@ -5225,7 +5230,6 @@ package android.app {
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 setTopic(android.app.Notification.Topic);
method public android.app.Notification.Builder setUsesChronometer(boolean);
method public android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
@@ -5263,6 +5267,16 @@ package android.app {
method public android.app.PendingIntent getReplyPendingIntent();
}
+ public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
+ ctor public Notification.DecoratedCustomViewStyle();
+ ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
+ }
+
+ public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+ ctor public Notification.DecoratedMediaCustomViewStyle();
+ ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+ }
+
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
@@ -5293,16 +5307,6 @@ package android.app {
field protected android.app.Notification.Builder mBuilder;
}
- public static class Notification.Topic implements android.os.Parcelable {
- ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
- method public android.app.Notification.Topic clone();
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.CharSequence getLabel();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
- }
-
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
@@ -5357,6 +5361,7 @@ package android.app {
public class NotificationManager {
method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+ method public boolean areNotificationsEnabled();
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5364,6 +5369,7 @@ package android.app {
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
+ method public int getImportance();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -5839,6 +5845,7 @@ package android.app {
public class WallpaperManager {
method public void clear() throws java.io.IOException;
method public void clearWallpaper();
+ method public void clearWallpaper(int, int);
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -5849,6 +5856,7 @@ package android.app {
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
+ method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
method public boolean isWallpaperSettingAllowed();
@@ -5962,9 +5970,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 deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
- method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
@@ -6021,12 +6027,14 @@ package android.app.admin {
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
+ method public int getUserProvisioningState();
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
method public java.lang.String getWifiMacAddress();
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
+ method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
@@ -6072,7 +6080,7 @@ package android.app.admin {
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
method public void setOrganizationName(android.content.ComponentName, java.lang.String);
- method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
+ method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -6107,6 +6115,7 @@ package android.app.admin {
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_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_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
@@ -6176,6 +6185,11 @@ package android.app.admin {
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
+ field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
+ field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
+ field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
+ field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
+ field public static final int STATE_USER_UNMANAGED = 0; // 0x0
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
@@ -8293,6 +8307,7 @@ package android.content {
method public final int getColor(int);
method public final android.content.res.ColorStateList getColorStateList(int);
method public abstract android.content.ContentResolver getContentResolver();
+ method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8495,6 +8510,7 @@ package android.content {
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -8769,6 +8785,7 @@ package android.content {
field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
+ field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
@@ -8816,6 +8833,7 @@ package android.content {
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -8835,7 +8853,6 @@ package android.content {
field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
- field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
@@ -9742,6 +9759,7 @@ package android.content.pm {
field public int flags;
field public java.lang.String name;
field public int reqGlEsVersion;
+ field public int version;
}
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -10024,6 +10042,7 @@ package android.content.pm {
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
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 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);
@@ -10135,6 +10154,8 @@ 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_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";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -10274,6 +10295,7 @@ package android.content.pm {
field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
field public static final int FLAG_COSTS_MONEY = 1; // 0x1
field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
+ field public static final int FLAG_REMOVED = 2; // 0x2
field public static final int PROTECTION_DANGEROUS = 1; // 0x1
field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20
@@ -12340,6 +12362,8 @@ package android.graphics {
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -13367,12 +13391,10 @@ package android.graphics.drawable {
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
@@ -13595,8 +13617,8 @@ package android.hardware {
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void unlock();
- field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
- field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+ field public static final deprecated java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+ field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -20337,11 +20359,10 @@ package android.location {
method public double getDriftInNsPerSec();
method public double getDriftUncertaintyInNsPerSec();
method public long getFullBiasInNs();
+ method public int getHardwareClockDiscontinuityCount();
method public short getLeapSecond();
method public long getTimeInNs();
- method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
- method public byte getType();
method public boolean hasBiasInNs();
method public boolean hasBiasUncertaintyInNs();
method public boolean hasDriftInNsPerSec();
@@ -20363,21 +20384,14 @@ package android.location {
method public void setDriftInNsPerSec(double);
method public void setDriftUncertaintyInNsPerSec(double);
method public void setFullBiasInNs(long);
+ method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
- method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
- method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
- field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
- field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
- public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
- }
-
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
@@ -20393,23 +20407,22 @@ package android.location {
method public double getCn0InDbHz();
method public double getCodePhaseInChips();
method public double getCodePhaseUncertaintyInChips();
+ method public byte getConstellationType();
method public double getDopplerShiftInHz();
method public double getDopplerShiftUncertaintyInHz();
method public double getElevationInDeg();
method public double getElevationUncertaintyInDeg();
method public byte getLossOfLock();
method public byte getMultipathIndicator();
- method public byte getPrn();
method public double getPseudorangeInMeters();
- method public double getPseudorangeRateCarrierInMetersPerSec();
- method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedGpsTowInNs();
- method public long getReceivedGpsTowUncertaintyInNs();
+ method public long getReceivedSvTimeInNs();
+ method public long getReceivedSvTimeUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
+ method public short getSvid();
method public short getTimeFromLastBitInMs();
method public double getTimeOffsetInNs();
method public boolean hasAzimuthInDeg();
@@ -20463,23 +20476,22 @@ package android.location {
method public void setCn0InDbHz(double);
method public void setCodePhaseInChips(double);
method public void setCodePhaseUncertaintyInChips(double);
+ method public void setConstellationType(byte);
method public void setDopplerShiftInHz(double);
method public void setDopplerShiftUncertaintyInHz(double);
method public void setElevationInDeg(double);
method public void setElevationUncertaintyInDeg(double);
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
- method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateCarrierInMetersPerSec(double);
- method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedGpsTowInNs(long);
- method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setReceivedSvTimeInNs(long);
+ method public void setReceivedSvTimeUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
+ method public void setSvid(short);
method public void setTimeFromLastBitInMs(short);
method public void setTimeOffsetInNs(double);
method public void setUsedInFix(boolean);
@@ -20534,25 +20546,30 @@ package android.location {
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
- method public byte getPrn();
method public short getStatus();
method public short getSubmessageId();
- method public byte getType();
+ method public short getSvid();
+ method public short getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
method public void setMessageId(short);
- method public void setPrn(byte);
method public void setStatus(short);
method public void setSubmessageId(short);
- method public void setType(byte);
+ method public void setSvid(short);
+ method public void setType(short);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
- field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
- field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
- field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
- field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
+ field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
+ field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
+ field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
+ field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
+ field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
+ field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
@@ -20587,21 +20604,24 @@ package android.location {
public final class GnssStatus {
method public float getAzimuth(int);
- method public int getConstellationType(int);
+ method public byte getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
- method public int getPrn(int);
method public float getSnr(int);
+ method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final int CONSTELLATION_GALILEO = 6; // 0x6
- field public static final int CONSTELLATION_GLONASS = 3; // 0x3
- field public static final int CONSTELLATION_GPS = 1; // 0x1
- field public static final int CONSTELLATION_QZSS = 4; // 0x4
- field public static final int CONSTELLATION_SBAS = 2; // 0x2
- field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final byte CONSTELLATION_GPS = 1; // 0x1
+ field public static final byte CONSTELLATION_QZSS = 4; // 0x4
+ field public static final byte CONSTELLATION_SBAS = 2; // 0x2
+ field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
}
public abstract class GnssStatusCallback {
@@ -21154,6 +21174,7 @@ package android.media {
field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+ field public static final int TYPE_BUS = 21; // 0x15
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_FM = 14; // 0xe
field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -21183,12 +21204,14 @@ package android.media {
field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
}
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
+ method public int describeContents();
method public int getChannelCount();
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -21230,6 +21253,7 @@ package android.media {
field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+ field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DTS = 7; // 0x7
@@ -21240,6 +21264,7 @@ package android.media {
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
+ field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
}
public static class AudioFormat.Builder {
@@ -21505,6 +21530,7 @@ package android.media {
public abstract interface AudioRouting {
method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
+ method public abstract android.media.AudioDeviceInfo getRoutedDevice();
method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -21685,6 +21711,8 @@ package android.media {
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+ ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public java.lang.String getAttribute(java.lang.String);
method public double getAttributeDouble(java.lang.String, double);
@@ -21706,6 +21734,10 @@ package android.media {
field public static final java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_DATETIME = "DateTime";
field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+ field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
field public static final java.lang.String TAG_FLASH = "Flash";
field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
@@ -21721,9 +21753,12 @@ package android.media {
field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
field public static final java.lang.String TAG_MAKE = "Make";
+ field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
field public static final java.lang.String TAG_MODEL = "Model";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+ field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
@@ -22464,6 +22499,7 @@ package android.media {
field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+ field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
field public static final java.lang.String KEY_PRIORITY = "priority";
field public static final java.lang.String KEY_PROFILE = "profile";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -22672,6 +22708,7 @@ package android.media {
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;
+ method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
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;
@@ -24111,6 +24148,10 @@ package android.media.session {
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -24144,7 +24185,6 @@ package android.media.session {
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -24159,6 +24199,10 @@ package android.media.session {
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onPrepare();
+ 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 onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -24215,6 +24259,10 @@ package android.media.session {
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
@@ -24223,7 +24271,6 @@ package android.media.session {
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
- field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -24275,19 +24322,26 @@ package android.media.session {
package android.media.soundtrigger {
public final class SoundTriggerDetector {
- method public boolean startRecognition();
+ method public boolean startRecognition(int);
method public boolean stopRecognition();
+ field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
+ field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
}
- public abstract class SoundTriggerDetector.Callback {
+ public static abstract class SoundTriggerDetector.Callback {
ctor public SoundTriggerDetector.Callback();
method public abstract void onAvailabilityChanged(int);
- method public abstract void onDetected();
+ method public abstract void onDetected(android.media.soundtrigger.SoundTriggerDetector.EventPayload);
method public abstract void onError();
method public abstract void onRecognitionPaused();
method public abstract void onRecognitionResumed();
}
+ public static class SoundTriggerDetector.EventPayload {
+ method public android.media.AudioFormat getCaptureAudioFormat();
+ method public byte[] getTriggerAudio();
+ }
+
public final class SoundTriggerManager {
method public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, android.media.soundtrigger.SoundTriggerDetector.Callback, android.os.Handler);
method public void deleteModel(java.util.UUID);
@@ -24341,7 +24395,10 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+ method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+ method public static final boolean isProgramUri(android.net.Uri);
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
@@ -24435,7 +24492,8 @@ package android.media.tv {
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_NUMBER = "episode_number";
+ 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";
@@ -24445,7 +24503,9 @@ package android.media.tv {
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_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ 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_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -24488,8 +24548,9 @@ package android.media.tv {
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_NUMBER = "episode_number";
+ 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";
@@ -24502,7 +24563,8 @@ package android.media.tv {
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_NUMBER = "season_number";
+ 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";
@@ -24583,6 +24645,7 @@ package android.media.tv {
method public boolean isPassthroughInput();
method public java.lang.CharSequence loadCustomLabel(android.content.Context);
method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
+ method public android.graphics.drawable.Drawable loadIcon(android.content.Context, int);
method public java.lang.CharSequence loadLabel(android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.tv.TvInputInfo> CREATOR;
@@ -24605,6 +24668,7 @@ package android.media.tv {
method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
+ method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
method public android.media.tv.TvInputInfo.Builder setLabel(int);
method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24642,13 +24706,13 @@ package android.media.tv {
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_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 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
field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
- field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
- field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
- field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+ field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+ field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -24714,7 +24778,7 @@ package android.media.tv {
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
method public void onInputUpdated(java.lang.String);
- method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
+ method public void onTvInputInfoUpdated(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -24726,7 +24790,7 @@ package android.media.tv {
method public java.lang.String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
method public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
method public java.lang.String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
- method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
+ method public static final void updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -24741,17 +24805,16 @@ package android.media.tv {
public static abstract class TvInputService.RecordingSession {
ctor public TvInputService.RecordingSession(android.content.Context);
- method public void notifyConnected();
method public void notifyError(int);
- method public void notifyRecordingStarted();
method public void notifyRecordingStopped(android.net.Uri);
method public void notifySessionEvent(java.lang.String, android.os.Bundle);
+ method public void notifyTuned();
method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
- method public abstract void onConnect(android.net.Uri);
- method public void onConnect(android.net.Uri, android.os.Bundle);
- method public abstract void onDisconnect();
- method public abstract void onStartRecording();
+ method public abstract void onRelease();
+ method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
+ method public abstract void onTune(android.net.Uri);
+ method public void onTune(android.net.Uri, android.os.Bundle);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -24798,22 +24861,22 @@ package android.media.tv {
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
- method public void connect(java.lang.String, android.net.Uri);
- method public void connect(java.lang.String, android.net.Uri, android.os.Bundle);
- method public void disconnect();
+ method public void release();
method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
- method public void startRecording();
+ method public void startRecording(android.net.Uri);
method public void stopRecording();
+ method public void tune(java.lang.String, android.net.Uri);
+ method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
}
public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
- method public void onConnected();
- method public void onDisconnected();
+ method public void onConnectionFailed(java.lang.String);
+ method public void onDisconnected(java.lang.String);
method public void onError(int);
method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
- method public void onRecordingStarted();
method public void onRecordingStopped(android.net.Uri);
+ method public void onTuned();
}
public class TvStreamConfig implements android.os.Parcelable {
@@ -24851,6 +24914,7 @@ package android.media.tv {
method public final java.lang.String getId();
method public final java.lang.String getLanguage();
method public final int getType();
+ method public final byte getVideoActiveFormatDescription();
method public final float getVideoFrameRate();
method public final int getVideoHeight();
method public final float getVideoPixelAspectRatio();
@@ -24870,6 +24934,7 @@ package android.media.tv {
method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+ method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float);
@@ -25279,6 +25344,17 @@ package android.net {
method public void onTetheringStarted();
}
+ public class ConnectivityMetricsEvent implements android.os.Parcelable {
+ ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+ field public final int componentTag;
+ field public final android.os.Parcelable data;
+ field public final int eventTag;
+ field public final long timestamp;
+ }
+
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -26384,6 +26460,7 @@ package android.net.wifi {
field public int numberBurst;
field public int preamble;
field public int requestType;
+ field public boolean secure;
}
public static class RttManager.RttResult {
@@ -26415,6 +26492,7 @@ package android.net.wifi {
field public deprecated long rtt_sd_ns;
field public deprecated long rtt_spread_ns;
field public int rxRate;
+ field public boolean secure;
field public int status;
field public int successMeasurementFrameNumber;
field public long ts;
@@ -26679,6 +26757,7 @@ package android.net.wifi {
method public boolean reconnect();
method public boolean removeNetwork(int);
method public boolean saveConfiguration();
+ method public boolean setMetered(int, boolean);
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -26791,6 +26870,7 @@ package android.net.wifi {
method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
+ field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
field public static final int REASON_NOT_AUTHORIZED = -4; // 0xfffffffc
@@ -26798,7 +26878,6 @@ package android.net.wifi {
field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
field public static final deprecated int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
- field public static final int REPORT_EVENT_CONTEXT_HUB = 8; // 0x8
field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
@@ -29109,6 +29188,7 @@ package android.opengl {
method public static void glProgramBinary(int, int, java.nio.Buffer, int);
method public static void glProgramParameteri(int, int, int);
method public static void glReadBuffer(int);
+ method public static void glReadPixels(int, int, int, int, int, int, int);
method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
method public static void glResumeTransformFeedback();
method public static void glSamplerParameterf(int, int, float);
@@ -30694,6 +30774,10 @@ package android.os {
ctor public DeadObjectException(java.lang.String);
}
+ public class DeadSystemException extends android.os.DeadObjectException {
+ ctor public DeadSystemException();
+ }
+
public final class Debug {
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
@@ -30851,7 +30935,6 @@ package android.os {
field public static java.lang.String DIRECTORY_DCIM;
field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
- field public static java.lang.String DIRECTORY_HOME;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -31330,7 +31413,6 @@ package android.os {
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
field public static final int USER_ACTIVITY_EVENT_TOUCH = 2; // 0x2
@@ -31355,6 +31437,7 @@ package android.os {
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
+ method public static boolean isApplicationUid(int);
method public static final void killProcess(int);
method public static final int myPid();
method public static final int myTid();
@@ -31384,9 +31467,14 @@ package android.os {
}
public class RecoverySystem {
+ method public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
+ method public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
+ method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
+ method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException;
+ method public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
method public static void verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File) throws java.security.GeneralSecurityException, java.io.IOException;
}
@@ -31581,6 +31669,7 @@ package android.os {
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
method public int getIdentifier();
+ method public static android.os.UserHandle getUserHandleForUid(int);
method public deprecated boolean isOwner();
method public boolean isSystem();
method public static int myUserId();
@@ -31704,11 +31793,27 @@ package android.os.storage {
public class StorageManager {
method public java.lang.String getMountedObbPath(java.lang.String);
+ method public android.os.storage.StorageVolume getPrimaryVolume();
+ method public android.os.storage.StorageVolume[] getVolumeList();
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
}
+ public class StorageVolume implements android.os.Parcelable {
+ method public android.content.Intent createAccessIntent(java.lang.String);
+ method public int describeContents();
+ method public java.lang.String getDescription(android.content.Context);
+ method public java.lang.String getState();
+ method public java.lang.String getUuid();
+ method public boolean isEmulated();
+ method public boolean isPrimary();
+ method public boolean isRemovable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.storage.StorageVolume> CREATOR;
+ field public static final java.lang.String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
+ }
+
}
package android.preference {
@@ -31823,6 +31928,7 @@ package android.preference {
method protected int getPersistedInt(int);
method protected long getPersistedLong(long);
method protected java.lang.String getPersistedString(java.lang.String);
+ method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
method public android.preference.PreferenceManager getPreferenceManager();
method public android.content.SharedPreferences getSharedPreferences();
method public boolean getShouldDisableView();
@@ -31857,6 +31963,7 @@ package android.preference {
method protected boolean persistInt(int);
method protected boolean persistLong(long);
method protected boolean persistString(java.lang.String);
+ method public boolean persistStringSet(java.util.Set<java.lang.String>);
method public void restoreHierarchyState(android.os.Bundle);
method public void saveHierarchyState(android.os.Bundle);
method public void setDefaultValue(java.lang.Object);
@@ -33839,6 +33946,8 @@ package android.provider {
}
protected static abstract interface ContactsContract.PhoneLookupColumns {
+ field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String DATA_ID = "data_id";
field public static final java.lang.String LABEL = "label";
field public static final java.lang.String NORMALIZED_NUMBER = "normalized_number";
field public static final java.lang.String NUMBER = "number";
@@ -34102,6 +34211,7 @@ package android.provider {
method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+ method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
@@ -34122,7 +34232,7 @@ package android.provider {
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
- method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+ method public void removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -34624,10 +34734,10 @@ package android.provider {
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
- field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34684,6 +34794,7 @@ package android.provider {
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
field public static final java.lang.String MODE_RINGER = "mode_ringer";
field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
+ field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth";
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
@@ -34696,6 +34807,7 @@ package android.provider {
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
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_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";
@@ -36529,6 +36641,7 @@ package android.security.keystore {
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+ method public byte[] getAttestationChallenge();
method public java.lang.String[] getBlockModes();
method public java.util.Date getCertificateNotAfter();
method public java.util.Date getCertificateNotBefore();
@@ -36545,14 +36658,17 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyGenParameterSpec.Builder {
ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
method public android.security.keystore.KeyGenParameterSpec build();
method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
@@ -36560,6 +36676,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -36568,6 +36685,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -36585,8 +36703,10 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isInsideSecureHardware();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -36647,8 +36767,10 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyProtection.Builder {
@@ -36657,6 +36779,7 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -36664,6 +36787,7 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -36935,9 +37059,8 @@ package android.service.notification {
field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
- field public static final int REASON_PACKAGE_SUSPENDED = 15; // 0xf
- field public static final int REASON_PROFILE_TURNED_OFF = 16; // 0x10
- field public static final int REASON_TOPIC_BANNED = 14; // 0xe
+ 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_USER_STOPPED = 6; // 0x6
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -36999,10 +37122,11 @@ package android.service.notification {
method public int getSuppressedVisualEffects();
method public boolean isAmbient();
method public boolean matchesInterruptionFilter();
- field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
- field public static final int IMPORTANCE_HIGH = 3; // 0x3
- field public static final int IMPORTANCE_LOW = 1; // 0x1
- field public static final int IMPORTANCE_MAX = 4; // 0x4
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
field public static final int IMPORTANCE_NONE = 0; // 0x0
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}
@@ -37041,6 +37165,7 @@ package android.service.persistentdata {
public abstract interface IPersistentDataBlockService implements android.os.IInterface {
method public abstract int getDataBlockSize() throws android.os.RemoteException;
+ method public abstract int getFlashLockState() throws android.os.RemoteException;
method public abstract long getMaximumDataBlockSize() throws android.os.RemoteException;
method public abstract boolean getOemUnlockEnabled() throws android.os.RemoteException;
method public abstract byte[] read() throws android.os.RemoteException;
@@ -37052,12 +37177,19 @@ package android.service.persistentdata {
public class PersistentDataBlockManager {
ctor public PersistentDataBlockManager(android.service.persistentdata.IPersistentDataBlockService);
method public int getDataBlockSize();
+ method public int getFlashLockState();
method public long getMaximumDataBlockSize();
method public boolean getOemUnlockEnabled();
method public byte[] read();
method public void setOemUnlockEnabled(boolean);
method public void wipe();
method public int write(byte[]);
+ field public static final int FLASH_LOCK_LOCKED = 1; // 0x1
+ field public static final int FLASH_LOCK_UNKNOWN = -1; // 0xffffffff
+ field public static final int FLASH_LOCK_UNLOCKED = 0; // 0x0
+ }
+
+ public static abstract class PersistentDataBlockManager.FlashLockState implements java.lang.annotation.Annotation {
}
}
@@ -37099,6 +37231,7 @@ package android.service.quicksettings {
method public final void startActivityAndCollapse(android.content.Intent);
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
@@ -38643,6 +38776,7 @@ package android.telecom {
method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public final java.util.Collection<android.telecom.Conference> getAllConferences();
method public final java.util.Collection<android.telecom.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
@@ -38985,6 +39119,7 @@ package android.telecom {
method public void cancelMissedCallsNotification();
method public deprecated void clearAccounts();
method public void clearPhoneAccounts();
+ method public android.content.Intent createManageBlockedNumbersIntent();
method public java.util.List<android.telecom.ParcelableCallAnalytics> dumpAnalytics();
method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
method public boolean endCall();
@@ -39095,10 +39230,12 @@ package android.telecom {
package android.telephony {
public class CarrierConfigManager {
+ method public android.os.PersistableBundle getConfig(int);
method public android.os.PersistableBundle getConfig();
- method public android.os.PersistableBundle getConfigForSubId(int);
+ method public deprecated android.os.PersistableBundle getConfigForSubId(int);
method public static android.os.PersistableBundle getDefaultConfig();
- method public void notifyConfigChangedForSubId(int);
+ method public void notifyConfigChanged(int);
+ method public deprecated void notifyConfigChangedForSubId(int);
method public void updateConfigForPhoneId(int, java.lang.String);
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
@@ -39758,12 +39895,18 @@ package android.telephony {
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
method public boolean hasCarrierPrivileges();
+ method public boolean hasCarrierPrivileges(int);
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
+ method public boolean iccCloseLogicalChannel(int, int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+ method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+ method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+ method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
method public boolean isDataConnectivityPossible();
method public boolean isHearingAidCompatibilitySupported();
method public boolean isIdle();
@@ -39781,12 +39924,15 @@ package android.telephony {
method public void listen(android.telephony.PhoneStateListener, int);
method public boolean needsOtaServiceProvisioning();
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+ method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
method public void setDataEnabled(boolean);
method public void setDataEnabled(int, boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
+ method public boolean setOperatorBrandOverride(int, java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
+ method public boolean setPreferredNetworkTypeToGlobal(int);
method public boolean setRadio(boolean);
method public boolean setRadioPower(boolean);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
@@ -40339,6 +40485,7 @@ package android.test.mock {
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -40530,6 +40677,7 @@ package android.test.mock {
method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
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 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);
@@ -43414,6 +43562,21 @@ package android.view {
method public static android.view.FocusFinder getInstance();
}
+ public final class FrameMetrics {
+ ctor public FrameMetrics(android.view.FrameMetrics);
+ method public long getMetric(int);
+ field public static final int ANIMATION_DURATION = 2; // 0x2
+ field public static final int COMMAND_ISSUE_DURATION = 6; // 0x6
+ field public static final int DRAW_DURATION = 4; // 0x4
+ field public static final int FIRST_DRAW_FRAME = 9; // 0x9
+ field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 3; // 0x3
+ field public static final int SWAP_BUFFERS_DURATION = 7; // 0x7
+ field public static final int SYNC_DURATION = 5; // 0x5
+ field public static final int TOTAL_DURATION = 8; // 0x8
+ field public static final int UNKNOWN_DELAY_DURATION = 0; // 0x0
+ }
+
public abstract class FrameStats {
ctor public FrameStats();
method public final long getEndTimeNano();
@@ -45917,6 +46080,7 @@ package android.view {
ctor public Window(android.content.Context);
method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void addFlags(int);
+ method public final void addFrameMetricsListener(android.view.Window.FrameMetricsListener, android.os.Handler);
method public void clearFlags(int);
method public abstract void closeAllPanels();
method public abstract void closePanel(int);
@@ -45968,6 +46132,7 @@ package android.view {
method public abstract boolean performContextMenuIdentifierAction(int, int);
method public abstract boolean performPanelIdentifierAction(int, int, int);
method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
+ method public final void removeFrameMetricsListener(android.view.Window.FrameMetricsListener);
method public boolean requestFeature(int);
method public abstract void restoreHierarchyState(android.os.Bundle);
method public abstract android.os.Bundle saveHierarchyState();
@@ -46094,6 +46259,10 @@ package android.view {
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static abstract interface Window.FrameMetricsListener {
+ method public abstract void onMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+ }
+
public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
}
@@ -46704,6 +46873,7 @@ package android.view.accessibility {
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
}
@@ -47043,6 +47213,7 @@ package android.view.inputmethod {
method public int getCursorCapsMode(int);
method public android.text.Editable getEditable();
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -47206,6 +47377,7 @@ package android.view.inputmethod {
method public abstract boolean finishComposingText();
method public abstract int getCursorCapsMode(int);
method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public abstract android.os.Handler getHandler();
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -47237,6 +47409,7 @@ package android.view.inputmethod {
method public boolean finishComposingText();
method public int getCursorCapsMode(int);
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -48487,6 +48660,7 @@ package android.webkit {
method public abstract void onConfigurationChanged(android.content.res.Configuration);
method public abstract android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
method public abstract void onDetachedFromWindow();
+ method public abstract boolean onDragEvent(android.view.DragEvent);
method public abstract void onDraw(android.graphics.Canvas);
method public abstract void onDrawVerticalScrollBar(android.graphics.Canvas, android.graphics.drawable.Drawable, int, int, int, int);
method public abstract void onFinishTemporaryDetach();
@@ -49076,7 +49250,9 @@ package android.widget {
method public long getBase();
method public java.lang.String getFormat();
method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
+ method public boolean isCountDown();
method public void setBase(long);
+ method public void setCountDown(boolean);
method public void setFormat(java.lang.String);
method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
method public void start();
@@ -50168,6 +50344,7 @@ package android.widget {
method public void setChar(int, java.lang.String, char);
method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
method public void setChronometer(int, long, java.lang.String, boolean);
+ method public void setChronometerCountsDown(int, boolean);
method public void setContentDescription(int, java.lang.CharSequence);
method public void setDisplayedChild(int, int);
method public void setDouble(int, java.lang.String, double);
@@ -54539,7 +54716,6 @@ package java.lang.reflect {
method public static int getLength(java.lang.Object);
method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
- method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -55215,7 +55391,6 @@ package java.net {
public class InetAddress implements java.io.Serializable {
method public byte[] getAddress();
- method public byte[] getAddressInternal();
method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
@@ -55489,7 +55664,7 @@ package java.net {
method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
method protected abstract void create(boolean) throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
+ method protected java.io.FileDescriptor getFileDescriptor();
method protected java.net.InetAddress getInetAddress();
method protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
method protected int getLocalPort();
@@ -56031,10 +56206,6 @@ package java.nio {
package java.nio.channels {
- public class AcceptPendingException extends java.lang.IllegalStateException {
- ctor public AcceptPendingException();
- }
-
public class AlreadyBoundException extends java.lang.IllegalStateException {
ctor public AlreadyBoundException();
}
@@ -56043,68 +56214,10 @@ package java.nio.channels {
ctor public AlreadyConnectedException();
}
- public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
- method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- }
-
- public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
- method public abstract void close() throws java.io.IOException;
- }
-
- public abstract class AsynchronousChannelGroup {
- ctor protected AsynchronousChannelGroup(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public abstract boolean isShutdown();
- method public abstract boolean isTerminated();
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void shutdown();
- method public abstract void shutdownNow() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withCachedThreadPool(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withFixedThreadPool(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withThreadPool(java.util.concurrent.ExecutorService) throws java.io.IOException;
- }
-
public class AsynchronousCloseException extends java.nio.channels.ClosedChannelException {
ctor public AsynchronousCloseException();
}
- public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
- method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
- method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- }
-
- public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
- method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
- method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- }
-
public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
}
@@ -56121,9 +56234,7 @@ package java.nio.channels {
method public static java.nio.channels.ReadableByteChannel newChannel(java.io.InputStream);
method public static java.nio.channels.WritableByteChannel newChannel(java.io.OutputStream);
method public static java.io.InputStream newInputStream(java.nio.channels.ReadableByteChannel);
- method public static java.io.InputStream newInputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
- method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
@@ -56142,16 +56253,11 @@ package java.nio.channels {
ctor public ClosedSelectorException();
}
- public abstract interface CompletionHandler {
- method public abstract void completed(V, A);
- method public abstract void failed(java.lang.Throwable, A);
- }
-
public class ConnectionPendingException extends java.lang.IllegalStateException {
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -56230,40 +56336,14 @@ package java.nio.channels {
ctor public IllegalBlockingModeException();
}
- public class IllegalChannelGroupException extends java.lang.IllegalArgumentException {
- ctor public IllegalChannelGroupException();
- }
-
public class IllegalSelectorException extends java.lang.IllegalArgumentException {
ctor public IllegalSelectorException();
}
- public class InterruptedByTimeoutException extends java.io.IOException {
- ctor public InterruptedByTimeoutException();
- }
-
public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
public abstract interface NetworkChannel implements java.nio.channels.Channel {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -56313,10 +56393,6 @@ package java.nio.channels {
method public final int validOps();
}
- public class ReadPendingException extends java.lang.IllegalStateException {
- ctor public ReadPendingException();
- }
-
public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
}
@@ -56394,10 +56470,6 @@ package java.nio.channels {
method public final int validOps();
}
- public class ShutdownChannelGroupException extends java.lang.IllegalStateException {
- ctor public ShutdownChannelGroupException();
- }
-
public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
@@ -56433,10 +56505,6 @@ package java.nio.channels {
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
}
- public class WritePendingException extends java.lang.IllegalStateException {
- ctor public WritePendingException();
- }
-
}
package java.nio.channels.spi {
@@ -56483,15 +56551,6 @@ package java.nio.channels.spi {
method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
}
- public abstract class AsynchronousChannelProvider {
- ctor protected AsynchronousChannelProvider();
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel openAsynchronousSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.spi.AsynchronousChannelProvider provider();
- }
-
public abstract class SelectorProvider {
ctor protected SelectorProvider();
method public java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
@@ -57306,7 +57365,6 @@ package java.security {
public abstract class Signature extends java.security.SignatureSpi {
ctor protected Signature(java.lang.String);
method public final java.lang.String getAlgorithm();
- method public java.security.SignatureSpi getCurrentSpi();
method public static java.security.Signature getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
method public static java.security.Signature getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.Signature getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
@@ -59846,13 +59904,11 @@ package java.text {
method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
method public java.lang.String getInternationalCurrencySymbol();
method public char getMinusSign();
- method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
method public java.lang.String getNaN();
method public char getPatternSeparator();
method public char getPerMill();
method public char getPercent();
- method public java.lang.String getPercentString();
method public char getZeroDigit();
method public void setCurrency(java.util.Currency);
method public void setCurrencySymbol(java.lang.String);
@@ -61105,8 +61161,11 @@ package java.util {
method public static boolean equals(java.lang.Object, java.lang.Object);
method public static int hash(java.lang.Object...);
method public static int hashCode(java.lang.Object);
+ method public static boolean isNull(java.lang.Object);
+ method public static boolean nonNull(java.lang.Object);
method public static T requireNonNull(T);
method public static T requireNonNull(T, java.lang.String);
+ method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
method public static java.lang.String toString(java.lang.Object);
method public static java.lang.String toString(java.lang.Object, java.lang.String);
}
@@ -62811,6 +62870,217 @@ package java.util.concurrent.locks {
}
+package java.util.function {
+
+ public abstract interface BiConsumer {
+ method public abstract void accept(T, U);
+ method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
+ }
+
+ public abstract interface BiFunction {
+ method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
+ method public abstract R apply(T, U);
+ }
+
+ public abstract interface BiPredicate {
+ method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
+ method public default java.util.function.BiPredicate<T, U> negate();
+ method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
+ method public abstract boolean test(T, U);
+ }
+
+ public abstract interface BinaryOperator implements java.util.function.BiFunction {
+ method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
+ method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
+ }
+
+ public abstract interface BooleanSupplier {
+ method public abstract boolean getAsBoolean();
+ }
+
+ public abstract interface Consumer {
+ method public abstract void accept(T);
+ method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
+ }
+
+ public abstract interface DoubleBinaryOperator {
+ method public abstract double applyAsDouble(double, double);
+ }
+
+ public abstract interface DoubleConsumer {
+ method public abstract void accept(double);
+ method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
+ }
+
+ public abstract interface DoubleFunction {
+ method public abstract R apply(double);
+ }
+
+ public abstract interface DoublePredicate {
+ method public default java.util.function.DoublePredicate and(java.util.function.DoublePredicate);
+ method public default java.util.function.DoublePredicate negate();
+ method public default java.util.function.DoublePredicate or(java.util.function.DoublePredicate);
+ method public abstract boolean test(double);
+ }
+
+ public abstract interface DoubleSupplier {
+ method public abstract double getAsDouble();
+ }
+
+ public abstract interface DoubleToIntFunction {
+ method public abstract int applyAsInt(double);
+ }
+
+ public abstract interface DoubleToLongFunction {
+ method public abstract long applyAsLong(double);
+ }
+
+ public abstract interface DoubleUnaryOperator {
+ method public default java.util.function.DoubleUnaryOperator andThen(java.util.function.DoubleUnaryOperator);
+ method public abstract double applyAsDouble(double);
+ method public default java.util.function.DoubleUnaryOperator compose(java.util.function.DoubleUnaryOperator);
+ method public static java.util.function.DoubleUnaryOperator identity();
+ }
+
+ public abstract interface Function {
+ method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
+ method public abstract R apply(T);
+ method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
+ method public static java.util.function.Function<T, T> identity();
+ }
+
+ public abstract interface IntBinaryOperator {
+ method public abstract int applyAsInt(int, int);
+ }
+
+ public abstract interface IntConsumer {
+ method public abstract void accept(int);
+ method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
+ }
+
+ public abstract interface IntFunction {
+ method public abstract R apply(int);
+ }
+
+ public abstract interface IntPredicate {
+ method public default java.util.function.IntPredicate and(java.util.function.IntPredicate);
+ method public default java.util.function.IntPredicate negate();
+ method public default java.util.function.IntPredicate or(java.util.function.IntPredicate);
+ method public abstract boolean test(int);
+ }
+
+ public abstract interface IntSupplier {
+ method public abstract int getAsInt();
+ }
+
+ public abstract interface IntToDoubleFunction {
+ method public abstract double applyAsDouble(int);
+ }
+
+ public abstract interface IntToLongFunction {
+ method public abstract long applyAsLong(int);
+ }
+
+ public abstract interface IntUnaryOperator {
+ method public default java.util.function.IntUnaryOperator andThen(java.util.function.IntUnaryOperator);
+ method public abstract int applyAsInt(int);
+ method public default java.util.function.IntUnaryOperator compose(java.util.function.IntUnaryOperator);
+ method public static java.util.function.IntUnaryOperator identity();
+ }
+
+ public abstract interface LongBinaryOperator {
+ method public abstract long applyAsLong(long, long);
+ }
+
+ public abstract interface LongConsumer {
+ method public abstract void accept(long);
+ method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
+ }
+
+ public abstract interface LongFunction {
+ method public abstract R apply(long);
+ }
+
+ public abstract interface LongPredicate {
+ method public default java.util.function.LongPredicate and(java.util.function.LongPredicate);
+ method public default java.util.function.LongPredicate negate();
+ method public default java.util.function.LongPredicate or(java.util.function.LongPredicate);
+ method public abstract boolean test(long);
+ }
+
+ public abstract interface LongSupplier {
+ method public abstract long getAsLong();
+ }
+
+ public abstract interface LongToDoubleFunction {
+ method public abstract double applyAsDouble(long);
+ }
+
+ public abstract interface LongToIntFunction {
+ method public abstract int applyAsInt(long);
+ }
+
+ public abstract interface LongUnaryOperator {
+ method public default java.util.function.LongUnaryOperator andThen(java.util.function.LongUnaryOperator);
+ method public abstract long applyAsLong(long);
+ method public default java.util.function.LongUnaryOperator compose(java.util.function.LongUnaryOperator);
+ method public static java.util.function.LongUnaryOperator identity();
+ }
+
+ public abstract interface ObjDoubleConsumer {
+ method public abstract void accept(T, double);
+ }
+
+ public abstract interface ObjIntConsumer {
+ method public abstract void accept(T, int);
+ }
+
+ public abstract interface ObjLongConsumer {
+ method public abstract void accept(T, long);
+ }
+
+ public abstract interface Predicate {
+ method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
+ method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
+ method public default java.util.function.Predicate<T> negate();
+ method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
+ method public abstract boolean test(T);
+ }
+
+ public abstract interface Supplier {
+ method public abstract T get();
+ }
+
+ public abstract interface ToDoubleBiFunction {
+ method public abstract double applyAsDouble(T, U);
+ }
+
+ public abstract interface ToDoubleFunction {
+ method public abstract double applyAsDouble(T);
+ }
+
+ public abstract interface ToIntBiFunction {
+ method public abstract int applyAsInt(T, U);
+ }
+
+ public abstract interface ToIntFunction {
+ method public abstract int applyAsInt(T);
+ }
+
+ public abstract interface ToLongBiFunction {
+ method public abstract long applyAsLong(T, U);
+ }
+
+ public abstract interface ToLongFunction {
+ method public abstract long applyAsLong(T);
+ }
+
+ public abstract interface UnaryOperator implements java.util.function.Function {
+ method public static java.util.function.UnaryOperator<T> identity();
+ }
+
+}
+
package java.util.jar {
public class Attributes implements java.lang.Cloneable java.util.Map {
@@ -65545,14 +65815,6 @@ package javax.security.auth {
method public abstract boolean isDestroyed();
}
- public abstract deprecated class Policy {
- ctor protected Policy();
- method public abstract java.security.PermissionCollection getPermissions(javax.security.auth.Subject, java.security.CodeSource);
- method public static javax.security.auth.Policy getPolicy();
- method public abstract void refresh();
- method public static void setPolicy(javax.security.auth.Policy);
- }
-
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
method public boolean equals(java.lang.Object);
@@ -65617,43 +65879,6 @@ package javax.security.auth.callback {
package javax.security.auth.login {
- public class AppConfigurationEntry {
- ctor public AppConfigurationEntry(java.lang.String, javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag, java.util.Map<java.lang.String, ?>);
- method public javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag getControlFlag();
- method public java.lang.String getLoginModuleName();
- method public java.util.Map<java.lang.String, ?> getOptions();
- }
-
- public static class AppConfigurationEntry.LoginModuleControlFlag {
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag OPTIONAL;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag REQUIRED;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag REQUISITE;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag SUFFICIENT;
- }
-
- public abstract class Configuration {
- ctor protected Configuration();
- method public abstract javax.security.auth.login.AppConfigurationEntry[] getAppConfigurationEntry(java.lang.String);
- method public static javax.security.auth.login.Configuration getConfiguration();
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters) throws java.security.NoSuchAlgorithmException;
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters, java.security.Provider) throws java.security.NoSuchAlgorithmException;
- method public javax.security.auth.login.Configuration.Parameters getParameters();
- method public java.security.Provider getProvider();
- method public java.lang.String getType();
- method public void refresh();
- method public static void setConfiguration(javax.security.auth.login.Configuration);
- }
-
- public static abstract interface Configuration.Parameters {
- }
-
- public abstract class ConfigurationSpi {
- ctor public ConfigurationSpi();
- method protected abstract javax.security.auth.login.AppConfigurationEntry[] engineGetAppConfigurationEntry(java.lang.String);
- method protected void engineRefresh();
- }
-
public class LoginException extends java.security.GeneralSecurityException {
ctor public LoginException();
ctor public LoginException(java.lang.String);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 27de91312fae..7347aa3f2110 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,6 +6,15 @@ package android.app {
}
+package android.app.admin {
+
+ public class DevicePolicyManager {
+ method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+ method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
+ }
+
+}
+
package android.content.pm {
public class PackageInfo implements android.os.Parcelable {
@@ -26,7 +35,7 @@ package android.database {
package android.media {
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
ctor public AudioFormat();
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 1ba48e44e52d..d2d470bbd274 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -101,7 +101,6 @@ package android {
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
- field public static final java.lang.String READ_WRITE_CONTACT_METADATA = "android.permission.READ_WRITE_CONTACT_METADATA";
field public static final java.lang.String REBOOT = "android.permission.REBOOT";
field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
@@ -198,7 +197,6 @@ package android {
public static final class R.attr {
ctor public R.attr();
- field public static final int abiOverride = 16844054; // 0x1010516
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -301,6 +299,7 @@ package android {
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -338,6 +337,7 @@ package android {
field public static final int calendarViewStyle = 16843613; // 0x101035d
field public static final int canControlMagnification = 16844040; // 0x1010508
field public static final int canPerformGestures = 16844046; // 0x101050e
+ field public static final int canRecord = 16844061; // 0x101051d
field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -423,6 +423,7 @@ package android {
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
field public static final int controlY2 = 16843775; // 0x10103ff
+ field public static final int countDown = 16844060; // 0x101051c
field public static final int country = 16843962; // 0x10104ba
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
@@ -1358,6 +1359,7 @@ package android {
field public static final int trimPathEnd = 16843785; // 0x1010409
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
+ field public static final int tunerCount = 16844062; // 0x101051e
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1365,6 +1367,7 @@ package android {
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
+ field public static final int use32bitAbi = 16844054; // 0x1010516
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
@@ -1376,6 +1379,7 @@ package android {
field public static final int valueType = 16843488; // 0x10102e0
field public static final int variablePadding = 16843157; // 0x1010195
field public static final int vendor = 16843751; // 0x10103e7
+ field public static final int version = 16844058; // 0x101051a
field public static final int versionCode = 16843291; // 0x101021b
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
@@ -2661,6 +2665,7 @@ package android.accessibilityservice {
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
}
@@ -4877,7 +4882,6 @@ package android.app {
method public android.graphics.drawable.Icon getLargeIcon();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
- method public android.app.Notification.Topic getTopic();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4903,6 +4907,7 @@ package android.app {
field public static final int DEFAULT_VIBRATE = 2; // 0x2
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_COUNTS_DOWN = "android.chronometerCountsDown";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
@@ -4941,7 +4946,6 @@ package android.app {
field public static final int PRIORITY_MAX = 2; // 0x2
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
- field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
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
@@ -5045,16 +5049,17 @@ package android.app {
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.widget.RemoteViews createBigContentView();
+ method public android.widget.RemoteViews createContentView();
+ method public android.widget.RemoteViews createHeadsUpContentView();
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
- method public android.widget.RemoteViews makeBigContentView();
- method public android.widget.RemoteViews makeContentView();
- method public android.widget.RemoteViews makeHeadsUpContentView();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
+ method public android.app.Notification.Builder setChronometerCountsDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
@@ -5093,7 +5098,6 @@ package android.app {
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 setTopic(android.app.Notification.Topic);
method public android.app.Notification.Builder setUsesChronometer(boolean);
method public android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
@@ -5131,6 +5135,16 @@ package android.app {
method public android.app.PendingIntent getReplyPendingIntent();
}
+ public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
+ ctor public Notification.DecoratedCustomViewStyle();
+ ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
+ }
+
+ public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+ ctor public Notification.DecoratedMediaCustomViewStyle();
+ ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+ }
+
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
@@ -5161,16 +5175,6 @@ package android.app {
field protected android.app.Notification.Builder mBuilder;
}
- public static class Notification.Topic implements android.os.Parcelable {
- ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
- method public android.app.Notification.Topic clone();
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.CharSequence getLabel();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
- }
-
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
@@ -5225,6 +5229,7 @@ package android.app {
public class NotificationManager {
method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+ method public boolean areNotificationsEnabled();
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5232,6 +5237,7 @@ package android.app {
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
+ method public int getImportance();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -5718,6 +5724,7 @@ package android.app {
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
+ method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
method public boolean isWallpaperSettingAllowed();
@@ -5828,9 +5835,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 deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
- method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void enableSystemApp(android.content.ComponentName, java.lang.String);
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
@@ -5885,6 +5890,7 @@ package android.app.admin {
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
+ method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String, boolean);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
@@ -5928,7 +5934,7 @@ package android.app.admin {
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
method public void setOrganizationName(android.content.ComponentName, java.lang.String);
- method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
+ method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -8005,6 +8011,7 @@ package android.content {
method public final int getColor(int);
method public final android.content.res.ColorStateList getColorStateList(int);
method public abstract android.content.ContentResolver getContentResolver();
+ method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8198,6 +8205,7 @@ package android.content {
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -8470,6 +8478,7 @@ package android.content {
field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
+ field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
@@ -8515,6 +8524,7 @@ package android.content {
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED = "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
@@ -8534,7 +8544,6 @@ package android.content {
field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
- field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
@@ -9404,6 +9413,7 @@ package android.content.pm {
field public int flags;
field public java.lang.String name;
field public int reqGlEsVersion;
+ field public int version;
}
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -9683,6 +9693,7 @@ package android.content.pm {
method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
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 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);
@@ -9786,6 +9797,8 @@ 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_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";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -11947,6 +11960,8 @@ package android.graphics {
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
method public float getAlpha();
+ method public float getRadius();
+ method public boolean getRect(android.graphics.Rect);
method public boolean isEmpty();
method public void offset(int, int);
method public void set(android.graphics.Outline);
@@ -12974,12 +12989,10 @@ package android.graphics.drawable {
ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
method public void draw(android.graphics.Canvas);
- method public android.graphics.NinePatch getNinePatch();
method public int getOpacity();
method public android.graphics.Paint getPaint();
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setNinePatch(android.graphics.NinePatch);
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
@@ -13202,8 +13215,8 @@ package android.hardware {
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
method public final void unlock();
- field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
- field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+ field public static final deprecated java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+ field public static final deprecated java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
@@ -19165,11 +19178,10 @@ package android.location {
method public double getDriftInNsPerSec();
method public double getDriftUncertaintyInNsPerSec();
method public long getFullBiasInNs();
+ method public int getHardwareClockDiscontinuityCount();
method public short getLeapSecond();
method public long getTimeInNs();
- method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
- method public byte getType();
method public boolean hasBiasInNs();
method public boolean hasBiasUncertaintyInNs();
method public boolean hasDriftInNsPerSec();
@@ -19191,21 +19203,14 @@ package android.location {
method public void setDriftInNsPerSec(double);
method public void setDriftUncertaintyInNsPerSec(double);
method public void setFullBiasInNs(long);
+ method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
- method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
- method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
- field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2
- field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1
- field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
- public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation {
- }
-
public final class GnssMeasurement implements android.os.Parcelable {
method public int describeContents();
method public double getAccumulatedDeltaRangeInMeters();
@@ -19221,23 +19226,22 @@ package android.location {
method public double getCn0InDbHz();
method public double getCodePhaseInChips();
method public double getCodePhaseUncertaintyInChips();
+ method public byte getConstellationType();
method public double getDopplerShiftInHz();
method public double getDopplerShiftUncertaintyInHz();
method public double getElevationInDeg();
method public double getElevationUncertaintyInDeg();
method public byte getLossOfLock();
method public byte getMultipathIndicator();
- method public byte getPrn();
method public double getPseudorangeInMeters();
- method public double getPseudorangeRateCarrierInMetersPerSec();
- method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedGpsTowInNs();
- method public long getReceivedGpsTowUncertaintyInNs();
+ method public long getReceivedSvTimeInNs();
+ method public long getReceivedSvTimeUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
+ method public short getSvid();
method public short getTimeFromLastBitInMs();
method public double getTimeOffsetInNs();
method public boolean hasAzimuthInDeg();
@@ -19291,23 +19295,22 @@ package android.location {
method public void setCn0InDbHz(double);
method public void setCodePhaseInChips(double);
method public void setCodePhaseUncertaintyInChips(double);
+ method public void setConstellationType(byte);
method public void setDopplerShiftInHz(double);
method public void setDopplerShiftUncertaintyInHz(double);
method public void setElevationInDeg(double);
method public void setElevationUncertaintyInDeg(double);
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
- method public void setPrn(byte);
method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateCarrierInMetersPerSec(double);
- method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedGpsTowInNs(long);
- method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setReceivedSvTimeInNs(long);
+ method public void setReceivedSvTimeUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
+ method public void setSvid(short);
method public void setTimeFromLastBitInMs(short);
method public void setTimeOffsetInNs(double);
method public void setUsedInFix(boolean);
@@ -19362,25 +19365,30 @@ package android.location {
method public int describeContents();
method public byte[] getData();
method public short getMessageId();
- method public byte getPrn();
method public short getStatus();
method public short getSubmessageId();
- method public byte getType();
+ method public short getSvid();
+ method public short getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
method public void setMessageId(short);
- method public void setPrn(byte);
method public void setStatus(short);
method public void setSubmessageId(short);
- method public void setType(byte);
+ method public void setSvid(short);
+ method public void setType(short);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
- field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
- field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
- field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
- field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
+ field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
+ field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
+ field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
+ field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
+ field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
+ field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
@@ -19415,21 +19423,24 @@ package android.location {
public final class GnssStatus {
method public float getAzimuth(int);
- method public int getConstellationType(int);
+ method public byte getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
- method public int getPrn(int);
method public float getSnr(int);
+ method public int getSvid(int);
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final int CONSTELLATION_GALILEO = 6; // 0x6
- field public static final int CONSTELLATION_GLONASS = 3; // 0x3
- field public static final int CONSTELLATION_GPS = 1; // 0x1
- field public static final int CONSTELLATION_QZSS = 4; // 0x4
- field public static final int CONSTELLATION_SBAS = 2; // 0x2
- field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final byte CONSTELLATION_GPS = 1; // 0x1
+ field public static final byte CONSTELLATION_QZSS = 4; // 0x4
+ field public static final byte CONSTELLATION_SBAS = 2; // 0x2
+ field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
}
public abstract class GnssStatusCallback {
@@ -19535,8 +19546,8 @@ package android.location {
method public void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
+ method public int getGnssYearOfHardware();
method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
- method public int getGpsYearOfHardware();
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);
@@ -19688,6 +19699,7 @@ package android.media {
field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1
field public static final int TYPE_BUILTIN_MIC = 15; // 0xf
field public static final int TYPE_BUILTIN_SPEAKER = 2; // 0x2
+ field public static final int TYPE_BUS = 21; // 0x15
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_FM = 14; // 0xe
field public static final int TYPE_FM_TUNER = 16; // 0x10
@@ -19705,12 +19717,14 @@ package android.media {
field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
}
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
+ method public int describeContents();
method public int getChannelCount();
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -19752,6 +19766,7 @@ package android.media {
field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000
field public static final int CHANNEL_OUT_STEREO = 12; // 0xc
field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
+ field public static final android.os.Parcelable.Creator<android.media.AudioFormat> CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DTS = 7; // 0x7
@@ -19762,6 +19777,7 @@ package android.media {
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
+ field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
}
public static class AudioFormat.Builder {
@@ -20015,6 +20031,7 @@ package android.media {
public abstract interface AudioRouting {
method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
+ method public abstract android.media.AudioDeviceInfo getRoutedDevice();
method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -20195,6 +20212,8 @@ package android.media {
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
+ ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public java.lang.String getAttribute(java.lang.String);
method public double getAttributeDouble(java.lang.String, double);
@@ -20216,6 +20235,10 @@ package android.media {
field public static final java.lang.String TAG_APERTURE = "FNumber";
field public static final java.lang.String TAG_DATETIME = "DateTime";
field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
+ field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
field public static final java.lang.String TAG_FLASH = "Flash";
field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
@@ -20231,9 +20254,12 @@ package android.media {
field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
field public static final java.lang.String TAG_MAKE = "Make";
+ field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
field public static final java.lang.String TAG_MODEL = "Model";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+ field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
@@ -20974,6 +21000,7 @@ package android.media {
field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+ field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
field public static final java.lang.String KEY_PRIORITY = "priority";
field public static final java.lang.String KEY_PROFILE = "profile";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -21182,6 +21209,7 @@ package android.media {
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;
+ method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
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;
@@ -22548,6 +22576,10 @@ package android.media.session {
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -22581,7 +22613,6 @@ package android.media.session {
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22596,6 +22627,10 @@ package android.media.session {
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onPrepare();
+ 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 onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -22652,6 +22687,10 @@ package android.media.session {
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
@@ -22660,7 +22699,6 @@ package android.media.session {
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
- field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22736,6 +22774,10 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final boolean isChannelUri(android.net.Uri);
+ method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
+ method public static final boolean isChannelUriForTunerInput(android.net.Uri);
+ method public static final boolean isProgramUri(android.net.Uri);
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
@@ -22827,7 +22869,8 @@ package android.media.tv {
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_NUMBER = "episode_number";
+ 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";
@@ -22837,7 +22880,9 @@ package android.media.tv {
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_NUMBER = "season_number";
+ field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ 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_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
@@ -22853,6 +22898,7 @@ package android.media.tv {
public static final class TvContract.Programs.Genres {
method public static java.lang.String[] decode(java.lang.String);
method public static java.lang.String encode(java.lang.String...);
+ method public static boolean isCanonical(java.lang.String);
field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
field public static final java.lang.String ARTS = "ARTS";
field public static final java.lang.String COMEDY = "COMEDY";
@@ -22879,8 +22925,9 @@ package android.media.tv {
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_NUMBER = "episode_number";
+ 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";
@@ -22893,7 +22940,8 @@ package android.media.tv {
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_NUMBER = "season_number";
+ 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";
@@ -22916,7 +22964,9 @@ package android.media.tv {
method public android.content.pm.ServiceInfo getServiceInfo();
method public int getTunerCount();
method public int getType();
+ method public boolean isHidden(android.content.Context);
method public boolean isPassthroughInput();
+ method public java.lang.CharSequence loadCustomLabel(android.content.Context);
method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
method public java.lang.CharSequence loadLabel(android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
@@ -22952,13 +23002,13 @@ package android.media.tv {
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_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 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
field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
- field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
- field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
- field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+ field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
+ field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
@@ -22978,7 +23028,7 @@ package android.media.tv {
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
method public void onInputUpdated(java.lang.String);
- method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
+ method public void onTvInputInfoUpdated(android.media.tv.TvInputInfo);
}
public abstract class TvInputService extends android.app.Service {
@@ -22986,7 +23036,7 @@ package android.media.tv {
method public final android.os.IBinder onBind(android.content.Intent);
method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
- method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
+ method public static final void updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
}
@@ -23001,14 +23051,13 @@ package android.media.tv {
public static abstract class TvInputService.RecordingSession {
ctor public TvInputService.RecordingSession(android.content.Context);
- method public void notifyConnected();
method public void notifyError(int);
- method public void notifyRecordingStarted();
method public void notifyRecordingStopped(android.net.Uri);
- method public abstract void onConnect(android.net.Uri);
- method public abstract void onDisconnect();
- method public abstract void onStartRecording();
+ method public void notifyTuned();
+ method public abstract void onRelease();
+ method public abstract void onStartRecording(android.net.Uri);
method public abstract void onStopRecording();
+ method public abstract void onTune(android.net.Uri);
}
public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
@@ -23051,19 +23100,19 @@ package android.media.tv {
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
- method public void connect(java.lang.String, android.net.Uri);
- method public void disconnect();
- method public void startRecording();
+ method public void release();
+ method public void startRecording(android.net.Uri);
method public void stopRecording();
+ method public void tune(java.lang.String, android.net.Uri);
}
public static abstract class TvRecordingClient.RecordingCallback {
ctor public TvRecordingClient.RecordingCallback();
- method public void onConnected();
- method public void onDisconnected();
+ method public void onConnectionFailed(java.lang.String);
+ method public void onDisconnected(java.lang.String);
method public void onError(int);
- method public void onRecordingStarted();
method public void onRecordingStopped(android.net.Uri);
+ method public void onTuned();
}
public final class TvTrackInfo implements android.os.Parcelable {
@@ -23075,6 +23124,7 @@ package android.media.tv {
method public final java.lang.String getId();
method public final java.lang.String getLanguage();
method public final int getType();
+ method public final byte getVideoActiveFormatDescription();
method public final float getVideoFrameRate();
method public final int getVideoHeight();
method public final float getVideoPixelAspectRatio();
@@ -23094,6 +23144,7 @@ package android.media.tv {
method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+ method public final android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
method public final android.media.tv.TvTrackInfo.Builder setVideoPixelAspectRatio(float);
@@ -23481,6 +23532,17 @@ package android.net {
method public abstract void onNetworkActive();
}
+ public class ConnectivityMetricsEvent implements android.os.Parcelable {
+ ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+ field public final int componentTag;
+ field public final android.os.Parcelable data;
+ field public final int eventTag;
+ field public final long timestamp;
+ }
+
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -26833,6 +26895,7 @@ package android.opengl {
method public static void glProgramBinary(int, int, java.nio.Buffer, int);
method public static void glProgramParameteri(int, int, int);
method public static void glReadBuffer(int);
+ method public static void glReadPixels(int, int, int, int, int, int, int);
method public static void glRenderbufferStorageMultisample(int, int, int, int, int);
method public static void glResumeTransformFeedback();
method public static void glSamplerParameterf(int, int, float);
@@ -28418,6 +28481,10 @@ package android.os {
ctor public DeadObjectException(java.lang.String);
}
+ public class DeadSystemException extends android.os.DeadObjectException {
+ ctor public DeadSystemException();
+ }
+
public final class Debug {
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
@@ -28575,7 +28642,6 @@ package android.os {
field public static java.lang.String DIRECTORY_DCIM;
field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
- field public static java.lang.String DIRECTORY_HOME;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -29051,7 +29117,6 @@ package android.os {
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -29071,6 +29136,7 @@ package android.os {
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
+ method public static boolean isApplicationUid(int);
method public static final void killProcess(int);
method public static final int myPid();
method public static final int myTid();
@@ -29252,6 +29318,7 @@ package android.os {
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
method public static int getAppId(int);
+ method public static android.os.UserHandle getUserHandleForUid(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -29365,11 +29432,27 @@ package android.os.storage {
public class StorageManager {
method public java.lang.String getMountedObbPath(java.lang.String);
+ method public android.os.storage.StorageVolume getPrimaryVolume();
+ method public android.os.storage.StorageVolume[] getVolumeList();
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
}
+ public class StorageVolume implements android.os.Parcelable {
+ method public android.content.Intent createAccessIntent(java.lang.String);
+ method public int describeContents();
+ method public java.lang.String getDescription(android.content.Context);
+ method public java.lang.String getState();
+ method public java.lang.String getUuid();
+ method public boolean isEmulated();
+ method public boolean isPrimary();
+ method public boolean isRemovable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.storage.StorageVolume> CREATOR;
+ field public static final java.lang.String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
+ }
+
}
package android.preference {
@@ -29484,6 +29567,7 @@ package android.preference {
method protected int getPersistedInt(int);
method protected long getPersistedLong(long);
method protected java.lang.String getPersistedString(java.lang.String);
+ method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
method public android.preference.PreferenceManager getPreferenceManager();
method public android.content.SharedPreferences getSharedPreferences();
method public boolean getShouldDisableView();
@@ -29518,6 +29602,7 @@ package android.preference {
method protected boolean persistInt(int);
method protected boolean persistLong(long);
method protected boolean persistString(java.lang.String);
+ method public boolean persistStringSet(java.util.Set<java.lang.String>);
method public void restoreHierarchyState(android.os.Bundle);
method public void saveHierarchyState(android.os.Bundle);
method public void setDefaultValue(java.lang.Object);
@@ -31472,6 +31557,8 @@ package android.provider {
}
protected static abstract interface ContactsContract.PhoneLookupColumns {
+ field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String DATA_ID = "data_id";
field public static final java.lang.String LABEL = "label";
field public static final java.lang.String NORMALIZED_NUMBER = "normalized_number";
field public static final java.lang.String NUMBER = "number";
@@ -31735,6 +31822,7 @@ package android.provider {
method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
+ method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
@@ -31755,7 +31843,7 @@ package android.provider {
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
- method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+ method public void removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -32155,10 +32243,10 @@ package android.provider {
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
- field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34061,6 +34149,7 @@ package android.security.keystore {
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+ method public byte[] getAttestationChallenge();
method public java.lang.String[] getBlockModes();
method public java.util.Date getCertificateNotAfter();
method public java.util.Date getCertificateNotBefore();
@@ -34077,14 +34166,17 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyGenParameterSpec.Builder {
ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
method public android.security.keystore.KeyGenParameterSpec build();
method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
@@ -34092,6 +34184,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
@@ -34100,6 +34193,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34117,8 +34211,10 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isInsideSecureHardware();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -34179,8 +34275,10 @@ package android.security.keystore {
method public java.lang.String[] getSignaturePaddings();
method public int getUserAuthenticationValidityDurationSeconds();
method public boolean isDigestsSpecified();
+ method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyProtection.Builder {
@@ -34189,6 +34287,7 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
@@ -34196,6 +34295,7 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34492,10 +34592,11 @@ package android.service.notification {
method public int getSuppressedVisualEffects();
method public boolean isAmbient();
method public boolean matchesInterruptionFilter();
- field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
- field public static final int IMPORTANCE_HIGH = 3; // 0x3
- field public static final int IMPORTANCE_LOW = 1; // 0x1
- field public static final int IMPORTANCE_MAX = 4; // 0x4
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
field public static final int IMPORTANCE_NONE = 0; // 0x0
field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
}
@@ -34566,6 +34667,7 @@ package android.service.quicksettings {
method public final void startActivityAndCollapse(android.content.Intent);
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
@@ -36056,6 +36158,7 @@ package android.telecom {
method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public final java.util.Collection<android.telecom.Conference> getAllConferences();
method public final java.util.Collection<android.telecom.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
@@ -36332,6 +36435,7 @@ package android.telecom {
public class TelecomManager {
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
+ method public android.content.Intent createManageBlockedNumbersIntent();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
method public java.lang.String getDefaultDialerPackage();
@@ -36424,9 +36528,11 @@ package android.telecom {
package android.telephony {
public class CarrierConfigManager {
+ method public android.os.PersistableBundle getConfig(int);
method public android.os.PersistableBundle getConfig();
- method public android.os.PersistableBundle getConfigForSubId(int);
- method public void notifyConfigChangedForSubId(int);
+ method public deprecated android.os.PersistableBundle getConfigForSubId(int);
+ method public void notifyConfigChanged(int);
+ method public deprecated void notifyConfigChangedForSubId(int);
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
field public static final java.lang.String BOOL_ALLOW_VIDEO_PAUSE = "bool_allow_video_pause";
@@ -37064,12 +37170,18 @@ package android.telephony {
method public int getVoiceNetworkType(int);
method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
+ method public boolean hasCarrierPrivileges(int);
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
+ method public boolean iccCloseLogicalChannel(int, int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+ method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+ method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+ method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
method public boolean isNetworkRoaming(int);
@@ -37080,10 +37192,13 @@ package android.telephony {
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+ method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
+ method public boolean setOperatorBrandOverride(int, java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
+ method public boolean setPreferredNetworkTypeToGlobal(int);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
@@ -37612,6 +37727,7 @@ package android.test.mock {
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -37799,6 +37915,7 @@ package android.test.mock {
method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
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 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);
@@ -40679,6 +40796,21 @@ package android.view {
method public static android.view.FocusFinder getInstance();
}
+ public final class FrameMetrics {
+ ctor public FrameMetrics(android.view.FrameMetrics);
+ method public long getMetric(int);
+ field public static final int ANIMATION_DURATION = 2; // 0x2
+ field public static final int COMMAND_ISSUE_DURATION = 6; // 0x6
+ field public static final int DRAW_DURATION = 4; // 0x4
+ field public static final int FIRST_DRAW_FRAME = 9; // 0x9
+ field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 3; // 0x3
+ field public static final int SWAP_BUFFERS_DURATION = 7; // 0x7
+ field public static final int SYNC_DURATION = 5; // 0x5
+ field public static final int TOTAL_DURATION = 8; // 0x8
+ field public static final int UNKNOWN_DELAY_DURATION = 0; // 0x0
+ }
+
public abstract class FrameStats {
ctor public FrameStats();
method public final long getEndTimeNano();
@@ -43182,6 +43314,7 @@ package android.view {
ctor public Window(android.content.Context);
method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void addFlags(int);
+ method public final void addFrameMetricsListener(android.view.Window.FrameMetricsListener, android.os.Handler);
method public void clearFlags(int);
method public abstract void closeAllPanels();
method public abstract void closePanel(int);
@@ -43233,6 +43366,7 @@ package android.view {
method public abstract boolean performContextMenuIdentifierAction(int, int);
method public abstract boolean performPanelIdentifierAction(int, int, int);
method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
+ method public final void removeFrameMetricsListener(android.view.Window.FrameMetricsListener);
method public boolean requestFeature(int);
method public abstract void restoreHierarchyState(android.os.Bundle);
method public abstract android.os.Bundle saveHierarchyState();
@@ -43358,6 +43492,10 @@ package android.view {
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static abstract interface Window.FrameMetricsListener {
+ method public abstract void onMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+ }
+
public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
}
@@ -43966,6 +44104,7 @@ package android.view.accessibility {
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
field public static final int TYPE_SYSTEM = 3; // 0x3
}
@@ -44305,6 +44444,7 @@ package android.view.inputmethod {
method public int getCursorCapsMode(int);
method public android.text.Editable getEditable();
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44468,6 +44608,7 @@ package android.view.inputmethod {
method public abstract boolean finishComposingText();
method public abstract int getCursorCapsMode(int);
method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public abstract android.os.Handler getHandler();
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44499,6 +44640,7 @@ package android.view.inputmethod {
method public boolean finishComposingText();
method public int getCursorCapsMode(int);
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -46005,7 +46147,9 @@ package android.widget {
method public long getBase();
method public java.lang.String getFormat();
method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
+ method public boolean isCountDown();
method public void setBase(long);
+ method public void setCountDown(boolean);
method public void setFormat(java.lang.String);
method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
method public void start();
@@ -47097,6 +47241,7 @@ package android.widget {
method public void setChar(int, java.lang.String, char);
method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
method public void setChronometer(int, long, java.lang.String, boolean);
+ method public void setChronometerCountsDown(int, boolean);
method public void setContentDescription(int, java.lang.CharSequence);
method public void setDisplayedChild(int, int);
method public void setDouble(int, java.lang.String, double);
@@ -51468,7 +51613,6 @@ package java.lang.reflect {
method public static int getLength(java.lang.Object);
method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
- method public static java.lang.Object newArray(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
@@ -52144,7 +52288,6 @@ package java.net {
public class InetAddress implements java.io.Serializable {
method public byte[] getAddress();
- method public byte[] getAddressInternal();
method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
@@ -52418,7 +52561,7 @@ package java.net {
method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
method protected abstract void create(boolean) throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
+ method protected java.io.FileDescriptor getFileDescriptor();
method protected java.net.InetAddress getInetAddress();
method protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
method protected int getLocalPort();
@@ -52960,10 +53103,6 @@ package java.nio {
package java.nio.channels {
- public class AcceptPendingException extends java.lang.IllegalStateException {
- ctor public AcceptPendingException();
- }
-
public class AlreadyBoundException extends java.lang.IllegalStateException {
ctor public AlreadyBoundException();
}
@@ -52972,68 +53111,10 @@ package java.nio.channels {
ctor public AlreadyConnectedException();
}
- public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
- method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- }
-
- public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
- method public abstract void close() throws java.io.IOException;
- }
-
- public abstract class AsynchronousChannelGroup {
- ctor protected AsynchronousChannelGroup(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public abstract boolean isShutdown();
- method public abstract boolean isTerminated();
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void shutdown();
- method public abstract void shutdownNow() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withCachedThreadPool(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withFixedThreadPool(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousChannelGroup withThreadPool(java.util.concurrent.ExecutorService) throws java.io.IOException;
- }
-
public class AsynchronousCloseException extends java.nio.channels.ClosedChannelException {
ctor public AsynchronousCloseException();
}
- public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
- method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
- method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- }
-
- public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
- ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
- method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
- method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
- method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
- method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
- method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
- method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
- method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
- method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
- }
-
public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
}
@@ -53050,9 +53131,7 @@ package java.nio.channels {
method public static java.nio.channels.ReadableByteChannel newChannel(java.io.InputStream);
method public static java.nio.channels.WritableByteChannel newChannel(java.io.OutputStream);
method public static java.io.InputStream newInputStream(java.nio.channels.ReadableByteChannel);
- method public static java.io.InputStream newInputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
- method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
@@ -53071,16 +53150,11 @@ package java.nio.channels {
ctor public ClosedSelectorException();
}
- public abstract interface CompletionHandler {
- method public abstract void completed(V, A);
- method public abstract void failed(java.lang.Throwable, A);
- }
-
public class ConnectionPendingException extends java.lang.IllegalStateException {
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -53159,40 +53233,14 @@ package java.nio.channels {
ctor public IllegalBlockingModeException();
}
- public class IllegalChannelGroupException extends java.lang.IllegalArgumentException {
- ctor public IllegalChannelGroupException();
- }
-
public class IllegalSelectorException extends java.lang.IllegalArgumentException {
ctor public IllegalSelectorException();
}
- public class InterruptedByTimeoutException extends java.io.IOException {
- ctor public InterruptedByTimeoutException();
- }
-
public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
public abstract interface NetworkChannel implements java.nio.channels.Channel {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -53242,10 +53290,6 @@ package java.nio.channels {
method public final int validOps();
}
- public class ReadPendingException extends java.lang.IllegalStateException {
- ctor public ReadPendingException();
- }
-
public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
}
@@ -53323,10 +53367,6 @@ package java.nio.channels {
method public final int validOps();
}
- public class ShutdownChannelGroupException extends java.lang.IllegalStateException {
- ctor public ShutdownChannelGroupException();
- }
-
public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
@@ -53362,10 +53402,6 @@ package java.nio.channels {
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
}
- public class WritePendingException extends java.lang.IllegalStateException {
- ctor public WritePendingException();
- }
-
}
package java.nio.channels.spi {
@@ -53412,15 +53448,6 @@ package java.nio.channels.spi {
method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
}
- public abstract class AsynchronousChannelProvider {
- ctor protected AsynchronousChannelProvider();
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(int, java.util.concurrent.ThreadFactory) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousChannelGroup openAsynchronousChannelGroup(java.util.concurrent.ExecutorService, int) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public abstract java.nio.channels.AsynchronousSocketChannel openAsynchronousSocketChannel(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
- method public static java.nio.channels.spi.AsynchronousChannelProvider provider();
- }
-
public abstract class SelectorProvider {
ctor protected SelectorProvider();
method public java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
@@ -54235,7 +54262,6 @@ package java.security {
public abstract class Signature extends java.security.SignatureSpi {
ctor protected Signature(java.lang.String);
method public final java.lang.String getAlgorithm();
- method public java.security.SignatureSpi getCurrentSpi();
method public static java.security.Signature getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
method public static java.security.Signature getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.Signature getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
@@ -56775,13 +56801,11 @@ package java.text {
method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
method public java.lang.String getInternationalCurrencySymbol();
method public char getMinusSign();
- method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
method public java.lang.String getNaN();
method public char getPatternSeparator();
method public char getPerMill();
method public char getPercent();
- method public java.lang.String getPercentString();
method public char getZeroDigit();
method public void setCurrency(java.util.Currency);
method public void setCurrencySymbol(java.lang.String);
@@ -58034,8 +58058,11 @@ package java.util {
method public static boolean equals(java.lang.Object, java.lang.Object);
method public static int hash(java.lang.Object...);
method public static int hashCode(java.lang.Object);
+ method public static boolean isNull(java.lang.Object);
+ method public static boolean nonNull(java.lang.Object);
method public static T requireNonNull(T);
method public static T requireNonNull(T, java.lang.String);
+ method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
method public static java.lang.String toString(java.lang.Object);
method public static java.lang.String toString(java.lang.Object, java.lang.String);
}
@@ -59740,6 +59767,217 @@ package java.util.concurrent.locks {
}
+package java.util.function {
+
+ public abstract interface BiConsumer {
+ method public abstract void accept(T, U);
+ method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
+ }
+
+ public abstract interface BiFunction {
+ method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
+ method public abstract R apply(T, U);
+ }
+
+ public abstract interface BiPredicate {
+ method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
+ method public default java.util.function.BiPredicate<T, U> negate();
+ method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
+ method public abstract boolean test(T, U);
+ }
+
+ public abstract interface BinaryOperator implements java.util.function.BiFunction {
+ method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
+ method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
+ }
+
+ public abstract interface BooleanSupplier {
+ method public abstract boolean getAsBoolean();
+ }
+
+ public abstract interface Consumer {
+ method public abstract void accept(T);
+ method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
+ }
+
+ public abstract interface DoubleBinaryOperator {
+ method public abstract double applyAsDouble(double, double);
+ }
+
+ public abstract interface DoubleConsumer {
+ method public abstract void accept(double);
+ method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
+ }
+
+ public abstract interface DoubleFunction {
+ method public abstract R apply(double);
+ }
+
+ public abstract interface DoublePredicate {
+ method public default java.util.function.DoublePredicate and(java.util.function.DoublePredicate);
+ method public default java.util.function.DoublePredicate negate();
+ method public default java.util.function.DoublePredicate or(java.util.function.DoublePredicate);
+ method public abstract boolean test(double);
+ }
+
+ public abstract interface DoubleSupplier {
+ method public abstract double getAsDouble();
+ }
+
+ public abstract interface DoubleToIntFunction {
+ method public abstract int applyAsInt(double);
+ }
+
+ public abstract interface DoubleToLongFunction {
+ method public abstract long applyAsLong(double);
+ }
+
+ public abstract interface DoubleUnaryOperator {
+ method public default java.util.function.DoubleUnaryOperator andThen(java.util.function.DoubleUnaryOperator);
+ method public abstract double applyAsDouble(double);
+ method public default java.util.function.DoubleUnaryOperator compose(java.util.function.DoubleUnaryOperator);
+ method public static java.util.function.DoubleUnaryOperator identity();
+ }
+
+ public abstract interface Function {
+ method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
+ method public abstract R apply(T);
+ method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
+ method public static java.util.function.Function<T, T> identity();
+ }
+
+ public abstract interface IntBinaryOperator {
+ method public abstract int applyAsInt(int, int);
+ }
+
+ public abstract interface IntConsumer {
+ method public abstract void accept(int);
+ method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
+ }
+
+ public abstract interface IntFunction {
+ method public abstract R apply(int);
+ }
+
+ public abstract interface IntPredicate {
+ method public default java.util.function.IntPredicate and(java.util.function.IntPredicate);
+ method public default java.util.function.IntPredicate negate();
+ method public default java.util.function.IntPredicate or(java.util.function.IntPredicate);
+ method public abstract boolean test(int);
+ }
+
+ public abstract interface IntSupplier {
+ method public abstract int getAsInt();
+ }
+
+ public abstract interface IntToDoubleFunction {
+ method public abstract double applyAsDouble(int);
+ }
+
+ public abstract interface IntToLongFunction {
+ method public abstract long applyAsLong(int);
+ }
+
+ public abstract interface IntUnaryOperator {
+ method public default java.util.function.IntUnaryOperator andThen(java.util.function.IntUnaryOperator);
+ method public abstract int applyAsInt(int);
+ method public default java.util.function.IntUnaryOperator compose(java.util.function.IntUnaryOperator);
+ method public static java.util.function.IntUnaryOperator identity();
+ }
+
+ public abstract interface LongBinaryOperator {
+ method public abstract long applyAsLong(long, long);
+ }
+
+ public abstract interface LongConsumer {
+ method public abstract void accept(long);
+ method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
+ }
+
+ public abstract interface LongFunction {
+ method public abstract R apply(long);
+ }
+
+ public abstract interface LongPredicate {
+ method public default java.util.function.LongPredicate and(java.util.function.LongPredicate);
+ method public default java.util.function.LongPredicate negate();
+ method public default java.util.function.LongPredicate or(java.util.function.LongPredicate);
+ method public abstract boolean test(long);
+ }
+
+ public abstract interface LongSupplier {
+ method public abstract long getAsLong();
+ }
+
+ public abstract interface LongToDoubleFunction {
+ method public abstract double applyAsDouble(long);
+ }
+
+ public abstract interface LongToIntFunction {
+ method public abstract int applyAsInt(long);
+ }
+
+ public abstract interface LongUnaryOperator {
+ method public default java.util.function.LongUnaryOperator andThen(java.util.function.LongUnaryOperator);
+ method public abstract long applyAsLong(long);
+ method public default java.util.function.LongUnaryOperator compose(java.util.function.LongUnaryOperator);
+ method public static java.util.function.LongUnaryOperator identity();
+ }
+
+ public abstract interface ObjDoubleConsumer {
+ method public abstract void accept(T, double);
+ }
+
+ public abstract interface ObjIntConsumer {
+ method public abstract void accept(T, int);
+ }
+
+ public abstract interface ObjLongConsumer {
+ method public abstract void accept(T, long);
+ }
+
+ public abstract interface Predicate {
+ method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
+ method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
+ method public default java.util.function.Predicate<T> negate();
+ method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
+ method public abstract boolean test(T);
+ }
+
+ public abstract interface Supplier {
+ method public abstract T get();
+ }
+
+ public abstract interface ToDoubleBiFunction {
+ method public abstract double applyAsDouble(T, U);
+ }
+
+ public abstract interface ToDoubleFunction {
+ method public abstract double applyAsDouble(T);
+ }
+
+ public abstract interface ToIntBiFunction {
+ method public abstract int applyAsInt(T, U);
+ }
+
+ public abstract interface ToIntFunction {
+ method public abstract int applyAsInt(T);
+ }
+
+ public abstract interface ToLongBiFunction {
+ method public abstract long applyAsLong(T, U);
+ }
+
+ public abstract interface ToLongFunction {
+ method public abstract long applyAsLong(T);
+ }
+
+ public abstract interface UnaryOperator implements java.util.function.Function {
+ method public static java.util.function.UnaryOperator<T> identity();
+ }
+
+}
+
package java.util.jar {
public class Attributes implements java.lang.Cloneable java.util.Map {
@@ -62474,14 +62712,6 @@ package javax.security.auth {
method public abstract boolean isDestroyed();
}
- public abstract deprecated class Policy {
- ctor protected Policy();
- method public abstract java.security.PermissionCollection getPermissions(javax.security.auth.Subject, java.security.CodeSource);
- method public static javax.security.auth.Policy getPolicy();
- method public abstract void refresh();
- method public static void setPolicy(javax.security.auth.Policy);
- }
-
public final class PrivateCredentialPermission extends java.security.Permission {
ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
method public boolean equals(java.lang.Object);
@@ -62546,43 +62776,6 @@ package javax.security.auth.callback {
package javax.security.auth.login {
- public class AppConfigurationEntry {
- ctor public AppConfigurationEntry(java.lang.String, javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag, java.util.Map<java.lang.String, ?>);
- method public javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag getControlFlag();
- method public java.lang.String getLoginModuleName();
- method public java.util.Map<java.lang.String, ?> getOptions();
- }
-
- public static class AppConfigurationEntry.LoginModuleControlFlag {
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag OPTIONAL;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag REQUIRED;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag REQUISITE;
- field public static final javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag SUFFICIENT;
- }
-
- public abstract class Configuration {
- ctor protected Configuration();
- method public abstract javax.security.auth.login.AppConfigurationEntry[] getAppConfigurationEntry(java.lang.String);
- method public static javax.security.auth.login.Configuration getConfiguration();
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters) throws java.security.NoSuchAlgorithmException;
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
- method public static javax.security.auth.login.Configuration getInstance(java.lang.String, javax.security.auth.login.Configuration.Parameters, java.security.Provider) throws java.security.NoSuchAlgorithmException;
- method public javax.security.auth.login.Configuration.Parameters getParameters();
- method public java.security.Provider getProvider();
- method public java.lang.String getType();
- method public void refresh();
- method public static void setConfiguration(javax.security.auth.login.Configuration);
- }
-
- public static abstract interface Configuration.Parameters {
- }
-
- public abstract class ConfigurationSpi {
- ctor public ConfigurationSpi();
- method protected abstract javax.security.auth.login.AppConfigurationEntry[] engineGetAppConfigurationEntry(java.lang.String);
- method protected void engineRefresh();
- }
-
public class LoginException extends java.security.GeneralSecurityException {
ctor public LoginException();
ctor public LoginException(java.lang.String);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 0bf659438340..50a24f6dfd93 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -9,6 +9,8 @@ package android.app {
package android.app.admin {
public class DevicePolicyManager {
+ method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
+ method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
}
@@ -35,7 +37,7 @@ package android.database {
package android.media {
- public class AudioFormat {
+ public class AudioFormat implements android.os.Parcelable {
ctor public AudioFormat();
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 6206323a89f5..eedb82bd5d0a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -167,6 +167,7 @@ public class Am extends BaseCommand {
" am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
" am stack list\n" +
" am stack info <STACK_ID>\n" +
+ " am stack remove <STACK_ID>\n" +
" am task lock <TASK_ID>\n" +
" am task lock stop\n" +
" am task resizeable <TASK_ID> [0 (unresizeable) | 1 (crop_windows) | 2 (resizeable) | 3 (resizeable_and_pipable)]\n" +
@@ -324,6 +325,8 @@ public class Am extends BaseCommand {
"\n" +
"am stack info: display the information about activity stack <STACK_ID>.\n" +
"\n" +
+ "am stack remove: remove stack <STACK_ID>.\n" +
+ "\n" +
"am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.\n" +
"\n" +
"am task lock stop: end the current task lock.\n" +
@@ -1732,6 +1735,9 @@ public class Am extends BaseCommand {
case "size-docked-stack-test":
runStackSizeDockedStackTest();
break;
+ case "remove":
+ runStackRemove();
+ break;
default:
showError("Error: unknown command '" + op + "'");
break;
@@ -1868,6 +1874,12 @@ public class Am extends BaseCommand {
}
}
+ private void runStackRemove() throws Exception {
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ mAm.removeStack(stackId);
+ }
+
private void runMoveTopActivityToPinnedStack() throws Exception {
int stackId = Integer.valueOf(nextArgRequired());
final Rect bounds = getBounds();
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 51bbb813df65..3ae9e1204632 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -20,6 +20,7 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
liblog \
libbinder \
+ libnativeloader \
libandroid_runtime \
$(app_process_common_shared_libs) \
@@ -52,6 +53,7 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
liblog \
libbinder \
+ libnativeloader \
libandroid_runtime \
$(app_process_common_shared_libs) \
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 2e023825a219..8bcbf51cc857 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -21,6 +21,7 @@
#include <cutils/properties.h>
#include <cutils/trace.h>
#include <android_runtime/AndroidRuntime.h>
+#include <nativeloader/native_loader.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
namespace android {
@@ -304,6 +305,7 @@ int main(int argc, char* const argv[])
}
if (zygote) {
+ PreloadPublicNativeLibraries();
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 67d63a44a908..69b5a17300de 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,11 +23,15 @@ import android.app.backup.IBackupManager;
import android.app.backup.IBackupObserver;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
public final class Bmgr {
IBackupManager mBmgr;
@@ -36,7 +40,9 @@ public final class Bmgr {
static final String BMGR_NOT_RUNNING_ERR =
"Error: Could not access the Backup Manager. Is the system running?";
static final String TRANSPORT_NOT_RUNNING_ERR =
- "Error: Could not access the backup transport. Is the system running?";
+ "Error: Could not access the backup transport. Is the system running?";
+ static final String PM_NOT_RUNNING_ERR =
+ "Error: Could not access the Package Manager. Is the system running?";
private String[] mArgs;
private int mNextArg;
@@ -203,19 +209,20 @@ public final class Bmgr {
@Override
public void onUpdate(String currentPackage, BackupProgress backupProgress) {
System.out.println(
- "onUpdate: " + currentPackage + " with progress: " + backupProgress.bytesTransferred
+ "Package " + currentPackage + " with progress: " + backupProgress.bytesTransferred
+ "/" + backupProgress.bytesExpected);
}
@Override
public void onResult(String currentPackage, int status) {
- System.out.println("onResult: " + currentPackage + " with result: "
+ System.out.println("Package " + currentPackage + " with result: "
+ convertBackupStatusToString(status));
}
@Override
public void backupFinished(int status) {
- System.out.println("backupFinished: " + convertBackupStatusToString(status));
+ System.out.println("Backup finished with result: "
+ + convertBackupStatusToString(status));
synchronized (this) {
done = true;
this.notify();
@@ -251,31 +258,83 @@ public final class Bmgr {
return "Transport rejected package";
case BackupManager.ERROR_AGENT_FAILURE:
return "Agent error";
+ case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
+ return "Size quota exceeded";
default:
return "Unknown error";
}
}
+ private void backupNowAllPackages() {
+ int userId = UserHandle.USER_SYSTEM;
+ IPackageManager mPm =
+ IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ if (mPm == null) {
+ System.err.println(PM_NOT_RUNNING_ERR);
+ return;
+ }
+ List<PackageInfo> installedPackages = null;
+ try {
+ installedPackages = mPm.getInstalledPackages(0, userId).getList();
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(PM_NOT_RUNNING_ERR);
+ }
+ if (installedPackages != null) {
+ List<String> packages = new ArrayList<>();
+ for (PackageInfo pi : installedPackages) {
+ try {
+ if (mBmgr.isAppEligibleForBackup(pi.packageName)) {
+ packages.add(pi.packageName);
+ }
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+ backupNowPackages(packages);
+ }
+ }
+
+ private void backupNowPackages(List<String> packages) {
+ try {
+ BackupObserver observer = new BackupObserver();
+ int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer);
+ if (err == 0) {
+ // Off and running -- wait for the backup to complete
+ observer.waitForCompletion();
+ } else {
+ System.err.println("Unable to run backup");
+ }
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+
private void doBackupNow() {
String pkg;
+ boolean backupAll = false;
ArrayList<String> allPkgs = new ArrayList<String>();
while ((pkg = nextArg()) != null) {
- allPkgs.add(pkg);
+ if (pkg.equals("--all")) {
+ backupAll = true;
+ } else {
+ allPkgs.add(pkg);
+ }
}
- if (allPkgs.size() > 0) {
- try {
- BackupObserver observer = new BackupObserver();
- int err = mBmgr.requestBackup(allPkgs.toArray(new String[allPkgs.size()]), observer);
- if (err == 0) {
- // Off and running -- wait for the backup to complete
- observer.waitForCompletion();
- } else {
- System.err.println("Unable to run backup");
- }
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(BMGR_NOT_RUNNING_ERR);
+ if (backupAll) {
+ if (allPkgs.size() == 0) {
+ System.out.println("Running backup for all packages.");
+ backupNowAllPackages();
+ } else {
+ System.err.println("Provide only '--all' flag or list of packages.");
}
+ } else if (allPkgs.size() > 0) {
+ System.out.println("Running backup for " + allPkgs.size() +" requested packages.");
+ backupNowPackages(allPkgs);
+ } else {
+ System.err.println("Provide '--all' flag or list of packages.");
}
}
@@ -568,6 +627,7 @@ public final class Bmgr {
System.err.println(" bmgr run");
System.err.println(" bmgr wipe TRANSPORT PACKAGE");
System.err.println(" bmgr fullbackup PACKAGE...");
+ System.err.println(" bmgr backupnow --all|PACKAGE...");
System.err.println("");
System.err.println("The 'backup' command schedules a backup pass for the named package.");
System.err.println("Note that the backup pass will effectively be a no-op if the package");
@@ -620,6 +680,7 @@ public final class Bmgr {
System.err.println("packages. The data is sent via the currently active transport.");
System.err.println("");
System.err.println("The 'backupnow' command runs an immediate backup for one or more packages.");
+ System.err.println(" --all flag runs backup for all eligible packages.");
System.err.println("For each package it will run key/value or full data backup ");
System.err.println("depending on the package's manifest declarations.");
System.err.println("The data is sent via the currently active transport.");
diff --git a/cmds/hid/jni/Android.mk b/cmds/hid/jni/Android.mk
index 8163a9d764ff..d41d39d27f5b 100644
--- a/cmds/hid/jni/Android.mk
+++ b/cmds/hid/jni/Android.mk
@@ -18,6 +18,6 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE := libhidcommand_jni
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -Wall
+LOCAL_CFLAGS += -Wall -Wextra -Werror
include $(BUILD_SHARED_LIBRARY)
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 4278e7d3ac12..1ea33ced7bbf 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -49,7 +49,7 @@ static struct {
jmethodID onDeviceError;
} gDeviceCallbackClassInfo;
-static int handleLooperEvents(int fd, int events, void* data) {
+static int handleLooperEvents(int /* fd */, int events, void* data) {
Device* d = reinterpret_cast<Device*>(data);
return d->handleEvents(events);
}
@@ -183,7 +183,7 @@ std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& ou
return data;
}
-static jlong openDevice(JNIEnv* env, jclass clazz, jstring rawName, jint id, jint vid, jint pid,
+static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
jbyteArray rawDescriptor, jobject queue, jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
@@ -202,7 +202,7 @@ static jlong openDevice(JNIEnv* env, jclass clazz, jstring rawName, jint id, jin
return reinterpret_cast<jlong>(d);
}
-static void sendReport(JNIEnv* env, jclass clazz, jlong ptr,jbyteArray rawReport) {
+static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr,jbyteArray rawReport) {
size_t size;
std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
@@ -211,7 +211,7 @@ static void sendReport(JNIEnv* env, jclass clazz, jlong ptr,jbyteArray rawReport
}
}
-static void closeDevice(JNIEnv* env, jclass clazz, jlong ptr) {
+static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
if (d) {
delete d;
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 24449d43b350..4025553b7674 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1490,7 +1490,7 @@ public final class Pm {
System.err.println(" -i: specify the installer package name");
System.err.println(" -s: install application on sdcard");
System.err.println(" -f: install application on internal flash");
- System.err.println(" -d: allow version code downgrade");
+ System.err.println(" -d: allow version code downgrade (debuggable packages only)");
System.err.println(" -p: partial application install");
System.err.println(" -g: grant all runtime permissions");
System.err.println(" -S: size in bytes of entire session");
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
index e0f09ee2c666..8e9791f8b731 100644
--- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -58,7 +58,7 @@ public class NfcCommand extends Svc.Command {
IPackageManager pm = IPackageManager.Stub.asInterface(
ServiceManager.getService("package"));
try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0)) {
INfcAdapter nfc = INfcAdapter.Stub
.asInterface(ServiceManager.getService(Context.NFC_SERVICE));
try {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4bc6b97c834d..fb5f5b9e1efc 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -334,7 +334,7 @@ public abstract class AccessibilityService extends Service {
public static final int GLOBAL_ACTION_HOME = 2;
/**
- * Action to open the recent apps.
+ * Action to toggle showing the overview of recent apps
*/
public static final int GLOBAL_ACTION_RECENTS = 3;
@@ -353,6 +353,11 @@ public abstract class AccessibilityService extends Service {
*/
public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
+ /**
+ * Action to toggle docking the current app's window
+ */
+ public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 079bdfcb7b90..75680e6a60ec 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -686,6 +686,11 @@ public class AccessibilityServiceInfo implements Parcelable {
return null;
}
+ /** {@hide} */
+ public boolean isEncryptionAware() {
+ return mResolveInfo.serviceInfo.encryptionAware;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 1d9e3bb4b4bb..e520b406656b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -353,8 +353,7 @@ public class AccountManager {
try {
return mService.getPassword(account);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -382,8 +381,7 @@ public class AccountManager {
try {
return mService.getUserData(account, key);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -402,8 +400,7 @@ public class AccountManager {
try {
return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
} catch (RemoteException e) {
- // will never happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -424,8 +421,7 @@ public class AccountManager {
try {
return mService.getAuthenticatorTypes(userId);
} catch (RemoteException e) {
- // will never happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -449,8 +445,7 @@ public class AccountManager {
try {
return mService.getAccounts(null, mContext.getOpPackageName());
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -475,8 +470,7 @@ public class AccountManager {
try {
return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -493,8 +487,7 @@ public class AccountManager {
try {
return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
} catch (RemoteException re) {
- // won't ever happen
- throw new RuntimeException(re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -512,8 +505,7 @@ public class AccountManager {
return mService.getAccountsByTypeForPackage(type, packageName,
mContext.getOpPackageName());
} catch (RemoteException re) {
- // won't ever happen
- throw new RuntimeException(re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -552,8 +544,7 @@ public class AccountManager {
return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
mContext.getOpPackageName());
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -572,8 +563,7 @@ public class AccountManager {
try {
mService.updateAppPermission(account, authTokenType, uid, value);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -742,8 +732,7 @@ public class AccountManager {
try {
return mService.addAccountExplicitly(account, password, userdata);
} catch (RemoteException e) {
- // Can happen if there was a SecurityException was thrown.
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -768,7 +757,7 @@ public class AccountManager {
try {
return mService.accountAuthenticated(account);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -836,8 +825,7 @@ public class AccountManager {
try {
return mService.getPreviousName(account);
} catch (RemoteException e) {
- // will never happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1008,8 +996,7 @@ public class AccountManager {
try {
return mService.removeAccountExplicitly(account);
} catch (RemoteException e) {
- // May happen if the caller doesn't match the signature of the authenticator.
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1036,8 +1023,7 @@ public class AccountManager {
mService.invalidateAuthToken(accountType, authToken);
}
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1068,8 +1054,7 @@ public class AccountManager {
try {
return mService.peekAuthToken(account, authTokenType);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1098,8 +1083,7 @@ public class AccountManager {
try {
mService.setPassword(account, password);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1127,8 +1111,7 @@ public class AccountManager {
try {
mService.clearPassword(account);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1156,8 +1139,7 @@ public class AccountManager {
try {
mService.setUserData(account, key, value);
} catch (RemoteException e) {
- // Will happen if there is not signature match.
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1186,8 +1168,7 @@ public class AccountManager {
try {
mService.setAuthToken(account, authTokenType, authToken);
} catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1588,7 +1569,7 @@ public class AccountManager {
mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
user.getIdentifier());
} catch (RemoteException re) {
- throw new IllegalStateException(re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1641,8 +1622,7 @@ public class AccountManager {
boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
return val;
} catch (RemoteException re) {
- // won't ever happen
- throw new RuntimeException(re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1655,8 +1635,7 @@ public class AccountManager {
try {
return mService.getSharedAccountsAsUser(user.getIdentifier());
} catch (RemoteException re) {
- // won't ever happen
- throw new RuntimeException(re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1878,7 +1857,7 @@ public class AccountManager {
try {
return mService.someUserHasAccount(account);
} catch (RemoteException re) {
- throw new RuntimeException(re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -2039,8 +2018,7 @@ public class AccountManager {
try {
doWork();
} catch (RemoteException e) {
- // this will only happen if the system process is dead, which means
- // we will be dying ourselves
+ throw e.rethrowFromSystemServer();
}
} else {
set(bundle);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 980329fe31c8..3385a17002bc 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -807,6 +807,8 @@ public final class AnimatorSet extends Animator {
}
/**
+ * AnimatorSet is only reversible when the set contains no sequential animation, and no child
+ * animators have a start delay.
* @hide
*/
@Override
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 622012ecf2e2..32751b2b47fe 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,8 @@
package android.app;
+import static java.lang.Character.MIN_VALUE;
+
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
@@ -26,20 +28,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.StyleRes;
-import android.os.PersistableBundle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
-import android.util.ArrayMap;
-import android.util.SuperNotCalledException;
-import android.view.DragEvent;
-import android.view.DropPermissions;
-import android.view.Window.WindowControllerCallback;
-import android.widget.Toolbar;
-
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.app.ToolbarActionBar;
-
import android.annotation.SystemApi;
import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
@@ -61,7 +49,13 @@ import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -71,6 +65,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.UserHandle;
@@ -78,16 +73,22 @@ import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SuperNotCalledException;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
+import android.view.DragEvent;
+import android.view.DropPermissions;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -104,11 +105,17 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewManager;
import android.view.ViewRootImpl;
import android.view.Window;
+import android.view.Window.WindowControllerCallback;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
+import android.widget.Toolbar;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneWindow;
import java.io.FileDescriptor;
@@ -119,8 +126,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import static java.lang.Character.MIN_VALUE;
-
/**
* An activity is a single, focused thing that the user can do. Almost all
* activities interact with the user, so the Activity class takes care of
@@ -810,6 +815,9 @@ public class Activity extends ContextThemeWrapper
private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE;
private SpannableStringBuilder mDefaultKeySsb = null;
+ private ActivityManager.TaskDescription mTaskDescription =
+ new ActivityManager.TaskDescription();
+
protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
@SuppressWarnings("unused")
@@ -1111,6 +1119,34 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Attempts to extract the color from a given drawable.
+ *
+ * @return the extracted color or 0 if no color could be extracted.
+ */
+ private int tryExtractColorFromDrawable(Drawable drawable) {
+ if (drawable instanceof ColorDrawable) {
+ return ((ColorDrawable) drawable).getColor();
+ } else if (drawable instanceof InsetDrawable) {
+ return tryExtractColorFromDrawable(((InsetDrawable) drawable).getDrawable());
+ } else if (drawable instanceof ShapeDrawable) {
+ Paint p = ((ShapeDrawable) drawable).getPaint();
+ if (p != null) {
+ return p.getColor();
+ }
+ } else if (drawable instanceof LayerDrawable) {
+ LayerDrawable ld = (LayerDrawable) drawable;
+ int numLayers = ld.getNumberOfLayers();
+ for (int i = 0; i < numLayers; i++) {
+ int color = tryExtractColorFromDrawable(ld.getDrawable(i));
+ if (color != 0) {
+ return color;
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
* Called when activity start-up is complete (after {@link #onStart}
* and {@link #onRestoreInstanceState} have been called). Applications will
* generally not implement this method; it is intended for system
@@ -1131,6 +1167,36 @@ public class Activity extends ContextThemeWrapper
mTitleReady = true;
onTitleChanged(getTitle(), getTitleColor());
}
+
+ Resources.Theme theme = getTheme();
+ if (theme != null) {
+ // Get the primary color and update the TaskDescription for this activity
+ TypedArray a = theme.obtainStyledAttributes(
+ com.android.internal.R.styleable.ActivityTaskDescription);
+ if (mTaskDescription.getPrimaryColor() == 0) {
+ int colorPrimary = a.getColor(
+ com.android.internal.R.styleable.ActivityTaskDescription_colorPrimary, 0);
+ if (colorPrimary != 0 && Color.alpha(colorPrimary) == 0xFF) {
+ mTaskDescription.setPrimaryColor(colorPrimary);
+ }
+ }
+ if (mTaskDescription.getBackgroundColor() == 0) {
+ int windowBgResourceId = a.getResourceId(
+ com.android.internal.R.styleable.ActivityTaskDescription_windowBackground,
+ 0);
+ int windowBgFallbackResourceId = a.getResourceId(
+ com.android.internal.R.styleable.ActivityTaskDescription_windowBackgroundFallback,
+ 0);
+ int colorBg = tryExtractColorFromDrawable(DecorView.getResizingBackgroundDrawable(
+ this, windowBgResourceId, windowBgFallbackResourceId));
+ if (colorBg != 0 && Color.alpha(colorBg) == 0xFF) {
+ mTaskDescription.setBackgroundColor(colorBg);
+ }
+ }
+ a.recycle();
+ setTaskDescription(mTaskDescription);
+ }
+
mCalled = true;
}
@@ -3970,18 +4036,6 @@ public class Activity extends ContextThemeWrapper
}
theme.applyStyle(resid, false);
}
-
- // Get the primary color and update the TaskDescription for this activity
- if (theme != null) {
- TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
- int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
- a.recycle();
- if (colorPrimary != 0) {
- ActivityManager.TaskDescription v = new ActivityManager.TaskDescription(null, null,
- colorPrimary);
- setTaskDescription(v);
- }
- }
}
/**
@@ -4056,7 +4110,7 @@ public class Activity extends ContextThemeWrapper
* }
* </code></pre></p>
*
- * @param permissions The requested permissions.
+ * @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
* reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
* Should be >= 0.
@@ -5607,18 +5661,18 @@ public class Activity extends ContextThemeWrapper
* @param taskDescription The TaskDescription properties that describe the task with this activity
*/
public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
- ActivityManager.TaskDescription td;
- // Scale the icon down to something reasonable if it is provided
- if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
- final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
- final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
- td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon,
- taskDescription.getPrimaryColor());
- } else {
- td = taskDescription;
+ if (mTaskDescription != taskDescription) {
+ mTaskDescription.copyFrom(taskDescription);
+ // Scale the icon down to something reasonable if it is provided
+ if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
+ final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
+ final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size,
+ true);
+ mTaskDescription.setIcon(icon);
+ }
}
try {
- ActivityManagerNative.getDefault().setTaskDescription(mToken, td);
+ ActivityManagerNative.getDefault().setTaskDescription(mToken, mTaskDescription);
} catch (RemoteException e) {
}
}
@@ -6574,9 +6628,7 @@ public class Activity extends ContextThemeWrapper
mFragments.noteStateNotSaved();
if (mToken != null && mParent == null) {
- // We might have view roots that were preserved during a relaunch, we need to start them
- // again. We don't need to check mStopped, the roots will check if they were actually
- // stopped.
+ // No need to check mStopped, the roots will check if they were actually stopped.
WindowManagerGlobal.getInstance().setStoppedState(mToken, false /* stopped */);
}
@@ -6674,7 +6726,7 @@ public class Activity extends ContextThemeWrapper
onUserLeaveHint();
}
- final void performStop() {
+ final void performStop(boolean preserveWindow) {
mDoReportFullyDrawn = false;
mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
@@ -6683,7 +6735,10 @@ public class Activity extends ContextThemeWrapper
mWindow.closeAllPanels();
}
- if (mToken != null && mParent == null) {
+ // If we're preserving the window, don't setStoppedState to true, since we
+ // need the window started immediately again. Stopping the window will
+ // destroys hardware resources and causes flicker.
+ if (!preserveWindow && mToken != null && mParent == null) {
WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1eb2fe2c89ec..4aab163597d6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -581,8 +581,12 @@ public class ActivityManager {
* the task to the specified stack.
*/
public static boolean useAnimationSpecForAppTransition(int stackId) {
+
+ // TODO: INVALID_STACK_ID is also animated because we don't persist stack id's across
+ // reboots.
return stackId == FREEFORM_WORKSPACE_STACK_ID
- || stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
+ || stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID
+ || stackId == INVALID_STACK_ID;
}
/** Returns true if the windows in the stack can receive input keys. */
@@ -632,6 +636,17 @@ public class ActivityManager {
public static boolean useWindowFrameForBackdrop(int stackId) {
return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
}
+
+ /**
+ * Returns true if a window from the specified stack with {@param stackId} are normally
+ * fullscreen, i. e. they can become the top opaque fullscreen window, meaning that it
+ * controls system bars, lockscreen occluded/dismissing state, screen rotation animation,
+ * etc.
+ */
+ public static boolean normallyFullscreenWindows(int stackId) {
+ return stackId != PINNED_STACK_ID && stackId != FREEFORM_WORKSPACE_STACK_ID
+ && stackId != DOCKED_STACK_ID;
+ }
}
/**
@@ -701,8 +716,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode();
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -711,7 +725,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
+ throw e.rethrowFromSystemServer();
}
}
@@ -720,8 +734,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getPackageScreenCompatMode(packageName);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -730,7 +743,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().setPackageScreenCompatMode(packageName, mode);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
+ throw e.rethrowFromSystemServer();
}
}
@@ -739,8 +752,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getPackageAskScreenCompat(packageName);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -749,7 +761,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().setPackageAskScreenCompat(packageName, ask);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
+ throw e.rethrowFromSystemServer();
}
}
@@ -863,8 +875,10 @@ public class ActivityManager {
public static final String ATTR_TASKDESCRIPTION_PREFIX = "task_description_";
private static final String ATTR_TASKDESCRIPTIONLABEL =
ATTR_TASKDESCRIPTION_PREFIX + "label";
- private static final String ATTR_TASKDESCRIPTIONCOLOR =
+ private static final String ATTR_TASKDESCRIPTIONCOLOR_PRIMARY =
ATTR_TASKDESCRIPTION_PREFIX + "color";
+ private static final String ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND =
+ ATTR_TASKDESCRIPTION_PREFIX + "colorBackground";
private static final String ATTR_TASKDESCRIPTIONICONFILENAME =
ATTR_TASKDESCRIPTION_PREFIX + "icon_filename";
@@ -872,28 +886,21 @@ public class ActivityManager {
private Bitmap mIcon;
private String mIconFilename;
private int mColorPrimary;
+ private int mColorBackground;
/**
* Creates the TaskDescription to the specified values.
*
* @param label A label and description of the current state of this task.
* @param icon An icon that represents the current state of this task.
- * @param colorPrimary A color to override the theme's primary color. This color must be opaque.
+ * @param colorPrimary A color to override the theme's primary color. This color must be
+ * opaque.
*/
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
+ this(label, icon, null, colorPrimary, 0);
if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
throw new RuntimeException("A TaskDescription's primary color should be opaque");
}
-
- mLabel = label;
- mIcon = icon;
- mColorPrimary = colorPrimary;
- }
-
- /** @hide */
- public TaskDescription(String label, int colorPrimary, String iconFilename) {
- this(label, null, colorPrimary);
- mIconFilename = iconFilename;
}
/**
@@ -903,7 +910,7 @@ public class ActivityManager {
* @param icon An icon that represents the current state of this activity.
*/
public TaskDescription(String label, Bitmap icon) {
- this(label, icon, 0);
+ this(label, icon, null, 0, 0);
}
/**
@@ -912,24 +919,43 @@ public class ActivityManager {
* @param label A label and description of the current state of this activity.
*/
public TaskDescription(String label) {
- this(label, null, 0);
+ this(label, null, null, 0, 0);
}
/**
* Creates an empty TaskDescription.
*/
public TaskDescription() {
- this(null, null, 0);
+ this(null, null, null, 0, 0);
+ }
+
+ /** @hide */
+ public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
+ int colorBackground) {
+ mLabel = label;
+ mIcon = icon;
+ mIconFilename = iconFilename;
+ mColorPrimary = colorPrimary;
+ mColorBackground = colorBackground;
}
/**
* Creates a copy of another TaskDescription.
*/
public TaskDescription(TaskDescription td) {
- mLabel = td.mLabel;
- mIcon = td.mIcon;
- mColorPrimary = td.mColorPrimary;
- mIconFilename = td.mIconFilename;
+ copyFrom(td);
+ }
+
+ /**
+ * Copies this the values from another TaskDescription.
+ * @hide
+ */
+ public void copyFrom(TaskDescription other) {
+ mLabel = other.mLabel;
+ mIcon = other.mIcon;
+ mIconFilename = other.mIconFilename;
+ mColorPrimary = other.mColorPrimary;
+ mColorBackground = other.mColorBackground;
}
private TaskDescription(Parcel source) {
@@ -957,6 +983,18 @@ public class ActivityManager {
}
/**
+ * Sets the background color for this task description.
+ * @hide
+ */
+ public void setBackgroundColor(int backgroundColor) {
+ // Ensure that the given color is valid
+ if ((backgroundColor != 0) && (Color.alpha(backgroundColor) != 255)) {
+ throw new RuntimeException("A TaskDescription's background color should be opaque");
+ }
+ mColorBackground = backgroundColor;
+ }
+
+ /**
* Sets the icon for this task description.
* @hide
*/
@@ -1005,9 +1043,10 @@ public class ActivityManager {
public static Bitmap loadTaskDescriptionIcon(String iconFilename, int userId) {
if (iconFilename != null) {
try {
- return ActivityManagerNative.getDefault().
- getTaskDescriptionIcon(iconFilename, userId);
+ return ActivityManagerNative.getDefault().getTaskDescriptionIcon(iconFilename,
+ userId);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return null;
@@ -1020,13 +1059,26 @@ public class ActivityManager {
return mColorPrimary;
}
+ /**
+ * @return The background color.
+ * @hide
+ */
+ public int getBackgroundColor() {
+ return mColorBackground;
+ }
+
/** @hide */
public void saveToXml(XmlSerializer out) throws IOException {
if (mLabel != null) {
out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, mLabel);
}
if (mColorPrimary != 0) {
- out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(mColorPrimary));
+ out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY,
+ Integer.toHexString(mColorPrimary));
+ }
+ if (mColorBackground != 0) {
+ out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND,
+ Integer.toHexString(mColorBackground));
}
if (mIconFilename != null) {
out.attribute(null, ATTR_TASKDESCRIPTIONICONFILENAME, mIconFilename);
@@ -1037,8 +1089,10 @@ public class ActivityManager {
public void restoreFromXml(String attrName, String attrValue) {
if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
setLabel(attrValue);
- } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
+ } else if (ATTR_TASKDESCRIPTIONCOLOR_PRIMARY.equals(attrName)) {
setPrimaryColor((int) Long.parseLong(attrValue, 16));
+ } else if (ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND.equals(attrName)) {
+ setBackgroundColor((int) Long.parseLong(attrValue, 16));
} else if (ATTR_TASKDESCRIPTIONICONFILENAME.equals(attrName)) {
setIconFilename(attrValue);
}
@@ -1064,6 +1118,7 @@ public class ActivityManager {
mIcon.writeToParcel(dest, 0);
}
dest.writeInt(mColorPrimary);
+ dest.writeInt(mColorBackground);
if (mIconFilename == null) {
dest.writeInt(0);
} else {
@@ -1076,6 +1131,7 @@ public class ActivityManager {
mLabel = source.readInt() > 0 ? source.readString() : null;
mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
mColorPrimary = source.readInt();
+ mColorBackground = source.readInt();
mIconFilename = source.readInt() > 0 ? source.readString() : null;
}
@@ -1092,7 +1148,8 @@ public class ActivityManager {
@Override
public String toString() {
return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
- " colorPrimary: " + mColorPrimary;
+ " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
+ " colorBackground: " + mColorBackground;
}
}
@@ -1370,8 +1427,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
flags, UserHandle.myUserId());
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1396,8 +1452,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
flags, userId);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1532,8 +1587,7 @@ public class ActivityManager {
try {
appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName());
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
int numAppTasks = appTasks.size();
for (int i = 0; i < numAppTasks; i++) {
@@ -1558,7 +1612,7 @@ public class ActivityManager {
try {
mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize();
} catch (RemoteException e) {
- throw new IllegalStateException("System dead?", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1624,7 +1678,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().addAppTask(activity.getActivityToken(),
intent, description, thumbnail);
} catch (RemoteException e) {
- throw new IllegalStateException("System dead?", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1666,8 +1720,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1683,8 +1736,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().removeTask(taskId);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1843,8 +1895,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getTaskThumbnail(id);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1853,8 +1904,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().isInHomeStack(taskId);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1903,7 +1953,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags, options);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
+ throw e.rethrowFromSystemServer();
}
}
@@ -2089,8 +2139,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault()
.getServices(maxNum, 0);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2105,8 +2154,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault()
.getRunningServiceControlPanel(service);
} catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2210,6 +2258,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().getMemoryInfo(outInfo);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2328,7 +2377,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().clearApplicationUserData(packageName,
observer, UserHandle.myUserId());
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2362,8 +2411,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().getGrantedUriPermissions(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
- Log.e(TAG, "Couldn't get granted URI permissions for :" + packageName, e);
- return ParceledListSlice.emptyList();
+ throw e.rethrowFromSystemServer();
}
}
@@ -2381,7 +2429,7 @@ public class ActivityManager {
ActivityManagerNative.getDefault().clearGrantedUriPermissions(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
- Log.e(TAG, "Couldn't clear granted URI permissions for :" + packageName, e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2501,7 +2549,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getProcessesInErrorState();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2815,7 +2863,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getRunningExternalApplications();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2832,7 +2880,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().setProcessMemoryTrimLevel(process, userId,
level);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2850,7 +2898,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getRunningAppProcesses();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2869,7 +2917,7 @@ public class ActivityManager {
mContext.getOpPackageName());
return RunningAppProcessInfo.procStateToImportance(procState);
} catch (RemoteException e) {
- return RunningAppProcessInfo.IMPORTANCE_GONE;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2888,6 +2936,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().getMyMemoryState(outState);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2906,7 +2955,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getProcessMemoryInfo(pids);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2940,6 +2989,7 @@ public class ActivityManager {
ActivityManagerNative.getDefault().killBackgroundProcesses(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2956,7 +3006,7 @@ public class ActivityManager {
ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
UserHandle.getUserId(uid), reason);
} catch (RemoteException e) {
- Log.e(TAG, "Couldn't kill uid:" + uid, e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2983,6 +3033,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().forceStopPackage(packageName, userId);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -3001,8 +3052,8 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -3091,8 +3142,8 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().isUserAMonkey();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -3167,10 +3218,8 @@ public class ActivityManager {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
- // Should never happen, but if it does... deny!
- Slog.e(TAG, "PackageManager is dead?!?", e);
+ throw e.rethrowFromSystemServer();
}
- return PackageManager.PERMISSION_DENIED;
}
/** @hide */
@@ -3179,10 +3228,8 @@ public class ActivityManager {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
- // Should never happen, but if it does... deny!
- Slog.e(TAG, "PackageManager is dead?!?", e);
+ throw e.rethrowFromSystemServer();
}
- return PackageManager.PERMISSION_DENIED;
}
/**
@@ -3218,7 +3265,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().handleIncomingUser(callingPid,
callingUid, userId, allowAll, requireFull, name, callerPackage);
} catch (RemoteException e) {
- throw new SecurityException("Failed calling activity manager", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3233,7 +3280,7 @@ public class ActivityManager {
ui = ActivityManagerNative.getDefault().getCurrentUser();
return ui != null ? ui.id : 0;
} catch (RemoteException e) {
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3245,7 +3292,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().switchUser(userid);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3269,7 +3316,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3279,7 +3326,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().isUserRunning(userId,
ActivityManager.FLAG_AND_LOCKED);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3289,7 +3336,7 @@ public class ActivityManager {
return ActivityManagerNative.getDefault().isUserRunning(userId,
ActivityManager.FLAG_AND_UNLOCKED);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3374,6 +3421,7 @@ public class ActivityManager {
ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize,
mContext.getPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -3392,6 +3440,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -3402,6 +3451,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().startLockTaskMode(taskId);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -3412,6 +3462,7 @@ public class ActivityManager {
try {
ActivityManagerNative.getDefault().stopLockTaskMode();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -3438,7 +3489,7 @@ public class ActivityManager {
try {
return ActivityManagerNative.getDefault().getLockTaskModeState();
} catch (RemoteException e) {
- return ActivityManager.LOCK_TASK_MODE_NONE;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3461,7 +3512,7 @@ public class ActivityManager {
try {
mAppTaskImpl.finishAndRemoveTask();
} catch (RemoteException e) {
- Slog.e(TAG, "Invalid AppTask", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3474,8 +3525,7 @@ public class ActivityManager {
try {
return mAppTaskImpl.getTaskInfo();
} catch (RemoteException e) {
- Slog.e(TAG, "Invalid AppTask", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3489,7 +3539,7 @@ public class ActivityManager {
try {
mAppTaskImpl.moveToFront();
} catch (RemoteException e) {
- Slog.e(TAG, "Invalid AppTask", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3531,7 +3581,7 @@ public class ActivityManager {
try {
mAppTaskImpl.setExcludeFromRecents(exclude);
} catch (RemoteException e) {
- Slog.e(TAG, "Invalid AppTask", e);
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 4fa654f0db5a..7310d679268c 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -29,6 +29,31 @@ import com.android.internal.app.IVoiceInteractor;
* @hide Only for use within the system server.
*/
public abstract class ActivityManagerInternal {
+
+ /**
+ * Type for {@link #notifyAppTransitionStarting}: The transition was started because we had
+ * the surface saved.
+ */
+ public static final int APP_TRANSITION_SAVED_SURFACE = 0;
+
+ /**
+ * Type for {@link #notifyAppTransitionStarting}: The transition was started because we drew
+ * the starting window.
+ */
+ public static final int APP_TRANSITION_STARTING_WINDOW = 1;
+
+ /**
+ * Type for {@link #notifyAppTransitionStarting}: The transition was started because we all
+ * app windows were drawn
+ */
+ public static final int APP_TRANSITION_WINDOWS_DRAWN = 2;
+
+ /**
+ * Type for {@link #notifyAppTransitionStarting}: The transition was started because of a
+ * timeout.
+ */
+ public static final int APP_TRANSITION_TIMEOUT = 3;
+
// Called by the power manager.
public abstract void onWakefulnessChanged(int wakefulness);
@@ -48,6 +73,7 @@ public abstract class ActivityManagerInternal {
* with underlying activities.
*/
public static abstract class SleepToken {
+
/**
* Releases the sleep token.
*/
@@ -56,6 +82,7 @@ public abstract class ActivityManagerInternal {
/**
* Returns home activity for the specified user.
+ *
* @param userId ID of the user or {@link android.os.UserHandle#USER_ALL}
*/
public abstract ComponentName getHomeActivityForUser(int userId);
@@ -72,4 +99,19 @@ public abstract class ActivityManagerInternal {
public abstract void onLocalVoiceInteractionStarted(IBinder callingActivity,
IVoiceInteractionSession mSession,
IVoiceInteractor mInteractor);
+
+ /**
+ * Callback for window manager to let activity manager know that the starting window has been
+ * drawn
+ */
+ public abstract void notifyStartingWindowDrawn();
+
+ /**
+ * Callback for window manager to let activity manager know that we are finally starting the
+ * app transition;
+ *
+ * @param reason The reason why the app transition started. Must be one of the APP_TRANSITION_*
+ * values.
+ */
+ public abstract void notifyAppTransitionStarting(int reason);
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1954774e1177..a1f82dea9542 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1532,6 +1532,22 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case SET_LENIENT_BACKGROUND_CHECK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ boolean enabled = data.readInt() != 0;
+ setLenientBackgroundCheck(enabled);
+ reply.writeNoException();
+ return true;
+ }
+
+ case GET_MEMORY_TRIM_LEVEL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int level = getMemoryTrimLevel();
+ reply.writeNoException();
+ reply.writeInt(level);
+ return true;
+ }
+
case ENTER_SAFE_MODE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
enterSafeMode();
@@ -2882,6 +2898,18 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(isForeground ? 1 : 0);
return true;
}
+ case NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ reply.writeNoException();
+ return true;
+ }
+ case REMOVE_STACK: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int stackId = data.readInt();
+ removeStack(stackId);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -4843,6 +4871,29 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+ public void setLenientBackgroundCheck(boolean enabled) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(enabled ? 1 : 0);
+ mRemote.transact(SET_LENIENT_BACKGROUND_CHECK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+ public int getMemoryTrimLevel() throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_MEMORY_TRIM_LEVEL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int level = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return level;
+ }
public void enterSafeMode() throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6732,5 +6783,27 @@ class ActivityManagerProxy implements IActivityManager
return isForeground;
};
+ @Override
+ public void notifyPinnedStackAnimationEnded() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION, data, reply, 0);
+ data.recycle();
+ reply.recycle();
+ };
+
+ @Override
+ public void removeStack(int stackId) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(stackId);
+ mRemote.transact(REMOVE_STACK, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 04883a961286..f2a8ea5eb148 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -75,6 +75,7 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.provider.Settings;
import android.security.NetworkSecurityPolicy;
@@ -977,18 +978,19 @@ public final class ActivityThread {
@Override
public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
- boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) {
+ boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+ boolean dumpUnreachable, String[] args) {
FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new FastPrintWriter(fout);
try {
- dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly);
+ dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable);
} finally {
pw.flush();
}
}
private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
- boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly) {
+ boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -1102,6 +1104,16 @@ public final class ActivityThread {
pw.println(" Asset Allocations");
pw.print(assetAlloc);
}
+
+ // Unreachable native memory
+ if (dumpUnreachable) {
+ boolean showContents = ((mBoundApplication != null)
+ && ((mBoundApplication.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0))
+ || android.os.Build.IS_DEBUGGABLE;
+ pw.println(" ");
+ pw.println(" Unreachable memory");
+ pw.print(Debug.getUnreachableMemory(100, showContents));
+ }
}
@Override
@@ -1693,7 +1705,7 @@ public final class ActivityThread {
am.activityIdle(a.token, a.createdConfig, stopProfiling);
a.createdConfig = null;
} catch (RemoteException ex) {
- // Ignore
+ throw ex.rethrowFromSystemServer();
}
}
prev = a;
@@ -1833,7 +1845,7 @@ public final class ActivityThread {
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId);
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
if (ai != null) {
@@ -2241,8 +2253,8 @@ public final class ActivityThread {
memInfo.getTotalSwappablePss(),
memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
- memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOut() :
- memInfo.getTotalSwappedOutPss(),
+ memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
+ memInfo.getTotalSwappedOut(),
nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
nativeFree+dalvikFree);
} else {
@@ -2592,6 +2604,7 @@ public final class ActivityThread {
try {
displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
ContextImpl appContext = ContextImpl.createActivityContext(
@@ -2697,7 +2710,7 @@ public final class ActivityThread {
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
- // Ignore
+ throw ex.rethrowFromSystemServer();
}
}
}
@@ -2726,6 +2739,7 @@ public final class ActivityThread {
ActivityManagerNative.getDefault().reportSizeConfigurations(r.token,
horizontal.copyKeys(), vertical.copyKeys(), smallest.copyKeys());
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -2802,6 +2816,7 @@ public final class ActivityThread {
try {
mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content, referrer);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2838,6 +2853,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().backgroundResourcesReleased(token);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2992,8 +3008,7 @@ public final class ActivityThread {
return;
}
} catch (RemoteException e) {
- Slog.e(TAG, "Can't reach package manager", e);
- return;
+ throw e.rethrowFromSystemServer();
}
// no longer idle; we have backup work to do
@@ -3054,7 +3069,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);
} catch (RemoteException e) {
- // nothing to do.
+ throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
throw new RuntimeException("Unable to create BackupAgent "
@@ -3116,7 +3131,7 @@ public final class ActivityThread {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
- // nothing to do.
+ throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
@@ -3147,6 +3162,7 @@ public final class ActivityThread {
}
ensureJitEnabled();
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
@@ -3174,6 +3190,7 @@ public final class ActivityThread {
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
@@ -3255,7 +3272,7 @@ public final class ActivityThread {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
- // nothing to do.
+ throw e.rethrowFromSystemServer();
}
ensureJitEnabled();
} catch (Exception e) {
@@ -3286,9 +3303,7 @@ public final class ActivityThread {
ActivityManagerNative.getDefault().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {
- // nothing to do.
- Slog.i(TAG, "handleStopService: unable to execute serviceDoneExecuting for "
- + token, e);
+ throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
@@ -3398,6 +3413,7 @@ public final class ActivityThread {
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
@@ -3481,6 +3497,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().activityResumed(token);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -3492,6 +3509,7 @@ public final class ActivityThread {
.finishActivity(token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
}
@@ -3577,6 +3595,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
@@ -3670,6 +3689,13 @@ public final class ActivityThread {
ActivityManagerNative.getDefault().activityStopped(
activity.token, state, persistentState, description);
} catch (RemoteException ex) {
+ if (ex instanceof TransactionTooLargeException
+ && "com.google.android.gms".equals(activity.packageInfo.getPackageName())) {
+ Log.d(TAG, "STAHP SENDING SO MUCH DATA KTHX: " + ex);
+ return;
+ }
+
+ throw ex.rethrowFromSystemServer();
}
}
}
@@ -3747,7 +3773,7 @@ public final class ActivityThread {
if (!keepShown) {
try {
// Now we are idle.
- r.activity.performStop();
+ r.activity.performStop(false /*preserveWindow*/);
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -3888,7 +3914,7 @@ public final class ActivityThread {
if (!r.stopped && !r.isPreHoneycomb()) {
try {
// Now we are idle.
- r.activity.performStop();
+ r.activity.performStop(false /*preserveWindow*/);
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -3909,6 +3935,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().activitySlept(r.token);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
} else {
if (r.stopped && r.activity.mVisibleFromServer) {
@@ -4058,7 +4085,7 @@ public final class ActivityThread {
}
if (!r.stopped) {
try {
- r.activity.performStop();
+ r.activity.performStop(r.mPreserveWindow);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
@@ -4175,7 +4202,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().activityDestroyed(token);
} catch (RemoteException ex) {
- // If the system process has died, it's game over for everyone.
+ throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
@@ -4216,7 +4243,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().activityRelaunched(token);
} catch (RemoteException e) {
- e.printStackTrace();
+ throw e.rethrowFromSystemServer();
}
}
break;
@@ -4337,7 +4364,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
} catch (RemoteException e) {
- // If the system process has died, it's game over for everyone.
+ throw e.rethrowFromSystemServer();
}
}
return;
@@ -4363,7 +4390,7 @@ public final class ActivityThread {
WindowManagerGlobal.getWindowSession().prepareToReplaceChildren(r.token);
}
} catch (RemoteException e) {
- // If the system process has died, it's game over for everyone.
+ throw e.rethrowFromSystemServer();
}
@@ -4408,7 +4435,7 @@ public final class ActivityThread {
r.window.reportActivityRelaunched();
}
} catch (RemoteException e) {
- // If the system process has died, it's game over for everyone.
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -4688,6 +4715,7 @@ public final class ActivityThread {
try {
ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -4770,10 +4798,16 @@ public final class ActivityThread {
RenderScriptCacheDir.setupDiskCache(cacheDir);
}
} catch (RemoteException e) {
- // Ignore
+ throw e.rethrowFromSystemServer();
}
}
+ // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
+ private static File getPrimaryProfileFile(String packageName) {
+ return new File("/data/misc/profiles/cur/" + UserHandle.myUserId() +
+ "/" + packageName + "/primary.prof");
+ }
+
private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
return;
@@ -4793,10 +4827,7 @@ public final class ActivityThread {
return;
}
- // Add an extension to the file name to better reveal its intended use.
- // Keep in sync with BackgroundDexOptService.
- final String profileExtension = ".prof";
- final File profileFile = new File(cacheDir, loadedApk.mPackageName + profileExtension);
+ final File profileFile = getPrimaryProfileFile(loadedApk.mPackageName);
if (!profileFile.exists()) {
FileDescriptor fd = null;
try {
@@ -4805,7 +4836,7 @@ public final class ActivityThread {
Os.fchmod(fd, permissions);
Os.fchown(fd, appInfo.uid, appInfo.uid);
} catch (ErrnoException e) {
- Log.w(TAG, "Unable to create jit profile file " + profileFile, e);
+ Log.v(TAG, "Unable to create jit profile file " + profileFile, e);
try {
Os.unlink(profileFile.getAbsolutePath());
} catch (ErrnoException unlinkErr) {
@@ -4959,6 +4990,7 @@ public final class ActivityThread {
try {
mgr.showWaitingForDebugger(mAppThread, true);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
Debug.waitForDebugger();
@@ -4966,6 +4998,7 @@ public final class ActivityThread {
try {
mgr.showWaitingForDebugger(mAppThread, false);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
} else {
@@ -4993,7 +5026,9 @@ public final class ActivityThread {
try {
final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
Proxy.setHttpProxySystemProperty(proxyInfo);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
// Instrumentation info affects the class loader, so load it before
@@ -5157,6 +5192,7 @@ public final class ActivityThread {
try {
am.finishInstrumentation(mAppThread, resultCode, results);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -5186,6 +5222,7 @@ public final class ActivityThread {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -5207,6 +5244,7 @@ public final class ActivityThread {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -5494,6 +5532,7 @@ public final class ActivityThread {
ActivityManagerNative.getDefault()
.appNotRespondingViaProvider(prc.holder.connection);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -5673,7 +5712,7 @@ public final class ActivityThread {
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
- // Ignore
+ throw ex.rethrowFromSystemServer();
}
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@@ -5692,6 +5731,7 @@ public final class ActivityThread {
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index af840d0760e4..198bfb0a414b 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -933,6 +933,17 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
return -1;
}
+ protected void setTransitioningViewsVisiblity(int visiblity, boolean invalidate) {
+ final int numElements = mTransitioningViews == null ? 0 : mTransitioningViews.size();
+ for (int i = 0; i < numElements; i++) {
+ final View view = mTransitioningViews.get(i);
+ view.setTransitionVisibility(visiblity);
+ if (invalidate) {
+ view.invalidate();
+ }
+ }
+ }
+
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f0453e9c45cc..9d1dfdd24a88 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1236,8 +1236,8 @@ public class AppOpsManager {
try {
return mService.getPackagesForOps(ops);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -1252,8 +1252,8 @@ public class AppOpsManager {
try {
return mService.getOpsForPackage(uid, packageName, ops);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/** @hide */
@@ -1261,6 +1261,16 @@ public class AppOpsManager {
try {
mService.setUidMode(code, uid, mode);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void setUserRestriction(int code, boolean restricted, IBinder token) {
+ try {
+ mService.setUserRestriction(code, restricted, token, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1269,6 +1279,7 @@ public class AppOpsManager {
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1289,6 +1300,7 @@ public class AppOpsManager {
final int uid = Binder.getCallingUid();
mService.setAudioRestriction(code, usage, uid, mode, exceptionPackages);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1297,6 +1309,7 @@ public class AppOpsManager {
try {
mService.resetAllModes(UserHandle.myUserId(), null);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1353,6 +1366,7 @@ public class AppOpsManager {
try {
mService.startWatchingMode(op, packageName, cb);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1368,6 +1382,7 @@ public class AppOpsManager {
try {
mService.stopWatchingMode(cb);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1532,8 +1547,8 @@ public class AppOpsManager {
}
return mode;
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_IGNORED;
}
/**
@@ -1545,8 +1560,8 @@ public class AppOpsManager {
try {
return mService.checkOperation(op, uid, packageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_ERRORED;
}
/**
@@ -1562,7 +1577,7 @@ public class AppOpsManager {
"Package " + packageName + " does not belong to " + uid);
}
} catch (RemoteException e) {
- throw new SecurityException("Unable to verify package ownership", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1578,8 +1593,8 @@ public class AppOpsManager {
}
return mode;
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_IGNORED;
}
/**
@@ -1591,8 +1606,8 @@ public class AppOpsManager {
try {
return mService.checkAudioOperation(op, stream, uid, packageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_ERRORED;
}
/**
@@ -1618,8 +1633,8 @@ public class AppOpsManager {
}
return mode;
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_IGNORED;
}
/**
@@ -1661,8 +1676,8 @@ public class AppOpsManager {
return mService.noteProxyOperation(op, mContext.getOpPackageName(),
Binder.getCallingUid(), proxiedPackageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_ERRORED;
}
/**
@@ -1674,8 +1689,8 @@ public class AppOpsManager {
try {
return mService.noteOperation(op, uid, packageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_ERRORED;
}
/** @hide */
@@ -1692,7 +1707,7 @@ public class AppOpsManager {
try {
sToken = service.getToken(new Binder());
} catch (RemoteException e) {
- // System is dead, whatevs.
+ throw e.rethrowFromSystemServer();
}
return sToken;
}
@@ -1723,8 +1738,8 @@ public class AppOpsManager {
}
return mode;
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_IGNORED;
}
/**
@@ -1736,8 +1751,8 @@ public class AppOpsManager {
try {
return mService.startOperation(getToken(mService), op, uid, packageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return MODE_ERRORED;
}
/** @hide */
@@ -1756,6 +1771,7 @@ public class AppOpsManager {
try {
mService.finishOperation(getToken(mService), op, uid, packageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 7d0d1b4f5ee5..b20c09125733 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -20,16 +20,14 @@ import android.os.Trace;
import android.util.ArrayMap;
import dalvik.system.PathClassLoader;
-class ApplicationLoaders
-{
- public static ApplicationLoaders getDefault()
- {
+class ApplicationLoaders {
+ public static ApplicationLoaders getDefault() {
return gApplicationLoaders;
}
- public ClassLoader getClassLoader(String zip, boolean isBundled, String librarySearchPath,
- String libraryPermittedPath, ClassLoader parent)
- {
+ public ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
+ String librarySearchPath, String libraryPermittedPath,
+ ClassLoader parent) {
/*
* This is the parent we use if they pass "null" in. In theory
* this should be the "system" class loader; in practice we
@@ -55,11 +53,22 @@ class ApplicationLoaders
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
+
PathClassLoader pathClassloader =
- new PathClassLoader(zip, isBundled, librarySearchPath,
- libraryPermittedPath, parent);
+ new PathClassLoader(zip, librarySearchPath, parent);
+
+ String errorMessage = createClassloaderNamespace(pathClassloader,
+ targetSdkVersion,
+ librarySearchPath,
+ libraryPermittedPath,
+ isBundled);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ if (errorMessage != null) {
+ throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " +
+ pathClassloader + ": " + errorMessage);
+ }
+
mLoaders.put(zip, pathClassloader);
return pathClassloader;
}
@@ -71,6 +80,12 @@ class ApplicationLoaders
}
}
+ private static native String createClassloaderNamespace(ClassLoader classLoader,
+ int targetSdkVersion,
+ String librarySearchPath,
+ String libraryPermittedPath,
+ boolean isShared);
+
private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>();
private static final ApplicationLoaders gApplicationLoaders
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c071162ca5b9..4d466d34a79c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.XmlRes;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
@@ -142,7 +143,7 @@ public class ApplicationPackageManager extends PackageManager {
return pi;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(packageName);
@@ -153,7 +154,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.currentToCanonicalPackageNames(names);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -162,7 +163,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.canonicalToCurrentPackageNames(names);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -226,7 +227,7 @@ public class ApplicationPackageManager extends PackageManager {
return gids;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(packageName);
@@ -251,7 +252,7 @@ public class ApplicationPackageManager extends PackageManager {
return uid;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(packageName);
@@ -266,7 +267,7 @@ public class ApplicationPackageManager extends PackageManager {
return pi;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(name);
@@ -281,7 +282,7 @@ public class ApplicationPackageManager extends PackageManager {
return pi;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(group);
@@ -296,7 +297,7 @@ public class ApplicationPackageManager extends PackageManager {
return pgi;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(name);
@@ -307,7 +308,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getAllPermissionGroups(flags);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -329,7 +330,7 @@ public class ApplicationPackageManager extends PackageManager {
return maybeAdjustApplicationInfo(ai);
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(packageName);
@@ -369,7 +370,7 @@ public class ApplicationPackageManager extends PackageManager {
return ai;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(className.toString());
@@ -384,7 +385,7 @@ public class ApplicationPackageManager extends PackageManager {
return ai;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(className.toString());
@@ -399,7 +400,7 @@ public class ApplicationPackageManager extends PackageManager {
return si;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(className.toString());
@@ -414,7 +415,7 @@ public class ApplicationPackageManager extends PackageManager {
return pi;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(className.toString());
@@ -425,7 +426,17 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getSystemSharedLibraryNames();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ @Override
+ public @Nullable String getServicesSystemSharedLibraryPackageName() {
+ try {
+ return mPM.getServicesSystemSharedLibraryPackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -434,16 +445,21 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getSystemAvailableFeatures();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@Override
public boolean hasSystemFeature(String name) {
+ return hasSystemFeature(name, 0);
+ }
+
+ @Override
+ public boolean hasSystemFeature(String name, int version) {
try {
- return mPM.hasSystemFeature(name);
+ return mPM.hasSystemFeature(name, version);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -452,7 +468,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.checkPermission(permName, pkgName, mContext.getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -461,7 +477,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.isPermissionRevokedByPolicy(permName, pkgName, mContext.getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -475,7 +491,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPermissionsControllerPackageName = mPM.getPermissionControllerPackageName();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
return mPermissionsControllerPackageName;
@@ -487,7 +503,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.addPermission(info);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -496,7 +512,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.addPermissionAsync(info);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -505,7 +521,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.removePermission(name);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -515,7 +531,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -525,7 +541,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -534,7 +550,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getPermissionFlags(permissionName, packageName, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -545,7 +561,7 @@ public class ApplicationPackageManager extends PackageManager {
mPM.updatePermissionFlags(permissionName, packageName, flagMask,
flagValues, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -555,7 +571,7 @@ public class ApplicationPackageManager extends PackageManager {
return mPM.shouldShowRequestPermissionRationale(permission,
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -564,7 +580,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.checkSignatures(pkg1, pkg2);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -573,7 +589,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.checkUidSignatures(uid1, uid2);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -582,7 +598,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getPackagesForUid(uid);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -591,7 +607,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getNameForUid(uid);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -604,7 +620,7 @@ public class ApplicationPackageManager extends PackageManager {
return uid;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
}
@@ -622,7 +638,7 @@ public class ApplicationPackageManager extends PackageManager {
ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
return slice.getList();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -636,7 +652,7 @@ public class ApplicationPackageManager extends PackageManager {
permissions, flags, userId);
return slice.getList();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -648,7 +664,7 @@ public class ApplicationPackageManager extends PackageManager {
ParceledListSlice<ApplicationInfo> slice = mPM.getInstalledApplications(flags, userId);
return slice.getList();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -664,7 +680,7 @@ public class ApplicationPackageManager extends PackageManager {
}
return Collections.emptyList();
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -679,7 +695,7 @@ public class ApplicationPackageManager extends PackageManager {
}
return null;
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -689,9 +705,8 @@ public class ApplicationPackageManager extends PackageManager {
return mPM.isEphemeralApplication(
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
- Log.e(TAG, "System server is dead", e);
+ throw e.rethrowFromSystemServer();
}
- return false;
}
@Override
@@ -708,11 +723,12 @@ public class ApplicationPackageManager extends PackageManager {
mContext.getPackageName(), mContext.getUserId());
if (cookie != null) {
return cookie;
+ } else {
+ return EmptyArray.BYTE;
}
} catch (RemoteException e) {
- Log.e(TAG, "System server is dead", e);
+ throw e.rethrowFromSystemServer();
}
- return EmptyArray.BYTE;
}
@Override
@@ -721,9 +737,8 @@ public class ApplicationPackageManager extends PackageManager {
return mPM.setEphemeralApplicationCookie(
mContext.getPackageName(), cookie, mContext.getUserId());
} catch (RemoteException e) {
- Log.e(TAG, "System server is dead", e);
+ throw e.rethrowFromSystemServer();
}
- return false;
}
@Override
@@ -740,7 +755,7 @@ public class ApplicationPackageManager extends PackageManager {
flags,
userId);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -761,7 +776,7 @@ public class ApplicationPackageManager extends PackageManager {
flags,
userId);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -793,7 +808,7 @@ public class ApplicationPackageManager extends PackageManager {
specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
flags, mContext.getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -809,7 +824,7 @@ public class ApplicationPackageManager extends PackageManager {
flags,
userId);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -827,7 +842,7 @@ public class ApplicationPackageManager extends PackageManager {
flags,
mContext.getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -840,7 +855,7 @@ public class ApplicationPackageManager extends PackageManager {
flags,
userId);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -856,7 +871,7 @@ public class ApplicationPackageManager extends PackageManager {
return mPM.queryIntentContentProviders(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -876,7 +891,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.resolveContentProvider(name, flags, userId);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -888,7 +903,7 @@ public class ApplicationPackageManager extends PackageManager {
= mPM.queryContentProviders(processName, uid, flags);
return slice != null ? slice.getList() : null;
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -903,7 +918,7 @@ public class ApplicationPackageManager extends PackageManager {
return ii;
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(className.toString());
@@ -915,7 +930,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.queryInstrumentation(targetPackage, flags);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1182,7 +1197,7 @@ public class ApplicationPackageManager extends PackageManager {
return getResourcesForApplication(ai);
}
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
}
@@ -1197,7 +1212,7 @@ public class ApplicationPackageManager extends PackageManager {
}
return mCachedSafeMode != 0;
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1213,7 +1228,7 @@ public class ApplicationPackageManager extends PackageManager {
mPM.addOnPermissionsChangeListener(delegate);
mPermissionListeners.put(listener, delegate);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1227,7 +1242,7 @@ public class ApplicationPackageManager extends PackageManager {
mPM.removeOnPermissionsChangeListener(delegate);
mPermissionListeners.remove(listener);
} catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1528,7 +1543,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
verificationParams, null, userId);
- } catch (RemoteException ignored) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1547,8 +1563,7 @@ public class ApplicationPackageManager extends PackageManager {
}
return res;
} catch (RemoteException e) {
- // Should never happen!
- throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+ throw e.rethrowFromSystemServer();
}
}
@@ -1557,7 +1572,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.verifyPendingInstall(id, response);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1567,7 +1582,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1576,7 +1591,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.verifyIntentFilter(id, verificationCode, outFailedDomains);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1585,8 +1600,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getIntentVerificationStatus(packageName, userId);
} catch (RemoteException e) {
- // Should never happen!
- return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1595,8 +1609,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.updateIntentVerificationStatus(packageName, status, userId);
} catch (RemoteException e) {
- // Should never happen!
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1605,8 +1618,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getIntentFilterVerifications(packageName);
} catch (RemoteException e) {
- // Should never happen!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1615,8 +1627,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getAllIntentFilters(packageName);
} catch (RemoteException e) {
- // Should never happen!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1625,8 +1636,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getDefaultBrowserPackageName(userId);
} catch (RemoteException e) {
- // Should never happen!
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1635,8 +1645,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.setDefaultBrowserPackageName(packageName, userId);
} catch (RemoteException e) {
- // Should never happen!
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1646,7 +1655,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.setInstallerPackageName(targetPackage, installerPackageName);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1655,9 +1664,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getInstallerPackageName(packageName);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return null;
}
@Override
@@ -1665,7 +1673,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getMoveStatus(moveId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1677,7 +1685,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.registerMoveCallback(delegate);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
mDelegates.add(delegate);
}
@@ -1692,7 +1700,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.unregisterMoveCallback(delegate);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
i.remove();
}
@@ -1714,7 +1722,7 @@ public class ApplicationPackageManager extends PackageManager {
return mPM.movePackage(packageName, volumeUuid);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1744,7 +1752,7 @@ public class ApplicationPackageManager extends PackageManager {
return candidates;
}
- private static boolean isPackageCandidateVolume(
+ private boolean isPackageCandidateVolume(
ContextImpl context, ApplicationInfo app, VolumeInfo vol) {
final boolean forceAllowOnExternal = Settings.Global.getInt(
context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
@@ -1774,6 +1782,15 @@ public class ApplicationPackageManager extends PackageManager {
return app.isInternal();
}
+ // Some apps can't be moved. (e.g. device admins)
+ try {
+ if (mPM.isPackageDeviceAdminOnAnyUser(app.packageName)) {
+ return false;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
// Otherwise we can move to any private volume
return (vol.getType() == VolumeInfo.TYPE_PRIVATE);
}
@@ -1792,7 +1809,7 @@ public class ApplicationPackageManager extends PackageManager {
return mPM.movePrimaryStorage(volumeUuid);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1849,7 +1866,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.deletePackageAsUser(packageName, observer, userId, flags);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1859,7 +1876,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.clearApplicationUserData(packageName, observer, mContext.getUserId());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@Override
@@ -1868,7 +1885,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.deleteApplicationCacheFiles(packageName, observer);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1878,7 +1895,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.freeStorageAndNotify(volumeUuid, idealStorageSize, observer);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1887,18 +1904,27 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.freeStorage(volumeUuid, freeStorageSize, pi);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+ int userId) {
+ try {
+ return mPM.setPackagesSuspendedAsUser(packageNames, suspended, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@Override
- public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ public boolean isPackageSuspendedForUser(String packageName, int userId) {
try {
- return mPM.setPackageSuspendedAsUser(packageName, suspended, userId);
+ return mPM.isPackageSuspendedForUser(packageName, userId);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return false;
}
@Override
@@ -1907,7 +1933,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.getPackageSizeInfo(packageName, userHandle, observer);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@Override
@@ -1915,7 +1941,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.addPackageToPreferred(packageName);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1924,7 +1950,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.removePackageFromPreferred(packageName);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1933,9 +1959,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getPreferredPackages(flags);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return new ArrayList<PackageInfo>();
}
@Override
@@ -1944,7 +1969,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.addPreferredActivity(filter, match, set, activity, mContext.getUserId());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1954,7 +1979,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.addPreferredActivity(filter, match, set, activity, userId);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1964,7 +1989,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.replacePreferredActivity(filter, match, set, activity, mContext.getUserId());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1975,7 +2000,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.replacePreferredActivity(filter, match, set, activity, userId);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1984,7 +2009,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.clearPackagePreferredActivities(packageName);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -1994,9 +2019,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getPreferredActivities(outFilters, outActivities, packageName);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return 0;
}
@Override
@@ -2004,9 +2028,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getHomeActivities(outActivities);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return null;
}
@Override
@@ -2015,7 +2038,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.setComponentEnabledSetting(componentName, newState, flags, mContext.getUserId());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -2024,9 +2047,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getComponentEnabledSetting(componentName, mContext.getUserId());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
}
@Override
@@ -2036,7 +2058,7 @@ public class ApplicationPackageManager extends PackageManager {
mPM.setApplicationEnabledSetting(packageName, newState, flags,
mContext.getUserId(), mContext.getOpPackageName());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -2045,9 +2067,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getApplicationEnabledSetting(packageName, mContext.getUserId());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
}
@Override
@@ -2056,20 +2077,18 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.setApplicationHiddenSettingAsUser(packageName, hidden,
user.getIdentifier());
- } catch (RemoteException re) {
- // Should never happen!
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
@Override
public boolean getApplicationHiddenSettingAsUser(String packageName, UserHandle user) {
try {
return mPM.getApplicationHiddenSettingAsUser(packageName, user.getIdentifier());
- } catch (RemoteException re) {
- // Should never happen!
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/** @hide */
@@ -2077,26 +2096,22 @@ public class ApplicationPackageManager extends PackageManager {
public KeySet getKeySetByAlias(String packageName, String alias) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(alias);
- KeySet ks;
try {
- ks = mPM.getKeySetByAlias(packageName, alias);
+ return mPM.getKeySetByAlias(packageName, alias);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
- return ks;
}
/** @hide */
@Override
public KeySet getSigningKeySet(String packageName) {
Preconditions.checkNotNull(packageName);
- KeySet ks;
try {
- ks = mPM.getSigningKeySet(packageName);
+ return mPM.getSigningKeySet(packageName);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
- return ks;
}
/** @hide */
@@ -2107,7 +2122,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.isPackageSignedByKeySet(packageName, ks);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2119,7 +2134,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.isPackageSignedByKeySetExactly(packageName, ks);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2131,9 +2146,8 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.getVerifierDeviceIdentity();
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -2144,7 +2158,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.isUpgrade();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2156,7 +2170,7 @@ public class ApplicationPackageManager extends PackageManager {
mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(),
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
return mInstaller;
@@ -2168,7 +2182,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.isPackageAvailable(packageName, mContext.getUserId());
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -2182,7 +2196,7 @@ public class ApplicationPackageManager extends PackageManager {
mPM.addCrossProfileIntentFilter(filter, mContext.getOpPackageName(),
sourceUserId, targetUserId, flags);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
@@ -2194,7 +2208,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName());
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 59ecc03d1295..744ddf704161 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -548,11 +548,12 @@ public abstract class ApplicationThreadNative extends Binder
boolean dumpInfo = data.readInt() != 0;
boolean dumpDalvik = data.readInt() != 0;
boolean dumpSummaryOnly = data.readInt() != 0;
+ boolean dumpUnreachable = data.readInt() != 0;
String[] args = data.readStringArray();
if (fd != null) {
try {
dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo,
- dumpDalvik, dumpSummaryOnly, args);
+ dumpDalvik, dumpSummaryOnly, dumpUnreachable, args);
} finally {
try {
fd.close();
@@ -1328,7 +1329,8 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
- boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException {
+ boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+ boolean dumpUnreachable, String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1338,6 +1340,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeInt(dumpInfo ? 1 : 0);
data.writeInt(dumpDalvik ? 1 : 0);
data.writeInt(dumpSummaryOnly ? 1 : 0);
+ data.writeInt(dumpUnreachable ? 1 : 0);
data.writeStringArray(args);
mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index e5fa02b248f4..b7eaf3947a42 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,6 +16,7 @@
package android.app;
+import android.app.NotificationManager.InterruptionFilter;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
@@ -30,7 +31,7 @@ public class AutomaticZenRule implements Parcelable {
private boolean enabled = false;
private String name;
- private int interruptionFilter;
+ private @InterruptionFilter int interruptionFilter;
private Uri conditionId;
private ComponentName owner;
private String id;
@@ -140,9 +141,9 @@ public class AutomaticZenRule implements Parcelable {
/**
* Sets the interruption filter that is applied when this rule is active.
- * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants in NotificationManager.
+ * @param interruptionFilter The do not disturb mode to enter when this rule is active.
*/
- public void setInterruptionFilter(int interruptionFilter) {
+ public void setInterruptionFilter(@InterruptionFilter int interruptionFilter) {
this.interruptionFilter = interruptionFilter;
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index eb4b13e69e9d..4b0dfc7e0a8b 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -470,6 +470,10 @@ final class BackStackRecord extends FragmentTransaction implements
}
if (containerViewId != 0) {
+ if (containerViewId == View.NO_ID) {
+ throw new IllegalArgumentException("Can't add fragment "
+ + fragment + " with tag " + tag + " to container view with no id");
+ }
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index eec503b233e8..47eec8bbfbfd 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -134,7 +134,14 @@ class ContextImpl extends Context {
/**
* Map from package name, to preference name, to cached preferences.
*/
- private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefs;
+ @GuardedBy("ContextImpl.class")
+ private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache;
+
+ /**
+ * Map from preference name to generated path.
+ */
+ @GuardedBy("ContextImpl.class")
+ private ArrayMap<String, File> mSharedPrefsPaths;
final ActivityThread mMainThread;
final LoadedApk mPackageInfo;
@@ -335,7 +342,17 @@ class ContextImpl extends Context {
}
}
- final File file = getSharedPreferencesPath(name);
+ File file;
+ synchronized (ContextImpl.class) {
+ if (mSharedPrefsPaths == null) {
+ mSharedPrefsPaths = new ArrayMap<>();
+ }
+ file = mSharedPrefsPaths.get(name);
+ if (file == null) {
+ file = getSharedPreferencesPath(name);
+ mSharedPrefsPaths.put(name, file);
+ }
+ }
return getSharedPreferences(file, mode);
}
@@ -363,15 +380,15 @@ class ContextImpl extends Context {
}
private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() {
- if (sSharedPrefs == null) {
- sSharedPrefs = new ArrayMap<>();
+ if (sSharedPrefsCache == null) {
+ sSharedPrefsCache = new ArrayMap<>();
}
final String packageName = getPackageName();
- ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
+ ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefsCache.get(packageName);
if (packagePrefs == null) {
packagePrefs = new ArrayMap<>();
- sSharedPrefs.put(packageName, packagePrefs);
+ sSharedPrefsCache.put(packageName, packagePrefs);
}
return packagePrefs;
@@ -443,7 +460,7 @@ class ContextImpl extends Context {
private File getPreferencesDir() {
synchronized (mSync) {
if (mPreferencesDir == null) {
- mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
+ mPreferencesDir = new File(getDataDir(), "shared_prefs");
}
return ensurePrivateDirExists(mPreferencesDir);
}
@@ -492,6 +509,7 @@ class ContextImpl extends Context {
if (!file.exists()) {
try {
Os.mkdir(file.getAbsolutePath(), 0771);
+ Os.chmod(file.getAbsolutePath(), 0771);
} catch (ErrnoException e) {
if (e.errno == OsConstants.EEXIST) {
// We must have raced with someone; that's okay
@@ -507,7 +525,7 @@ class ContextImpl extends Context {
public File getFilesDir() {
synchronized (mSync) {
if (mFilesDir == null) {
- mFilesDir = new File(getDataDirFile(), "files");
+ mFilesDir = new File(getDataDir(), "files");
}
return ensurePrivateDirExists(mFilesDir);
}
@@ -517,7 +535,7 @@ class ContextImpl extends Context {
public File getNoBackupFilesDir() {
synchronized (mSync) {
if (mNoBackupFilesDir == null) {
- mNoBackupFilesDir = new File(getDataDirFile(), "no_backup");
+ mNoBackupFilesDir = new File(getDataDir(), "no_backup");
}
return ensurePrivateDirExists(mNoBackupFilesDir);
}
@@ -569,7 +587,7 @@ class ContextImpl extends Context {
public File getCacheDir() {
synchronized (mSync) {
if (mCacheDir == null) {
- mCacheDir = new File(getDataDirFile(), "cache");
+ mCacheDir = new File(getDataDir(), "cache");
}
return ensurePrivateDirExists(mCacheDir);
}
@@ -579,7 +597,7 @@ class ContextImpl extends Context {
public File getCodeCacheDir() {
synchronized (mSync) {
if (mCodeCacheDir == null) {
- mCodeCacheDir = new File(getDataDirFile(), "code_cache");
+ mCodeCacheDir = new File(getDataDir(), "code_cache");
}
return ensurePrivateDirExists(mCodeCacheDir);
}
@@ -706,7 +724,7 @@ class ContextImpl extends Context {
if ("android".equals(getPackageName())) {
mDatabasesDir = new File("/data/system");
} else {
- mDatabasesDir = new File(getDataDirFile(), "databases");
+ mDatabasesDir = new File(getDataDir(), "databases");
}
}
return ensurePrivateDirExists(mDatabasesDir);
@@ -795,7 +813,7 @@ class ContextImpl extends Context {
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -860,7 +878,7 @@ class ContextImpl extends Context {
}
Instrumentation.checkStartActivityResult(result, null);
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -875,7 +893,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -892,7 +910,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -907,7 +925,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -924,7 +942,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
options, false, false, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -941,7 +959,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -958,7 +976,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, true, false, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1021,7 +1039,7 @@ class ContextImpl extends Context {
initialCode, initialData, initialExtras, receiverPermissions, appOp,
options, true, false, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1034,7 +1052,7 @@ class ContextImpl extends Context {
intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1057,7 +1075,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1108,7 +1126,7 @@ class ContextImpl extends Context {
initialCode, initialData, initialExtras, receiverPermissions,
appOp, options, true, false, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1124,7 +1142,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1160,7 +1178,7 @@ class ContextImpl extends Context {
initialCode, initialData, initialExtras, null,
AppOpsManager.OP_NONE, null, true, true, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1177,7 +1195,7 @@ class ContextImpl extends Context {
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1192,7 +1210,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1207,7 +1225,7 @@ class ContextImpl extends Context {
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1242,7 +1260,7 @@ class ContextImpl extends Context {
initialCode, initialData, initialExtras, null,
AppOpsManager.OP_NONE, null, true, true, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1259,7 +1277,7 @@ class ContextImpl extends Context {
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, user.getIdentifier());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1307,7 +1325,7 @@ class ContextImpl extends Context {
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1319,6 +1337,7 @@ class ContextImpl extends Context {
try {
ActivityManagerNative.getDefault().unregisterReceiver(rd);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
} else {
throw new RuntimeException("Not supported in system context");
@@ -1375,7 +1394,7 @@ class ContextImpl extends Context {
}
return cn;
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1397,7 +1416,7 @@ class ContextImpl extends Context {
}
return res != 0;
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1405,25 +1424,35 @@ class ContextImpl extends Context {
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
- return bindServiceCommon(service, conn, flags, Process.myUserHandle());
+ return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
+ Process.myUserHandle());
}
/** @hide */
@Override
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
- return bindServiceCommon(service, conn, flags, user);
+ return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), user);
}
- private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
- UserHandle user) {
+ /** @hide */
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ if (handler == null) {
+ throw new IllegalArgumentException("handler must not be null.");
+ }
+ return bindServiceCommon(service, conn, flags, handler, user);
+ }
+
+ private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
+ handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
- sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
- mMainThread.getHandler(), flags);
+ sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
@@ -1446,7 +1475,7 @@ class ContextImpl extends Context {
}
return res != 0;
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1461,6 +1490,7 @@ class ContextImpl extends Context {
try {
ActivityManagerNative.getDefault().unbindService(sd);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
} else {
throw new RuntimeException("Not supported in system context");
@@ -1478,7 +1508,7 @@ class ContextImpl extends Context {
className, profileFile, 0, arguments, null, null, getUserId(),
null /* ABI override */);
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1502,7 +1532,7 @@ class ContextImpl extends Context {
return ActivityManagerNative.getDefault().checkPermission(
permission, pid, uid);
} catch (RemoteException e) {
- return PackageManager.PERMISSION_DENIED;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1517,7 +1547,7 @@ class ContextImpl extends Context {
return ActivityManagerNative.getDefault().checkPermissionWithToken(
permission, pid, uid, callerToken);
} catch (RemoteException e) {
- return PackageManager.PERMISSION_DENIED;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1603,6 +1633,7 @@ class ContextImpl extends Context {
mMainThread.getApplicationThread(), toPackage,
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1613,6 +1644,7 @@ class ContextImpl extends Context {
mMainThread.getApplicationThread(),
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1623,7 +1655,7 @@ class ContextImpl extends Context {
ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
resolveUserId(uri), null);
} catch (RemoteException e) {
- return PackageManager.PERMISSION_DENIED;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1635,7 +1667,7 @@ class ContextImpl extends Context {
ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
resolveUserId(uri), callerToken);
} catch (RemoteException e) {
- return PackageManager.PERMISSION_DENIED;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1892,7 +1924,8 @@ class ContextImpl extends Context {
return mDisplayAdjustments;
}
- private File getDataDirFile() {
+ @Override
+ public File getDataDir() {
if (mPackageInfo != null) {
File res = null;
if (isCredentialEncryptedStorage()) {
@@ -1919,7 +1952,7 @@ class ContextImpl extends Context {
public File getDir(String name, int mode) {
checkMode(mode);
name = "app_" + name;
- File file = makeFilename(getDataDirFile(), name);
+ File file = makeFilename(getDataDir(), name);
if (!file.exists()) {
file.mkdir();
setFilePermissionsFromMode(file.getPath(), mode,
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index fe9cc8055262..ddd0ae90fc5c 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -263,6 +263,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
mViewsReadyListener = null;
}
showViews(mTransitioningViews, true);
+ setTransitioningViewsVisiblity(View.VISIBLE, true);
mSharedElements.clear();
mAllSharedElementNames.clear();
mTransitioningViews.clear();
@@ -280,6 +281,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
if (!mIsViewsTransitionStarted) {
mIsViewsTransitionStarted = true;
showViews(mTransitioningViews, true);
+ setTransitioningViewsVisiblity(View.VISIBLE, true);
mTransitioningViews.clear();
viewsTransitionComplete();
}
@@ -506,7 +508,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
if (viewsTransition == null) {
viewsTransitionComplete();
} else {
- viewsTransition.forceVisibility(View.INVISIBLE, true);
final ArrayList<View> transitioningViews = mTransitioningViews;
viewsTransition.addListener(new ContinueTransitionListener() {
@Override
@@ -532,12 +533,15 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
if (transition != null) {
transition.addListener(new ContinueTransitionListener());
+ if (startEnterTransition) {
+ setTransitioningViewsVisiblity(View.INVISIBLE, false);
+ }
TransitionManager.beginDelayedTransition(decorView, transition);
if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
mSharedElements.get(0).invalidate();
- } else if (startEnterTransition && mTransitioningViews != null &&
- !mTransitioningViews.isEmpty()) {
- mTransitioningViews.get(0).invalidate();
+ }
+ if (startEnterTransition) {
+ setTransitioningViewsVisiblity(View.VISIBLE, true);
}
} else {
transitionStarted();
@@ -613,6 +617,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
moveSharedElementsFromOverlay();
if (mTransitioningViews != null) {
showViews(mTransitioningViews, true);
+ setTransitioningViewsVisiblity(View.VISIBLE, true);
}
showViews(mSharedElements, true);
clearState();
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index e93b40ed7210..d54ffa0b23f9 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -48,27 +48,16 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private static final long MAX_WAIT_MS = 1000;
private Bundle mSharedElementBundle;
-
private boolean mExitNotified;
-
private boolean mSharedElementNotified;
-
private Activity mActivity;
-
private boolean mIsBackgroundReady;
-
private boolean mIsCanceled;
-
private Handler mHandler;
-
private ObjectAnimator mBackgroundAnimator;
-
private boolean mIsHidden;
-
private Bundle mExitSharedElementBundle;
-
private boolean mIsExitStarted;
-
private boolean mSharedElementsHidden;
public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
@@ -129,6 +118,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
public void resetViews() {
if (mTransitioningViews != null) {
showViews(mTransitioningViews, true);
+ setTransitioningViewsVisiblity(View.VISIBLE, true);
}
showViews(mSharedElements, true);
mIsHidden = true;
@@ -276,8 +266,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
Transition transition = getExitTransition();
ViewGroup decorView = getDecor();
if (transition != null && decorView != null && mTransitioningViews != null) {
+ setTransitioningViewsVisiblity(View.VISIBLE, false);
TransitionManager.beginDelayedTransition(decorView, transition);
- mTransitioningViews.get(0).invalidate();
+ setTransitioningViewsVisiblity(View.INVISIBLE, true);
} else {
transitionStarted();
}
@@ -325,6 +316,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
viewsTransitionComplete();
if (mIsHidden && transitioningViews != null) {
showViews(transitioningViews, true);
+ setTransitioningViewsVisiblity(View.VISIBLE, true);
}
if (mSharedElementBundle != null) {
delayCancel();
@@ -332,7 +324,6 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
super.onTransitionEnd(transition);
}
});
- viewsTransition.forceVisibility(View.INVISIBLE, false);
}
return viewsTransition;
}
@@ -369,9 +360,15 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
if (transition != null && decorView != null) {
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
+ if (viewsTransition != null) {
+ setTransitioningViewsVisiblity(View.VISIBLE, false);
+ }
TransitionManager.beginDelayedTransition(decorView, transition);
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
+ if (viewsTransition != null) {
+ setTransitioningViewsVisiblity(View.INVISIBLE, true);
+ }
decorView.invalidate();
} else {
transitionStarted();
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 02a898b33dd1..aafb3c638a65 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1033,7 +1033,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
- if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
+ if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null) {
mFragmentManager.performPendingDeferredStart(this);
}
mUserVisibleHint = isVisibleToUser;
@@ -1203,7 +1203,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* }
* </code></pre></p>
*
- * @param permissions The requested permissions.
+ * @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
* reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
* Should be >= 0.
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 4c8761c86b93..78a054b3a717 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Debug;
@@ -960,12 +961,24 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
- container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
+ if (f.mContainerId == View.NO_ID) {
+ throwException(new IllegalArgumentException(
+ "Cannot create fragment "
+ + f
+ + " for a container view with no id"));
+ }
+ container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
+ String resName;
+ try {
+ resName = f.getResources().getResourceName(f.mContainerId);
+ } catch (NotFoundException e) {
+ resName = "unknown";
+ }
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
- + f.getResources().getResourceName(f.mContainerId)
+ + resName
+ ") for fragment " + f));
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b5ca6ee5a343..2cb615103024 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -307,6 +307,8 @@ public interface IActivityManager extends IInterface {
public void setAlwaysFinish(boolean enabled) throws RemoteException;
public void setActivityController(IActivityController watcher)
throws RemoteException;
+ public void setLenientBackgroundCheck(boolean enabled) throws RemoteException;
+ public int getMemoryTrimLevel() throws RemoteException;
public void enterSafeMode() throws RemoteException;
@@ -597,6 +599,10 @@ public interface IActivityManager extends IInterface {
public boolean supportsLocalVoiceInteraction() throws RemoteException;
+ public void notifyPinnedStackAnimationEnded() throws RemoteException;
+
+ public void removeStack(int stackId) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -972,4 +978,8 @@ public interface IActivityManager extends IInterface {
int START_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 363;
int STOP_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 364;
int SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 365;
+ int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366;
+ int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367;
+ int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368;
+ int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index b55da88c8a3e..a3c95916bb98 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -133,7 +133,8 @@ public interface IApplicationThread extends IInterface {
void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
void scheduleTrimMemory(int level) throws RemoteException;
void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo,
- boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException;
+ boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable,
+ String[] args) throws RemoteException;
void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
void unstableProviderDied(IBinder provider) throws RemoteException;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 40e58af57204..8be00aa50ca3 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -46,16 +46,15 @@ interface INotificationManager
void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled);
boolean areNotificationsEnabledForPackage(String pkg, int uid);
-
- ParceledListSlice getTopics(String pkg, int uid);
- void setVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
- int getVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
- void setPriority(String pkg, int uid, in Notification.Topic topic, int priority);
- int getPriority(String pkg, int uid, in Notification.Topic topic);
- void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
- int getImportance(String pkg, int uid, in Notification.Topic topic);
- boolean doesAppUseTopics(String pkg, int uid);
- boolean hasBannedTopics(String pkg, int uid);
+ boolean areNotificationsEnabled(String pkg);
+
+ void setVisibilityOverride(String pkg, int uid, int visibility);
+ int getVisibilityOverride(String pkg, int uid);
+ void setPriority(String pkg, int uid, int priority);
+ int getPriority(String pkg, int uid);
+ void setImportance(String pkg, int uid, int importance);
+ int getImportance(String pkg, int uid);
+ int getPackageImportance(String pkg);
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index fa1123423e35..643255822cb9 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -30,4 +30,9 @@ oneway interface ITaskStackListener {
* brought to the front or a new Intent is delivered to it.
*/
void onPinnedActivityRestartAttempt();
+
+ /**
+ * Called whenever the pinned stack is done animating a resize.
+ */
+ void onPinnedStackAnimationEnded();
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 04493cb0fc58..1143c6aec7a6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -27,7 +27,7 @@ import android.content.ComponentName;
interface IWallpaperManager {
/**
- * Set the wallpaper.
+ * Set the wallpaper for the current user.
*
* If 'extras' is non-null, on successful return it will contain:
* EXTRA_SET_WALLPAPER_ID : integer ID that the new wallpaper will have
@@ -56,10 +56,10 @@ interface IWallpaperManager {
void setWallpaperComponent(in ComponentName name);
/**
- * Get the system wallpaper.
+ * Get the wallpaper for a given user.
*/
- ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
- out Bundle outParams);
+ ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, int which,
+ out Bundle outParams, int userId);
/**
* If the current system wallpaper is a live wallpaper component, return the
@@ -71,7 +71,7 @@ interface IWallpaperManager {
/**
* Clear the system wallpaper.
*/
- void clearWallpaper(in String callingPackage);
+ void clearWallpaper(in String callingPackage, int which, int userId);
/**
* Return whether the current system wallpaper has the given name.
@@ -118,4 +118,10 @@ interface IWallpaperManager {
* Check whether setting of wallpapers are allowed for the calling user.
*/
boolean isWallpaperSettingAllowed(in String callingPackage);
+
+ /*
+ * Keyguard: register a callback for being notified that lock-state relevant
+ * wallpaper content has changed.
+ */
+ boolean setLockWallpaperCallback(IWallpaperManagerCallback cb);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 9a88f2c67697..33fd1dbda63d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1842,13 +1842,10 @@ public class Instrumentation {
* @see UiAutomation
*/
public UiAutomation getUiAutomation() {
- if (mUiAutomationConnection != null) {
- if (mUiAutomation == null) {
- return getUiAutomation(0);
- }
- return mUiAutomation;
+ if ((mUiAutomation == null) || (mUiAutomation.isDestroyed())) {
+ return getUiAutomation(0);
}
- return null;
+ return mUiAutomation;
}
/**
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index dacf4ea997dc..b3a486f450bf 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -46,9 +46,9 @@ public class JobSchedulerImpl extends JobScheduler {
}
@Override
- public int scheduleAsPackage(JobInfo job, String packageName, int userId) {
+ public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag) {
try {
- return mBinder.scheduleAsPackage(job, packageName, userId);
+ return mBinder.scheduleAsPackage(job, packageName, userId, tag);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index da52c1e5ba1d..06fe515c22db 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -225,6 +225,10 @@ public final class LoadedApk {
return mApplicationInfo;
}
+ public int getTargetSdkVersion() {
+ return mApplicationInfo.targetSdkVersion;
+ }
+
public boolean isSecurityViolation() {
return mSecurityViolation;
}
@@ -252,7 +256,7 @@ public final class LoadedApk {
ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
} catch (RemoteException e) {
- throw new AssertionError(e);
+ throw e.rethrowFromSystemServer();
}
if (ai == null) {
@@ -268,154 +272,157 @@ public final class LoadedApk {
return mClassLoader;
}
- if (mIncludeCode && !mPackageName.equals("android")) {
- // Avoid the binder call when the package is the current application package.
- // The activity manager will perform ensure that dexopt is performed before
- // spinning up the process.
- if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
- final String isa = VMRuntime.getRuntime().vmInstructionSet();
- try {
- ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
- } catch (RemoteException re) {
- // Ignored.
- }
+ if (mPackageName.equals("android")) {
+ if (mBaseClassLoader == null) {
+ mClassLoader = ClassLoader.getSystemClassLoader();
+ } else {
+ mClassLoader = mBaseClassLoader;
}
+ return mClassLoader;
+ }
- final List<String> zipPaths = new ArrayList<>();
- final List<String> apkPaths = new ArrayList<>();
- final List<String> libPaths = new ArrayList<>();
-
- if (mRegisterPackage) {
- try {
- ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
- } catch (RemoteException e) {
- }
+ // Avoid the binder call when the package is the current application package.
+ // The activity manager will perform ensure that dexopt is performed before
+ // spinning up the process.
+ if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
+ final String isa = VMRuntime.getRuntime().vmInstructionSet();
+ try {
+ ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
+ }
+
+ final List<String> zipPaths = new ArrayList<>();
+ final List<String> apkPaths = new ArrayList<>();
+ final List<String> libPaths = new ArrayList<>();
- zipPaths.add(mAppDir);
- if (mSplitAppDirs != null) {
- Collections.addAll(zipPaths, mSplitAppDirs);
+ if (mRegisterPackage) {
+ try {
+ ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
+ }
- libPaths.add(mLibDir);
-
- /*
- * The following is a bit of a hack to inject
- * instrumentation into the system: If the app
- * being started matches one of the instrumentation names,
- * then we combine both the "instrumentation" and
- * "instrumented" app into the path, along with the
- * concatenation of both apps' shared library lists.
- */
-
- String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
- String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
- String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
- String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
-
- String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
- String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
- String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
- String[] instrumentationLibs = null;
-
- if (mAppDir.equals(instrumentationAppDir)
- || mAppDir.equals(instrumentedAppDir)) {
- zipPaths.clear();
- zipPaths.add(instrumentationAppDir);
- if (instrumentationSplitAppDirs != null) {
- Collections.addAll(zipPaths, instrumentationSplitAppDirs);
- }
- zipPaths.add(instrumentedAppDir);
- if (instrumentedSplitAppDirs != null) {
- Collections.addAll(zipPaths, instrumentedSplitAppDirs);
- }
+ zipPaths.add(mAppDir);
+ if (mSplitAppDirs != null) {
+ Collections.addAll(zipPaths, mSplitAppDirs);
+ }
- libPaths.clear();
- libPaths.add(instrumentationLibDir);
- libPaths.add(instrumentedLibDir);
+ libPaths.add(mLibDir);
+
+ /*
+ * The following is a bit of a hack to inject
+ * instrumentation into the system: If the app
+ * being started matches one of the instrumentation names,
+ * then we combine both the "instrumentation" and
+ * "instrumented" app into the path, along with the
+ * concatenation of both apps' shared library lists.
+ */
+
+ String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
+ String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
+ String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
+ String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
+
+ String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
+ String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
+ String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
+ String[] instrumentationLibs = null;
+
+ if (mAppDir.equals(instrumentationAppDir)
+ || mAppDir.equals(instrumentedAppDir)) {
+ zipPaths.clear();
+ zipPaths.add(instrumentationAppDir);
+ if (instrumentationSplitAppDirs != null) {
+ Collections.addAll(zipPaths, instrumentationSplitAppDirs);
+ }
+ zipPaths.add(instrumentedAppDir);
+ if (instrumentedSplitAppDirs != null) {
+ Collections.addAll(zipPaths, instrumentedSplitAppDirs);
+ }
- if (!instrumentedAppDir.equals(instrumentationAppDir)) {
- instrumentationLibs = getLibrariesFor(instrumentationPackageName);
- }
+ libPaths.clear();
+ libPaths.add(instrumentationLibDir);
+ libPaths.add(instrumentedLibDir);
+
+ if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+ instrumentationLibs = getLibrariesFor(instrumentationPackageName);
}
+ }
- apkPaths.addAll(zipPaths);
+ apkPaths.addAll(zipPaths);
- if (mSharedLibraries != null) {
- for (String lib : mSharedLibraries) {
- if (!zipPaths.contains(lib)) {
- zipPaths.add(0, lib);
- }
+ if (mSharedLibraries != null) {
+ for (String lib : mSharedLibraries) {
+ if (!zipPaths.contains(lib)) {
+ zipPaths.add(0, lib);
}
}
+ }
- if (instrumentationLibs != null) {
- for (String lib : instrumentationLibs) {
- if (!zipPaths.contains(lib)) {
- zipPaths.add(0, lib);
- }
+ if (instrumentationLibs != null) {
+ for (String lib : instrumentationLibs) {
+ if (!zipPaths.contains(lib)) {
+ zipPaths.add(0, lib);
}
}
+ }
- final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+ final String zip = mIncludeCode ? TextUtils.join(File.pathSeparator, zipPaths) : "";
- // Add path to libraries in apk for current abi
- if (mApplicationInfo.primaryCpuAbi != null) {
- for (String apk : apkPaths) {
- libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
- }
+ // Add path to libraries in apk for current abi
+ if (mApplicationInfo.primaryCpuAbi != null) {
+ for (String apk : apkPaths) {
+ libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
}
+ }
- String libraryPermittedPath = mDataDir;
- boolean isBundledApp = false;
-
- if (mApplicationInfo.isSystemApp()) {
- isBundledApp = true;
- // Add path to system libraries to libPaths;
- // Access to system libs should be limited
- // to bundled applications; this is why updated
- // system apps are not included.
- libPaths.add(System.getProperty("java.library.path"));
-
- // This is necessary to grant bundled apps access to
- // libraries located in subdirectories of /system/lib
- libraryPermittedPath += File.pathSeparator +
- System.getProperty("java.library.path");
- }
- // DO NOT SHIP: this is a workaround for apps loading native libraries
- // provided by 3rd party apps using absolute path instead of corresponding
- // classloader; see http://b/26954419 for example.
- if (mApplicationInfo.targetSdkVersion <= 23) {
- libraryPermittedPath += File.pathSeparator + "/data/app";
- }
- // -----------------------------------------------------------------------------
+ String libraryPermittedPath = mDataDir;
+ boolean isBundledApp = false;
+
+ if (mApplicationInfo.isSystemApp()) {
+ isBundledApp = true;
+ // Add path to system libraries to libPaths;
+ // Access to system libs should be limited
+ // to bundled applications; this is why updated
+ // system apps are not included.
+ libPaths.add(System.getProperty("java.library.path"));
+
+ // This is necessary to grant bundled apps access to
+ // libraries located in subdirectories of /system/lib
+ libraryPermittedPath += File.pathSeparator +
+ System.getProperty("java.library.path");
+ }
+ // DO NOT SHIP: this is a workaround for apps loading native libraries
+ // provided by 3rd party apps using absolute path instead of corresponding
+ // classloader; see http://b/26954419 for example.
+ if (mApplicationInfo.targetSdkVersion <= 23) {
+ libraryPermittedPath += File.pathSeparator + "/data/app";
+ }
+ // -----------------------------------------------------------------------------
- final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+ final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
- /*
- * With all the combination done (if necessary, actually
- * create the class loader.
- */
+ /*
+ * With all the combination done (if necessary, actually
+ * create the class loader.
+ */
- if (ActivityThread.localLOGV)
- Slog.v(ActivityThread.TAG, "Class path: " + zip +
- ", JNI path: " + librarySearchPath);
+ if (ActivityThread.localLOGV)
+ Slog.v(ActivityThread.TAG, "Class path: " + zip +
+ ", JNI path: " + librarySearchPath);
- // Temporarily disable logging of disk reads on the Looper thread
- // as this is early and necessary.
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ // Temporarily disable logging of disk reads on the Looper thread
+ // as this is early and necessary.
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, isBundledApp,
- librarySearchPath, libraryPermittedPath, mBaseClassLoader);
+ mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
+ mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+ libraryPermittedPath, mBaseClassLoader);
- StrictMode.setThreadPolicy(oldPolicy);
- } else {
- if (mBaseClassLoader == null) {
- mClassLoader = ClassLoader.getSystemClassLoader();
- } else {
- mClassLoader = mBaseClassLoader;
- }
- }
+ StrictMode.setThreadPolicy(oldPolicy);
return mClassLoader;
}
}
@@ -447,10 +454,10 @@ public final class LoadedApk {
IPackageManager pm = ActivityThread.getPackageManager();
android.content.pm.PackageInfo pi;
try {
- pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId());
+ pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.myUserId());
} catch (RemoteException e) {
- throw new IllegalStateException("Unable to get package info for "
- + mPackageName + "; is system dying?", e);
+ throw e.rethrowFromSystemServer();
}
if (pi == null) {
throw new IllegalStateException("Unable to get package info for "
@@ -707,7 +714,7 @@ public final class LoadedApk {
ActivityManagerNative.getDefault().unregisterReceiver(
rd.getIIntentReceiver());
} catch (RemoteException e) {
- // system crashed, nothing we can do
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -733,7 +740,7 @@ public final class LoadedApk {
ActivityManagerNative.getDefault().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
- // system crashed, nothing we can do
+ throw e.rethrowFromSystemServer();
}
sd.doForget();
}
@@ -858,7 +865,7 @@ public final class LoadedApk {
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
- Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index aa14cb513d46..b6e0467154c0 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -95,8 +95,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
private native long loadNativeCode(String path, String funcname, MessageQueue queue,
String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
- AssetManager assetMgr, byte[] savedState, ClassLoader classLoader, String libraryPath,
- String isolationPath);
+ AssetManager assetMgr, byte[] savedState, ClassLoader classLoader, String libraryPath);
private native String getDlError();
private native void unloadNativeCode(long handle);
private native void onStartNative(long handle);
@@ -166,7 +165,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
String path = classLoader.findLibrary(libname);
if (path == null) {
- throw new IllegalArgumentException("Unable to find native library: " + libname);
+ throw new IllegalArgumentException("Unable to find native library " + libname +
+ " using classloader: " + classLoader.toString());
}
byte[] nativeSavedState = savedInstanceState != null
@@ -176,8 +176,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
getAbsolutePath(getExternalFilesDir(null)),
Build.VERSION.SDK_INT, getAssets(), nativeSavedState,
- classLoader, classLoader.getLdLibraryPath(),
- classLoader.getLibraryPermittedPath());
+ classLoader, classLoader.getLdLibraryPath());
if (mNativeHandle == 0) {
throw new UnsatisfiedLinkError(
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a78076bdfa6f..2c34371a12c1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -21,7 +21,6 @@ import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -44,13 +43,19 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.NotificationHeaderView;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
@@ -64,7 +69,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
/**
@@ -262,8 +266,8 @@ public class Notification implements Parcelable
* The view that will represent this notification in the notification list (which is pulled
* down from the status bar).
*
- * As of N, this field is not used. The notification view is determined by the inputs to
- * {@link Notification.Builder}; a custom RemoteViews can optionally be
+ * As of N, this field may be null. The notification view is determined by the inputs
+ * to {@link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}.
*/
@Deprecated
@@ -274,7 +278,7 @@ public class Notification implements Parcelable
* opportunity to show more detail. The system UI may choose to show this
* instead of the normal content view at its discretion.
*
- * As of N, this field is not used. The expanded notification view is determined by the
+ * As of N, this field may be null. The expanded notification view is determined by the
* inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}.
*/
@@ -288,7 +292,7 @@ public class Notification implements Parcelable
* choose to show this as a heads-up notification, which will pop up so the user can see
* it without leaving their current activity.
*
- * As of N, this field is not used. The heads-up notification view is determined by the
+ * As of N, this field may be null. The heads-up notification view is determined by the
* inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}.
*/
@@ -822,6 +826,12 @@ public class Notification implements Parcelable
public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
/**
+ * {@link #extras} key: whether the chronometer set on the notification should count down
+ * instead of counting up. Is only relevant if key {@link #EXTRA_SHOW_CHRONOMETER} is present.
+ */
+ public static final String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
+
+ /**
* {@link #extras} key: whether {@link #when} should be shown,
* as supplied to {@link Builder#setShowWhen(boolean)}.
*/
@@ -894,6 +904,11 @@ public class Notification implements Parcelable
*/
public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
+
private Icon mSmallIcon;
private Icon mLargeIcon;
@@ -1365,98 +1380,6 @@ public class Notification implements Parcelable
public Notification publicVersion;
/**
- * Structure to encapsulate a topic that is shown in Notification settings.
- * It must include an id and label.
- */
- public static class Topic implements Parcelable {
- private final String id;
- private final CharSequence label;
-
- public Topic(String id, CharSequence label) {
- this.id = id;
- this.label = safeCharSequence(label);
- }
-
- private Topic(Parcel in) {
- if (in.readInt() != 0) {
- id = in.readString();
- } else {
- id = null;
- }
- label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- }
-
- public String getId() {
- return id;
- }
-
- public CharSequence getLabel() {
- return label;
- }
-
- @Override
- public String toString() {
- return new StringBuilder(Topic.class.getSimpleName()).append('[')
- .append("id=").append(id)
- .append(",label=").append(label)
- .append(']').toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Topic)) return false;
- if (o == this) return true;
- final Topic other = (Topic) o;
- return Objects.equals(other.id, id)
- && Objects.equals(other.label, label);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, label);
- }
-
- @Override
- public Topic clone() {
- return new Topic(id, label);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- if (id != null) {
- out.writeInt(1);
- out.writeString(id);
- } else {
- out.writeInt(0);
- }
- TextUtils.writeToParcel(label, out, flags);
- }
- public static final Parcelable.Creator<Topic> CREATOR =
- new Parcelable.Creator<Topic>() {
- public Topic createFromParcel(Parcel in) {
- return new Topic(in);
- }
- public Topic[] newArray(int size) {
- return new Topic[size];
- }
- };
- }
-
- @SystemApi
- public static final String TOPIC_DEFAULT = "system_default_topic";
-
- private Topic topic;
-
- public Topic getTopic() {
- return topic;
- }
-
- /**
* Constructs a Notification object with default values.
* You might want to consider using {@link Builder} instead.
*/
@@ -1582,10 +1505,6 @@ public class Notification implements Parcelable
}
color = parcel.readInt();
-
- if (parcel.readInt() != 0) {
- topic = Topic.CREATOR.createFromParcel(parcel);
- }
}
@Override
@@ -1686,10 +1605,6 @@ public class Notification implements Parcelable
that.color = this.color;
- if (this.topic != null) {
- that.topic = this.topic.clone();
- }
-
if (!heavy) {
that.lightenPayload(); // will clean out extras
}
@@ -1739,8 +1654,34 @@ public class Notification implements Parcelable
+ " instance is a custom Parcelable and not allowed in Notification");
return cs.toString();
}
+ return removeTextSizeSpans(cs);
+ }
- return cs;
+ private static CharSequence removeTextSizeSpans(CharSequence charSequence) {
+ if (charSequence instanceof Spanned) {
+ Spanned ss = (Spanned) charSequence;
+ Object[] spans = ss.getSpans(0, ss.length(), Object.class);
+ SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
+ for (Object span : spans) {
+ Object resultSpan = span;
+ if (span instanceof TextAppearanceSpan) {
+ TextAppearanceSpan originalSpan = (TextAppearanceSpan) span;
+ resultSpan = new TextAppearanceSpan(
+ originalSpan.getFamily(),
+ originalSpan.getTextStyle(),
+ -1,
+ originalSpan.getTextColor(),
+ originalSpan.getLinkTextColor());
+ } else if (span instanceof RelativeSizeSpan
+ || span instanceof AbsoluteSizeSpan) {
+ continue;
+ }
+ builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
+ ss.getSpanFlags(span));
+ }
+ return builder;
+ }
+ return charSequence;
}
public int describeContents() {
@@ -1870,13 +1811,6 @@ public class Notification implements Parcelable
}
parcel.writeInt(color);
-
- if (topic != null) {
- parcel.writeInt(1);
- topic.writeToParcel(parcel, 0);
- } else {
- parcel.writeInt(0);
- }
}
/**
@@ -2019,10 +1953,6 @@ public class Notification implements Parcelable
sb.append(" publicVersion=");
sb.append(publicVersion.toString());
}
- if (topic != null) {
- sb.append("topic=");
- sb.append(topic.toString());
- }
sb.append(")");
return sb.toString();
}
@@ -2128,8 +2058,23 @@ public class Notification implements Parcelable
* </pre>
*/
public static class Builder {
+ /**
+ * @hide
+ */
+ public static final String EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT =
+ "android.rebuild.contentViewActionCount";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT
+ = "android.rebuild.bigViewActionCount";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT
+ = "android.rebuild.hudViewActionCount";
+
private static final int MAX_ACTION_BUTTONS = 3;
- private static final float LARGE_TEXT_SCALE = 1.3f;
private Context mContext;
private Notification mN;
@@ -2248,8 +2193,12 @@ public class Notification implements Parcelable
*
* Useful when showing an elapsed time (like an ongoing phone call).
*
+ * The counter can also be set to count down to <code>when</code> when using
+ * {@link #setChronometerCountsDown(boolean)}.
+ *
* @see android.widget.Chronometer
* @see Notification#when
+ * @see #setChronometerCountsDown(boolean)
*/
public Builder setUsesChronometer(boolean b) {
mN.extras.putBoolean(EXTRA_SHOW_CHRONOMETER, b);
@@ -2257,6 +2206,19 @@ public class Notification implements Parcelable
}
/**
+ * Sets the Chronometer to count down instead of counting up.
+ *
+ * <p>This is only relevant if {@link #setUsesChronometer(boolean)} has been set to true.
+ * If it isn't set the chronometer will count up.
+ *
+ * @see #setUsesChronometer(boolean)
+ */
+ public Builder setChronometerCountsDown(boolean countsDown) {
+ mN.extras.putBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN, countsDown);
+ return this;
+ }
+
+ /**
* Set the small icon resource, which will be used to represent the notification in the
* status bar.
*
@@ -2979,19 +2941,6 @@ public class Notification implements Parcelable
return this;
}
- /**
- * Sets the topic of this notification. Topics are typically displayed in Notification
- * settings.
- * <p>
- * Every topic must have an id and a textual label.
- *
- * @param topic The topic to add.
- */
- public Builder setTopic(Topic topic) {
- mN.topic = topic;
- return this;
- }
-
private Drawable getProfileBadgeDrawable() {
// Note: This assumes that the current user can read the profile badge of the
// originating user.
@@ -3200,6 +3149,8 @@ public class Notification implements Parcelable
contentView.setLong(R.id.chronometer, "setBase",
mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
contentView.setBoolean(R.id.chronometer, "setStarted", true);
+ boolean countsDown = mN.extras.getBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN);
+ contentView.setChronometerCountsDown(R.id.chronometer, countsDown);
} else {
contentView.setViewVisibility(R.id.time, View.VISIBLE);
contentView.setLong(R.id.time, "setTime", mN.when);
@@ -3281,6 +3232,10 @@ public class Notification implements Parcelable
validRemoteInput |= hasValidRemoteInput(action);
final RemoteViews button = generateActionButton(action);
+ if (i == N - 1) {
+ button.setViewLayoutWidth(com.android.internal.R.id.action0,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ }
big.addView(R.id.actions, button);
}
}
@@ -3332,8 +3287,8 @@ public class Notification implements Parcelable
* 2. Style's proposed content view
* 3. Standard template view
*/
- public RemoteViews makeContentView() {
- if (mN.contentView != null) {
+ public RemoteViews createContentView() {
+ if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.contentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeContentView();
@@ -3347,19 +3302,16 @@ public class Notification implements Parcelable
/**
* Construct a RemoteViews for the final big notification layout.
*/
- public RemoteViews makeBigContentView() {
+ public RemoteViews createBigContentView() {
RemoteViews result = null;
- if (mN.bigContentView != null) {
+ if (mN.bigContentView != null
+ && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.bigContentView;
} else if (mStyle != null) {
result = mStyle.makeBigContentView();
- } else if (mActions.size() == 0) {
- return null;
- }
- if (result == null) {
- result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
- } else {
hideLine1Text(result);
+ } else if (mActions.size() != 0) {
+ result = applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
adaptNotificationHeaderForBigContentView(result);
return result;
@@ -3379,18 +3331,23 @@ public class Notification implements Parcelable
}
private void hideLine1Text(RemoteViews result) {
- result.setViewVisibility(R.id.text_line_1, View.GONE);
+ if (result != null) {
+ result.setViewVisibility(R.id.text_line_1, View.GONE);
+ }
}
private void adaptNotificationHeaderForBigContentView(RemoteViews result) {
- result.setBoolean(R.id.notification_header, "setExpanded", true);
+ if (result != null) {
+ result.setBoolean(R.id.notification_header, "setExpanded", true);
+ }
}
/**
* Construct a RemoteViews for the final heads-up notification layout.
*/
- public RemoteViews makeHeadsUpContentView() {
- if (mN.headsUpContentView != null) {
+ public RemoteViews createHeadsUpContentView() {
+ if (mN.headsUpContentView != null
+ && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.headsUpContentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeHeadsUpContentView();
@@ -3401,7 +3358,6 @@ public class Notification implements Parcelable
return null;
}
-
return applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
@@ -3413,7 +3369,7 @@ public class Notification implements Parcelable
public RemoteViews makePublicContentView() {
if (mN.publicVersion != null) {
final Builder builder = recoverBuilder(mContext, mN.publicVersion);
- return builder.makeContentView();
+ return builder.createContentView();
}
Bundle savedBundle = mN.extras;
Style style = mStyle;
@@ -3425,6 +3381,8 @@ public class Notification implements Parcelable
savedBundle.getBoolean(EXTRA_SHOW_WHEN));
publicExtras.putBoolean(EXTRA_SHOW_CHRONOMETER,
savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
+ publicExtras.putBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN,
+ savedBundle.getBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN));
publicExtras.putCharSequence(EXTRA_TITLE,
mContext.getString(R.string.notification_hidden_text));
mN.extras = publicExtras;
@@ -3527,9 +3485,18 @@ public class Notification implements Parcelable
mN.extras.putStringArray(EXTRA_PEOPLE,
mPersonList.toArray(new String[mPersonList.size()]));
}
+ if (mN.bigContentView != null || mN.contentView != null
+ || mN.headsUpContentView != null) {
+ mN.extras.putBoolean(EXTRA_CONTAINS_CUSTOM_VIEW, true);
+ }
return mN;
}
+ /**
+ * Creates a Builder from an existing notification so further changes can be made.
+ * @param context The context for your application / activity.
+ * @param n The notification to create a Builder from.
+ */
public static Notification.Builder recoverBuilder(Context context, Notification n) {
// Re-create notification context so we can access app resources.
ApplicationInfo applicationInfo = n.extras.getParcelable(
@@ -3551,8 +3518,9 @@ public class Notification implements Parcelable
}
private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
- Class<? extends Style>[] classes = new Class[]{
- BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class};
+ Class<? extends Style>[] classes = new Class[] {
+ BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
+ DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class };
for (Class<? extends Style> innerClass : classes) {
if (templateClass.equals(innerClass.getName())) {
return innerClass;
@@ -3561,19 +3529,6 @@ public class Notification implements Parcelable
return null;
}
- private void setBuilderContentView(Notification n, RemoteViews contentView) {
- n.contentView = contentView;
- }
-
- private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) {
- n.bigContentView = bigContentView;
- }
-
- private void setBuilderHeadsUpContentView(Notification n,
- RemoteViews headsUpContentView) {
- n.headsUpContentView = headsUpContentView;
- }
-
/**
* @deprecated Use {@link #build()} instead.
*/
@@ -3601,6 +3556,29 @@ public class Notification implements Parcelable
mStyle.buildStyled(mN);
}
+ if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
+ && (mStyle == null || !mStyle.displayCustomViewInline())) {
+ if (mN.contentView == null) {
+ mN.contentView = createContentView();
+ mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
+ mN.contentView.getSequenceNumber());
+ }
+ if (mN.bigContentView == null) {
+ mN.bigContentView = createBigContentView();
+ if (mN.bigContentView != null) {
+ mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
+ mN.bigContentView.getSequenceNumber());
+ }
+ }
+ if (mN.headsUpContentView == null) {
+ mN.headsUpContentView = createHeadsUpContentView();
+ if (mN.headsUpContentView != null) {
+ mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
+ mN.headsUpContentView.getSequenceNumber());
+ }
+ }
+ }
+
if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
mN.flags |= FLAG_SHOW_LIGHTS;
}
@@ -3618,6 +3596,40 @@ public class Notification implements Parcelable
return n;
}
+ /**
+ * @hide
+ */
+ public static void stripForDelivery(Notification n) {
+ String templateClass = n.extras.getString(EXTRA_TEMPLATE);
+ if (TextUtils.isEmpty(templateClass)) {
+ return;
+ }
+ // Only strip views for known Styles because we won't know how to
+ // re-create them otherwise.
+ if (getNotificationStyleClass(templateClass) == null) {
+ return;
+ }
+ // Get rid of unmodified BuilderRemoteViews.
+ if (n.contentView instanceof BuilderRemoteViews &&
+ n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) ==
+ n.contentView.getSequenceNumber()) {
+ n.contentView = null;
+ n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
+ }
+ if (n.bigContentView instanceof BuilderRemoteViews &&
+ n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) ==
+ n.bigContentView.getSequenceNumber()) {
+ n.bigContentView = null;
+ n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
+ }
+ if (n.headsUpContentView instanceof BuilderRemoteViews &&
+ n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) ==
+ n.headsUpContentView.getSequenceNumber()) {
+ n.headsUpContentView = null;
+ n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
+ }
+ }
+
private int getBaseLayoutResource() {
return R.layout.notification_template_material_base;
}
@@ -3814,6 +3826,14 @@ public class Notification implements Parcelable
public boolean hasSummaryInHeader() {
return true;
}
+
+ /**
+ * @hide
+ * @return Whether custom content views are displayed inline in the style
+ */
+ public boolean displayCustomViewInline() {
+ return false;
+ }
}
/**
@@ -4187,6 +4207,7 @@ public class Notification implements Parcelable
final float density = mBuilder.mContext.getResources().getDisplayMetrics().density;
int topPadding = (int) (5 * density);
int bottomPadding = (int) (13 * density);
+ boolean first = true;
while (i < mTexts.size() && i < rowIds.length) {
CharSequence str = mTexts.get(i);
if (str != null && !str.equals("")) {
@@ -4198,23 +4219,26 @@ public class Notification implements Parcelable
}
contentView.setViewPadding(rowIds[i], 0, topPadding, 0,
i == rowIds.length - 1 || i == mTexts.size() - 1 ? bottomPadding : 0);
+ handleInboxImageMargin(contentView, rowIds[i], first);
+ first = false;
}
i++;
}
- handleInboxImageMargin(contentView, rowIds[0]);
return contentView;
}
- private void handleInboxImageMargin(RemoteViews contentView, int id) {
- final int max = mBuilder.mN.extras.getInt(EXTRA_PROGRESS_MAX, 0);
- final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
- boolean hasProgress = max != 0 || ind;
+ private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first) {
int endMargin = 0;
- if (mTexts.size() > 0 && mBuilder.mN.mLargeIcon != null && !hasProgress) {
- endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_content_picture_margin);
+ if (first) {
+ final int max = mBuilder.mN.extras.getInt(EXTRA_PROGRESS_MAX, 0);
+ final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
+ boolean hasProgress = max != 0 || ind;
+ if (mBuilder.mN.mLargeIcon != null && !hasProgress) {
+ endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
+ }
}
contentView.setViewLayoutMarginEnd(id, endMargin);
}
@@ -4321,6 +4345,15 @@ public class Notification implements Parcelable
return makeMediaBigContentView();
}
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ RemoteViews expanded = makeMediaBigContentView();
+ return expanded != null ? expanded : makeMediaContentView();
+ }
+
/** @hide */
@Override
public void addExtras(Bundle extras) {
@@ -4388,13 +4421,11 @@ public class Notification implements Parcelable
}
handleImage(view);
// handle the content margin
- int endMargin;
+ int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_margin_end);;
if (mBuilder.mN.mLargeIcon != null) {
- endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_content_picture_margin_media);
- } else {
- endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_content_margin_end);
+ endMargin += mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
}
view.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
return view;
@@ -4402,6 +4433,13 @@ public class Notification implements Parcelable
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
+ int actionsInCompact = mActionsToShowInCompact == null
+ ? 0
+ : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
+ if (mBuilder.mN.mLargeIcon == null && actionCount <= actionsInCompact) {
+ return null;
+ }
RemoteViews big = mBuilder.applyStandardTemplate(
R.layout.notification_template_material_big_media,
false);
@@ -4434,6 +4472,224 @@ public class Notification implements Parcelable
}
}
+ /**
+ * Notification style for custom views that are decorated by the system
+ *
+ * <p>Instead of providing a notification that is completely custom, a developer can set this
+ * style and still obtain system decorations like the notification header with the expand
+ * affordance and actions.
+ *
+ * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+ * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+ * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+ * corresponding custom views to display.
+ *
+ * To use this style with your Notification, feed it to
+ * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
+ * <pre class="prettyprint">
+ * Notification noti = new Notification.Builder()
+ * .setSmallIcon(R.drawable.ic_stat_player)
+ * .setLargeIcon(albumArtBitmap))
+ * .setCustomContentView(contentView);
+ * .setStyle(<b>new Notification.DecoratedCustomViewStyle()</b>)
+ * .build();
+ * </pre>
+ */
+ public static class DecoratedCustomViewStyle extends Style {
+
+ public DecoratedCustomViewStyle() {
+ }
+
+ public DecoratedCustomViewStyle(Builder builder) {
+ setBuilder(builder);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean displayCustomViewInline() {
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeContentView() {
+ return makeStandardTemplateWithCustomContent(mBuilder.mN.contentView);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeBigContentView() {
+ return makeDecoratedBigContentView();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ return makeDecoratedHeadsUpContentView();
+ }
+
+ private RemoteViews makeDecoratedHeadsUpContentView() {
+ RemoteViews headsUpContentView = mBuilder.mN.headsUpContentView == null
+ ? mBuilder.mN.contentView
+ : mBuilder.mN.headsUpContentView;
+ if (mBuilder.mActions.size() == 0) {
+ return makeStandardTemplateWithCustomContent(headsUpContentView);
+ }
+ RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
+ mBuilder.getBigBaseLayoutResource());
+ buildIntoRemoteViewContent(remoteViews, headsUpContentView);
+ return remoteViews;
+ }
+
+ private RemoteViews makeStandardTemplateWithCustomContent(RemoteViews customContent) {
+ RemoteViews remoteViews = mBuilder.applyStandardTemplate(
+ mBuilder.getBaseLayoutResource());
+ buildIntoRemoteViewContent(remoteViews, customContent);
+ return remoteViews;
+ }
+
+ private RemoteViews makeDecoratedBigContentView() {
+ RemoteViews bigContentView = mBuilder.mN.bigContentView == null
+ ? mBuilder.mN.contentView
+ : mBuilder.mN.bigContentView;
+ if (mBuilder.mActions.size() == 0) {
+ return makeStandardTemplateWithCustomContent(bigContentView);
+ }
+ RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
+ mBuilder.getBigBaseLayoutResource());
+ buildIntoRemoteViewContent(remoteViews, bigContentView);
+ return remoteViews;
+ }
+
+ private void buildIntoRemoteViewContent(RemoteViews remoteViews,
+ RemoteViews customContent) {
+ remoteViews.removeAllViews(R.id.notification_main_column);
+ // Need to clone customContent before adding, because otherwise it can no longer be
+ // parceled independently of remoteViews.
+ if (customContent != null) {
+ customContent = customContent.clone();
+ }
+ remoteViews.addView(R.id.notification_main_column, customContent);
+ // also update the end margin if there is an image
+ int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_margin_end);
+ if (mBuilder.mN.mLargeIcon != null) {
+ endMargin += mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
+ }
+ remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
+ }
+ }
+
+ /**
+ * Notification style for media custom views that are decorated by the system
+ *
+ * <p>Instead of providing a media notification that is completely custom, a developer can set
+ * this style and still obtain system decorations like the notification header with the expand
+ * affordance and actions.
+ *
+ * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+ * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+ * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+ * corresponding custom views to display.
+ *
+ * To use this style with your Notification, feed it to
+ * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
+ * <pre class="prettyprint">
+ * Notification noti = new Notification.Builder()
+ * .setSmallIcon(R.drawable.ic_stat_player)
+ * .setLargeIcon(albumArtBitmap))
+ * .setCustomContentView(contentView);
+ * .setStyle(<b>new Notification.DecoratedMediaCustomViewStyle()</b>
+ * .setMediaSession(mySession))
+ * .build();
+ * </pre>
+ *
+ * @see android.app.Notification.DecoratedCustomViewStyle
+ * @see android.app.Notification.MediaStyle
+ */
+ public static class DecoratedMediaCustomViewStyle extends MediaStyle {
+
+ public DecoratedMediaCustomViewStyle() {
+ }
+
+ public DecoratedMediaCustomViewStyle(Builder builder) {
+ setBuilder(builder);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean displayCustomViewInline() {
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeContentView() {
+ RemoteViews remoteViews = super.makeContentView();
+ return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
+ mBuilder.mN.contentView);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeBigContentView() {
+ RemoteViews customRemoteView = mBuilder.mN.bigContentView != null
+ ? mBuilder.mN.bigContentView
+ : mBuilder.mN.contentView;
+ return makeBigContentViewWithCustomContent(customRemoteView);
+ }
+
+ private RemoteViews makeBigContentViewWithCustomContent(RemoteViews customRemoteView) {
+ RemoteViews remoteViews = super.makeBigContentView();
+ if (remoteViews != null) {
+ return buildIntoRemoteView(remoteViews, R.id.notification_main_column,
+ customRemoteView);
+ } else if (customRemoteView != mBuilder.mN.contentView){
+ remoteViews = super.makeContentView();
+ return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
+ customRemoteView);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ RemoteViews customRemoteView = mBuilder.mN.headsUpContentView != null
+ ? mBuilder.mN.headsUpContentView
+ : mBuilder.mN.contentView;
+ return makeBigContentViewWithCustomContent(customRemoteView);
+ }
+
+ private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
+ RemoteViews customContent) {
+ remoteViews.removeAllViews(id);
+ // Need to clone customContent before adding, because otherwise it can no longer be
+ // parceled independently of remoteViews.
+ if (customContent != null) {
+ customContent = customContent.clone();
+ }
+ remoteViews.addView(id, customContent);
+ return remoteViews;
+ }
+ }
+
// When adding a new Style subclass here, don't forget to update
// Builder.getNotificationStyleClass.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index a83225d961b0..344315d5266f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -16,6 +16,9 @@
package android.app;
+import com.android.internal.util.Preconditions;
+
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -37,11 +40,14 @@ import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.service.notification.IConditionListener;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
import java.util.List;
@@ -135,6 +141,13 @@ public class NotificationManager
public static final String ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL
= "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL";
+
+ /** @hide */
+ @IntDef({INTERRUPTION_FILTER_NONE, INTERRUPTION_FILTER_PRIORITY, INTERRUPTION_FILTER_ALARMS,
+ INTERRUPTION_FILTER_ALL, INTERRUPTION_FILTER_UNKNOWN})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InterruptionFilter {}
+
/**
* {@link #getCurrentInterruptionFilter() Interruption filter} constant -
* Normal interruption filter.
@@ -243,6 +256,7 @@ public class NotificationManager
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
final Notification copy = notification.clone();
+ Builder.stripForDelivery(copy);
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
copy, idOut, user.getIdentifier());
@@ -250,6 +264,7 @@ public class NotificationManager
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -290,6 +305,7 @@ public class NotificationManager
try {
service.cancelNotificationWithTag(pkg, tag, id, user.getIdentifier());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -305,6 +321,7 @@ public class NotificationManager
try {
service.cancelAllNotifications(pkg, UserHandle.myUserId());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -316,7 +333,7 @@ public class NotificationManager
try {
return service.getEffectsSuppressor();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -328,7 +345,7 @@ public class NotificationManager
try {
return service.matchesCallFilter(extras);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -340,7 +357,7 @@ public class NotificationManager
try {
return service.isSystemConditionProviderEnabled(path);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -352,6 +369,7 @@ public class NotificationManager
try {
service.setZenMode(mode, conditionId, reason);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -363,8 +381,8 @@ public class NotificationManager
try {
return service.getZenMode();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return Global.ZEN_MODE_OFF;
}
/**
@@ -375,8 +393,8 @@ public class NotificationManager
try {
return service.getZenModeConfig();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -387,8 +405,8 @@ public class NotificationManager
try {
return service.getRuleInstanceCount(owner);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return 0;
}
/**
@@ -403,8 +421,8 @@ public class NotificationManager
try {
return service.getAutomaticZenRules();
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -423,8 +441,8 @@ public class NotificationManager
try {
return service.getAutomaticZenRule(id);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -443,8 +461,8 @@ public class NotificationManager
try {
return service.addAutomaticZenRule(automaticZenRule);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -464,8 +482,8 @@ public class NotificationManager
try {
return service.updateAutomaticZenRule(automaticZenRule);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -485,8 +503,8 @@ public class NotificationManager
try {
return service.removeAutomaticZenRule(id);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -499,8 +517,32 @@ public class NotificationManager
try {
return service.removeAutomaticZenRules(packageName);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the user specified importance for notifications from the calling package.
+ */
+ public @NotificationListenerService.Ranking.Importance int getImportance() {
+ INotificationManager service = getService();
+ try {
+ return service.getPackageImportance(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether notifications from the calling package are blocked.
+ */
+ public boolean areNotificationsEnabled() {
+ INotificationManager service = getService();
+ try {
+ return service.areNotificationsEnabled(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -522,8 +564,8 @@ public class NotificationManager
try {
return service.isNotificationPolicyAccessGranted(mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/** @hide */
@@ -532,8 +574,8 @@ public class NotificationManager
try {
return service.isNotificationPolicyAccessGrantedForPackage(pkg);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -548,8 +590,8 @@ public class NotificationManager
try {
return service.getNotificationPolicy(mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -567,6 +609,7 @@ public class NotificationManager
try {
service.setNotificationPolicy(mContext.getOpPackageName(), policy);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -576,6 +619,7 @@ public class NotificationManager
try {
service.setNotificationPolicyAccessGranted(pkg, granted);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -592,8 +636,9 @@ public class NotificationManager
return rt;
}
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return new ArraySet<String>();
+ return new ArraySet<>();
}
private Context mContext;
@@ -852,7 +897,7 @@ public class NotificationManager
* Only available if policy access is granted to this package.
* See {@link #isNotificationPolicyAccessGranted}.
*/
- public final int getCurrentInterruptionFilter() {
+ public final @InterruptionFilter int getCurrentInterruptionFilter() {
final INotificationManager service = getService();
try {
return zenModeToInterruptionFilter(service.getZenMode());
diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index c7d2140d042d..a95291514936 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -363,7 +363,8 @@ public final class SearchableInfo implements Parcelable {
String suggestProviderPackage = null;
if (mSuggestAuthority != null) {
PackageManager pm = activityContext.getPackageManager();
- ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority, 0);
+ ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
if (pi != null) {
suggestProviderPackage = pi.packageName;
}
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index c552cfc98677..c1180e25a0d3 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -87,20 +87,20 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
new Thread("SharedPreferencesImpl-load") {
public void run() {
- synchronized (SharedPreferencesImpl.this) {
- loadFromDiskLocked();
- }
+ loadFromDisk();
}
}.start();
}
- private void loadFromDiskLocked() {
- if (mLoaded) {
- return;
- }
- if (mBackupFile.exists()) {
- mFile.delete();
- mBackupFile.renameTo(mFile);
+ private void loadFromDisk() {
+ synchronized (SharedPreferencesImpl.this) {
+ if (mLoaded) {
+ return;
+ }
+ if (mBackupFile.exists()) {
+ mFile.delete();
+ mBackupFile.renameTo(mFile);
+ }
}
// Debugging
@@ -118,27 +118,27 @@ final class SharedPreferencesImpl implements SharedPreferences {
str = new BufferedInputStream(
new FileInputStream(mFile), 16*1024);
map = XmlUtils.readMapXml(str);
- } catch (XmlPullParserException e) {
- Log.w(TAG, "getSharedPreferences", e);
- } catch (FileNotFoundException e) {
- Log.w(TAG, "getSharedPreferences", e);
- } catch (IOException e) {
+ } catch (XmlPullParserException | IOException e) {
Log.w(TAG, "getSharedPreferences", e);
} finally {
IoUtils.closeQuietly(str);
}
}
} catch (ErrnoException e) {
+ /* ignore */
}
- mLoaded = true;
- if (map != null) {
- mMap = map;
- mStatTimestamp = stat.st_mtime;
- mStatSize = stat.st_size;
- } else {
- mMap = new HashMap<String, Object>();
+
+ synchronized (SharedPreferencesImpl.this) {
+ mLoaded = true;
+ if (map != null) {
+ mMap = map;
+ mStatTimestamp = stat.st_mtime;
+ mStatSize = stat.st_size;
+ } else {
+ mMap = new HashMap<>();
+ }
+ notifyAll();
}
- notifyAll();
}
static File makeBackupFile(File prefsFile) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5eed781d76c3..307c3eb18362 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -89,10 +89,13 @@ import android.os.BatteryManager;
import android.os.DropBoxManager;
import android.os.HardwarePropertiesManager;
import android.os.IBinder;
+import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
+import android.os.IRecoverySystem;
import android.os.IUserManager;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RecoverySystem;
import android.os.ServiceManager;
import android.os.SystemVibrator;
import android.os.UserHandle;
@@ -379,6 +382,18 @@ final class SystemServiceRegistry {
service, ctx.mMainThread.getHandler());
}});
+ registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,
+ new CachedServiceFetcher<RecoverySystem>() {
+ @Override
+ public RecoverySystem createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.RECOVERY_SERVICE);
+ IRecoverySystem service = IRecoverySystem.Stub.asInterface(b);
+ if (service == null) {
+ Log.wtf(TAG, "Failed to get recovery service.");
+ }
+ return new RecoverySystem(service);
+ }});
+
registerService(Context.SEARCH_SERVICE, SearchManager.class,
new CachedServiceFetcher<SearchManager>() {
@Override
@@ -715,7 +730,14 @@ final class SystemServiceRegistry {
new CachedServiceFetcher<HardwarePropertiesManager>() {
@Override
public HardwarePropertiesManager createService(ContextImpl ctx) {
- return new HardwarePropertiesManager();
+ IBinder b = ServiceManager.getService(Context.HARDWARE_PROPERTIES_SERVICE);
+ IHardwarePropertiesManager service =
+ IHardwarePropertiesManager.Stub.asInterface(b);
+ if (service == null) {
+ Log.wtf(TAG, "Failed to get hardwareproperties service.");
+ return null;
+ }
+ return new HardwarePropertiesManager(ctx, service);
}});
registerService(Context.SOUND_TRIGGER_SERVICE, SoundTriggerManager.class,
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index eda82c0119f0..b7e31ab752fa 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+h * Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.WindowManagerGlobal;
@@ -265,11 +266,10 @@ public class WallpaperManager {
private Bitmap mWallpaper;
private Bitmap mDefaultWallpaper;
- private static final int MSG_CLEAR_WALLPAPER = 1;
-
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
+ forgetLoadedWallpaper();
}
public void onWallpaperChanged() {
@@ -278,13 +278,14 @@ public class WallpaperManager {
* to null so if the user requests the wallpaper again then we'll
* fetch it.
*/
- synchronized (this) {
- mWallpaper = null;
- mDefaultWallpaper = null;
- }
+ forgetLoadedWallpaper();
}
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
+ return peekWallpaperBitmap(context, returnDefault, context.getUserId());
+ }
+
+ public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault, int userId) {
synchronized (this) {
if (mService != null) {
try {
@@ -303,7 +304,7 @@ public class WallpaperManager {
}
mWallpaper = null;
try {
- mWallpaper = getCurrentWallpaperLocked(context);
+ mWallpaper = getCurrentWallpaperLocked(userId);
} catch (OutOfMemoryError e) {
Log.w(TAG, "No memory load current wallpaper", e);
}
@@ -326,7 +327,7 @@ public class WallpaperManager {
}
}
- private Bitmap getCurrentWallpaperLocked(Context context) {
+ private Bitmap getCurrentWallpaperLocked(int userId) {
if (mService == null) {
Log.w(TAG, "WallpaperService not running");
return null;
@@ -334,7 +335,8 @@ public class WallpaperManager {
try {
Bundle params = new Bundle();
- ParcelFileDescriptor fd = mService.getWallpaper(this, params);
+ ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM,
+ params, userId);
if (fd != null) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -633,7 +635,7 @@ public class WallpaperManager {
* wallpaper or a null pointer if these is none.
*/
public Drawable peekFastDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -646,7 +648,52 @@ public class WallpaperManager {
* @hide
*/
public Bitmap getBitmap() {
- return sGlobals.peekWallpaperBitmap(mContext, true);
+ return getBitmapAsUser(mContext.getUserId());
+ }
+
+ /**
+ * Like {@link #getDrawable()} but returns a Bitmap for the provided user.
+ *
+ * @hide
+ */
+ public Bitmap getBitmapAsUser(int userId) {
+ return sGlobals.peekWallpaperBitmap(mContext, true, userId);
+ }
+
+ /**
+ * Get an open, readable file descriptor to the given wallpaper image file.
+ * The callee is resopnsible for closing the fd when done ingesting the file.
+ *
+ * <p>If no lock-specific wallpaper has been configured for the given user, then
+ * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than
+ * returning the system wallpaper's image file.
+ */
+ public ParcelFileDescriptor getWallpaperFile(int which) {
+ return getWallpaperFile(which, mContext.getUserId());
+ }
+
+ /**
+ * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
+ * for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
+ * permission to access another user's wallpaper data.
+ * @hide
+ */
+ public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
+ if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
+ }
+
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ } else {
+ try {
+ Bundle outParams = new Bundle();
+ return sGlobals.mService.getWallpaper(null, which, outParams, userId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
}
/**
@@ -656,9 +703,7 @@ public class WallpaperManager {
* wallpaper will require reloading it again from disk.
*/
public void forgetLoadedWallpaper() {
- if (isWallpaperSupported()) {
- sGlobals.forgetLoadedWallpaper();
- }
+ sGlobals.forgetLoadedWallpaper();
}
/**
@@ -722,7 +767,9 @@ public class WallpaperManager {
}
// fallback crop activity
- cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
+ final String cropperPackage = mContext.getString(
+ com.android.internal.R.string.config_wallpaperCropperPackage);
+ cropAndSetWallpaperIntent.setPackage(cropperPackage);
List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
cropAndSetWallpaperIntent, 0);
if (cropAppList.size() > 0) {
@@ -1209,12 +1256,23 @@ public class WallpaperManager {
*/
@SystemApi
public void clearWallpaper() {
+ clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId());
+ }
+
+ /**
+ * Clear the wallpaper for a specific user. The caller must hold the
+ * INTERACT_ACROSS_USERS_FULL permission to clear another user's
+ * wallpaper.
+ * @hide
+ */
+ @SystemApi
+ public void clearWallpaper(int which, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
}
try {
- sGlobals.mService.clearWallpaper(mContext.getOpPackageName());
+ sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId);
} catch (RemoteException e) {
// Ignore
}
@@ -1363,7 +1421,7 @@ public class WallpaperManager {
}
/**
- * Remove any currently set wallpaper, reverting to the system's built-in
+ * Remove any currently set system wallpaper, reverting to the system's built-in
* wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
* is broadcast.
*
@@ -1424,6 +1482,26 @@ public class WallpaperManager {
return null;
}
+ /**
+ * Register a callback for lock wallpaper observation. Only the OS may use this.
+ *
+ * @return true on success; false on error.
+ * @hide
+ */
+ public boolean setLockWallpaperCallback(IWallpaperManagerCallback callback) {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return false;
+ }
+
+ try {
+ return sGlobals.mService.setLockWallpaperCallback(callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to contact wallpaper service");
+ }
+ return false;
+ }
+
// Private completion callback for setWallpaper() synchronization
private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
final CountDownLatch mLatch;
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 4e9adf09c351..1de1d2fbb822 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -240,7 +240,7 @@ public final class DeviceAdminInfo implements Parcelable {
/**
* The BroadcastReceiver that implements this device admin component.
*/
- final ResolveInfo mReceiver;
+ final ActivityInfo mActivityInfo;
/**
* Whether this should be visible to the user.
@@ -252,29 +252,42 @@ public final class DeviceAdminInfo implements Parcelable {
*/
int mUsesPolicies;
+
+ /**
+ * Constructor.
+ *
+ * @param context The Context in which we are parsing the device admin.
+ * @param resolveInfo The ResolveInfo returned from the package manager about
+ * this device admin's component.
+ */
+ public DeviceAdminInfo(Context context, ResolveInfo resolveInfo)
+ throws XmlPullParserException, IOException {
+ this(context, resolveInfo.activityInfo);
+ }
/**
* Constructor.
*
* @param context The Context in which we are parsing the device admin.
- * @param receiver The ResolveInfo returned from the package manager about
+ * @param activityInfo The ActivityInfo returned from the package manager about
* this device admin's component.
+ *
+ * @hide
*/
- public DeviceAdminInfo(Context context, ResolveInfo receiver)
+ public DeviceAdminInfo(Context context, ActivityInfo activityInfo)
throws XmlPullParserException, IOException {
- mReceiver = receiver;
- ActivityInfo ai = receiver.activityInfo;
+ mActivityInfo = activityInfo;
PackageManager pm = context.getPackageManager();
XmlResourceParser parser = null;
try {
- parser = ai.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
+ parser = mActivityInfo.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
if (parser == null) {
throw new XmlPullParserException("No "
+ DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
}
- Resources res = pm.getResourcesForApplication(ai.applicationInfo);
+ Resources res = pm.getResourcesForApplication(mActivityInfo.applicationInfo);
AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -324,14 +337,14 @@ public final class DeviceAdminInfo implements Parcelable {
}
} catch (NameNotFoundException e) {
throw new XmlPullParserException(
- "Unable to create context for: " + ai.packageName);
+ "Unable to create context for: " + mActivityInfo.packageName);
} finally {
if (parser != null) parser.close();
}
}
DeviceAdminInfo(Parcel source) {
- mReceiver = ResolveInfo.CREATOR.createFromParcel(source);
+ mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source);
mUsesPolicies = source.readInt();
}
@@ -339,7 +352,7 @@ public final class DeviceAdminInfo implements Parcelable {
* Return the .apk package that implements this device admin.
*/
public String getPackageName() {
- return mReceiver.activityInfo.packageName;
+ return mActivityInfo.packageName;
}
/**
@@ -347,7 +360,7 @@ public final class DeviceAdminInfo implements Parcelable {
* this device admin.
*/
public String getReceiverName() {
- return mReceiver.activityInfo.name;
+ return mActivityInfo.name;
}
/**
@@ -355,7 +368,7 @@ public final class DeviceAdminInfo implements Parcelable {
* device admin. Do not modify the returned object.
*/
public ActivityInfo getActivityInfo() {
- return mReceiver.activityInfo;
+ return mActivityInfo;
}
/**
@@ -363,8 +376,8 @@ public final class DeviceAdminInfo implements Parcelable {
*/
@NonNull
public ComponentName getComponent() {
- return new ComponentName(mReceiver.activityInfo.packageName,
- mReceiver.activityInfo.name);
+ return new ComponentName(mActivityInfo.packageName,
+ mActivityInfo.name);
}
/**
@@ -374,7 +387,7 @@ public final class DeviceAdminInfo implements Parcelable {
* resources.
*/
public CharSequence loadLabel(PackageManager pm) {
- return mReceiver.loadLabel(pm);
+ return mActivityInfo.loadLabel(pm);
}
/**
@@ -384,15 +397,9 @@ public final class DeviceAdminInfo implements Parcelable {
* resources.
*/
public CharSequence loadDescription(PackageManager pm) throws NotFoundException {
- if (mReceiver.activityInfo.descriptionRes != 0) {
- String packageName = mReceiver.resolvePackageName;
- ApplicationInfo applicationInfo = null;
- if (packageName == null) {
- packageName = mReceiver.activityInfo.packageName;
- applicationInfo = mReceiver.activityInfo.applicationInfo;
- }
- return pm.getText(packageName,
- mReceiver.activityInfo.descriptionRes, applicationInfo);
+ if (mActivityInfo.descriptionRes != 0) {
+ return pm.getText(mActivityInfo.packageName,
+ mActivityInfo.descriptionRes, mActivityInfo.applicationInfo);
}
throw new NotFoundException();
}
@@ -404,7 +411,7 @@ public final class DeviceAdminInfo implements Parcelable {
* resources.
*/
public Drawable loadIcon(PackageManager pm) {
- return mReceiver.loadIcon(pm);
+ return mActivityInfo.loadIcon(pm);
}
/**
@@ -464,12 +471,12 @@ public final class DeviceAdminInfo implements Parcelable {
public void dump(Printer pw, String prefix) {
pw.println(prefix + "Receiver:");
- mReceiver.dump(pw, prefix + " ");
+ mActivityInfo.dump(pw, prefix + " ");
}
@Override
public String toString() {
- return "DeviceAdminInfo{" + mReceiver.activityInfo.name + "}";
+ return "DeviceAdminInfo{" + mActivityInfo.name + "}";
}
/**
@@ -479,7 +486,7 @@ public final class DeviceAdminInfo implements Parcelable {
* @param flags The flags used for parceling.
*/
public void writeToParcel(Parcel dest, int flags) {
- mReceiver.writeToParcel(dest, flags);
+ mActivityInfo.writeToParcel(dest, flags);
dest.writeInt(mUsesPolicies);
}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 34dfb26ba33e..a34e8551ed4b 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -117,8 +117,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
= "android.app.action.DEVICE_ADMIN_DISABLED";
/**
- * Action sent to a device administrator when the user has changed the
- * password of their device. You can at this point check the characteristics
+ * Action sent to a device administrator when the user has changed the password of their device
+ * or profile challenge. You can at this point check the characteristics
* of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
* DevicePolicyManager.isActivePasswordSufficient()}.
* You will generally
@@ -133,8 +133,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
= "android.app.action.ACTION_PASSWORD_CHANGED";
/**
- * Action sent to a device administrator when the user has failed at
- * attempted to enter the password. You can at this point check the
+ * Action sent to a device administrator when the user has entered an incorrect device
+ * or profile challenge password. You can at this point check the
* number of failed password attempts there have been with
* {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
* DevicePolicyManager.getCurrentFailedPasswordAttempts()}. You will generally
@@ -149,8 +149,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
= "android.app.action.ACTION_PASSWORD_FAILED";
/**
- * Action sent to a device administrator when the user has successfully
- * entered their password, after failing one or more times.
+ * Action sent to a device administrator when the user has successfully entered their device
+ * or profile challenge password, after failing one or more times. You will generally
+ * handle this in {@link DeviceAdminReceiver#onPasswordSucceeded}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
@@ -161,8 +162,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
= "android.app.action.ACTION_PASSWORD_SUCCEEDED";
/**
- * Action periodically sent to a device administrator when the device password
- * is expiring.
+ * Action periodically sent to a device administrator when the device or profile challenge
+ * password is expiring. You will generally
+ * handle this in {@link DeviceAdminReceiver#onPasswordExpiring}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to receive
@@ -381,8 +383,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
*
* <p> If the admin is activated by a device owner, then the intent
* may contain private extras that are relevant to user setup.
- * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
- * ComponentName, Intent)}
+ * {@see DevicePolicyManager#createAndManageUser(ComponentName, String, ComponentName,
+ * PersistableBundle, int)}
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
@@ -417,7 +419,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
- * Called after the user has changed their password, as a result of
+ * Called after the user has changed their device or profile challenge password, as a result of
* receiving {@link #ACTION_PASSWORD_CHANGED}. At this point you
* can use {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
* to retrieve the active password characteristics.
@@ -428,10 +430,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
- * Called after the user has failed at entering their current password, as a result of
- * receiving {@link #ACTION_PASSWORD_FAILED}. At this point you
- * can use {@link DevicePolicyManager} to retrieve the number of failed
- * password attempts.
+ * Called after the user has failed at entering their device or profile challenge password,
+ * as a result of receiving {@link #ACTION_PASSWORD_FAILED}. At this point you can use
+ * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()} to retrieve the number of
+ * failed password attempts.
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
*/
@@ -439,7 +441,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
- * Called after the user has succeeded at entering their current password,
+ * Called after the user has succeeded at entering their device or profile challenge password,
* as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}. This will
* only be received the first time they succeed after having previously
* failed.
@@ -450,9 +452,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
- * Called periodically when the password is about to expire or has expired. It will typically
- * be called at these times: on device boot, once per day before the password expires,
- * and at the time when the password expires.
+ * Called periodically when the device or profile challenge password is about to expire
+ * or has expired. It will typically be called at these times: on device boot, once per day
+ * before the password expires, and at the time when the password expires.
*
* <p>If the password is not updated by the user, this method will continue to be called
* once per day until the password is changed or the device admin disables password expiration.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 02eb115175fd..74fe13ac1961 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,12 +16,14 @@
package android.app.admin;
+import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
import android.app.Activity;
import android.auditing.SecurityLog;
import android.auditing.SecurityLog.SecurityEvent;
@@ -339,6 +341,7 @@ public class DevicePolicyManager {
*
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PROVISION_FINALIZATION
= "android.app.action.PROVISION_FINALIZATION";
@@ -847,6 +850,8 @@ public class DevicePolicyManager {
* this will trigger entering a new password for the parent of the profile.
* For all other cases it will trigger entering a new password for the user
* or profile it is launched from.
+ *
+ * @see #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SET_NEW_PASSWORD
@@ -928,30 +933,35 @@ public class DevicePolicyManager {
* No management for current user in-effect. This is the default.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_UNMANAGED = 0;
/**
* Management partially setup, user setup needs to be completed.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_SETUP_INCOMPLETE = 1;
/**
* Management partially setup, user setup completed.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_SETUP_COMPLETE = 2;
/**
* Management setup and active on current user.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_SETUP_FINALIZED = 3;
/**
* Management partially setup on a managed profile.
* @hide
*/
+ @SystemApi
public static final int STATE_USER_PROFILE_COMPLETE = 4;
/**
@@ -1031,9 +1041,18 @@ public class DevicePolicyManager {
* @hide
*/
public boolean packageHasActiveAdmins(String packageName) {
+ return packageHasActiveAdmins(packageName, myUserId());
+ }
+
+ /**
+ * Used by package administration code to determine if a package can be stopped
+ * or uninstalled.
+ * @hide
+ */
+ public boolean packageHasActiveAdmins(String packageName, int userId) {
if (mService != null) {
try {
- return mService.packageHasActiveAdmins(packageName, myUserId());
+ return mService.packageHasActiveAdmins(packageName, userId);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -1046,6 +1065,9 @@ public class DevicePolicyManager {
* by the application that owns the administration component; if you
* try to remove someone else's component, a security exception will be
* thrown.
+ *
+ * <p>Note that the operation is not synchronous and the admin might still be active (as
+ * indicated by {@link #getActiveAdmins()}) by the time this method returns.
*/
public void removeActiveAdmin(@NonNull ComponentName admin) {
if (mService != null) {
@@ -1177,7 +1199,8 @@ public class DevicePolicyManager {
* restrictive as what has been set. Note that the current password
* will remain until the user has set a new one, so the change does not
* take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after calling this method.
*
* <p>Quality constants are ordered so that higher values are more restrictive;
* thus the highest requested quality constant (between the policy set here,
@@ -1188,6 +1211,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param quality The new desired quality. One of
* {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
@@ -1206,8 +1233,14 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current minimum password quality for all admins of this user
- * and its profiles or a particular one.
+ * Retrieve the current minimum password quality for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
*/
@@ -1234,7 +1267,8 @@ public class DevicePolicyManager {
* restrictive as what has been set. Note that the current password
* will remain until the user has set a new one, so the change does not
* take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested either
* {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX},
* {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC},
@@ -1244,6 +1278,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param length The new desired minimum password length. A value of 0
* means there is no restriction.
@@ -1259,7 +1297,14 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current minimum password length for all admins of this
+ * Retrieve the current minimum password length for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* user and its profiles or a particular one.
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
@@ -1287,7 +1332,8 @@ public class DevicePolicyManager {
* not at least as restrictive as what has been set. Note that the current
* password will remain until the user has set a new one, so the change does
* not take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 0.
@@ -1296,6 +1342,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of upper case letters
@@ -1313,13 +1363,19 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current number of upper case letters required in the
- * password for all admins of this user and its profiles or a particular one.
+ * Retrieve the current number of upper case letters required in the password
+ * for a particular admin or all admins that set retrictions on this user and
+ * its participating profiles. Restrictions on profiles that have a separate challenge
+ * are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
+ * {@link #setPasswordMinimumUpperCase(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of upper case letters required in the
@@ -1348,7 +1404,8 @@ public class DevicePolicyManager {
* not at least as restrictive as what has been set. Note that the current
* password will remain until the user has set a new one, so the change does
* not take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 0.
@@ -1357,6 +1414,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of lower case letters
@@ -1374,13 +1435,19 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current number of lower case letters required in the
- * password for all admins of this user and its profiles or a particular one.
+ * Retrieve the current number of lower case letters required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
+ * {@link #setPasswordMinimumLowerCase(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of lower case letters required in the
@@ -1409,7 +1476,8 @@ public class DevicePolicyManager {
* restrictive as what has been set. Note that the current password will
* remain until the user has set a new one, so the change does not take
* place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 1.
@@ -1418,6 +1486,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of letters required in the
@@ -1434,12 +1506,19 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current number of letters required in the password for all
- * admins or a particular one. This is the same value as
- * set by {#link {@link #setPasswordMinimumLetters(ComponentName, int)}
+ * Retrieve the current number of letters required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ * This is the same value as set by
+ * {@link #setPasswordMinimumLetters(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of letters required in the password.
@@ -1467,7 +1546,8 @@ public class DevicePolicyManager {
* not at least as restrictive as what has been set. Note that the current
* password will remain until the user has set a new one, so the change does
* not take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 1.
@@ -1476,6 +1556,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of numerical digits required
@@ -1493,12 +1577,18 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of numerical digits required in the password
- * for all admins of this user and its profiles or a particular one.
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
+ * {@link #setPasswordMinimumNumeric(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of numerical digits required in the password.
@@ -1526,7 +1616,8 @@ public class DevicePolicyManager {
* restrictive as what has been set. Note that the current password will
* remain until the user has set a new one, so the change does not take
* place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 1.
@@ -1535,6 +1626,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of symbols required in the
@@ -1551,12 +1646,18 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current number of symbols required in the password for all
- * admins or a particular one. This is the same value as
- * set by {#link {@link #setPasswordMinimumSymbols(ComponentName, int)}
+ * Retrieve the current number of symbols required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account. This is the same value as
+ * set by {@link #setPasswordMinimumSymbols(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of symbols required in the password.
@@ -1584,7 +1685,8 @@ public class DevicePolicyManager {
* to enter a new password that is not at least as restrictive as what has
* been set. Note that the current password will remain until the user has
* set a new one, so the change does not take place immediately. To prompt
- * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} after
+ * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
* setting this value. This constraint is only imposed if the administrator
* has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
* {@link #setPasswordQuality}. The default value is 0.
@@ -1593,6 +1695,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of letters required in the
@@ -1609,13 +1715,19 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current number of non-letter characters required in the
- * password for all admins of this user and its profiles or a particular one.
+ * Retrieve the current number of non-letter characters required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
+ * {@link #setPasswordMinimumNonLetter(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of letters required in the password.
@@ -1642,7 +1754,8 @@ public class DevicePolicyManager {
* enter a new password that is the same as any password in the history. Note
* that the current password will remain until the user has set a new one, so
* the change does not take place immediately. To prompt the user for a new
- * password, use {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+ * password, use {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value.
* This constraint is only imposed if the administrator has also requested
* either {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}
* {@link #PASSWORD_QUALITY_ALPHABETIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
@@ -1653,6 +1766,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this
* method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired length of password history. A value of 0
@@ -1686,6 +1803,10 @@ public class DevicePolicyManager {
* <p> Note that setting the password will automatically reset the expiration time for all
* active admins. Active admins do not need to explicitly call this method in that case.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeout The limit (in ms) that a password can remain in effect. A value of 0
* means there is no restriction (unlimited).
@@ -1704,7 +1825,12 @@ public class DevicePolicyManager {
* Get the password expiration timeout for the given admin. The expiration timeout is the
* recurring expiration timeout provided in the call to
* {@link #setPasswordExpirationTimeout(ComponentName, long)} for the given admin or the
- * aggregate of all policy administrators if {@code admin} is null.
+ * aggregate of all participating policy administrators if {@code admin} is null. Admins that
+ * have set restrictions on profiles that have a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
*
* @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
* @return The timeout for the given admin or the minimum of all timeouts
@@ -1721,14 +1847,17 @@ public class DevicePolicyManager {
}
/**
- * Get the current password expiration time for the given admin or an aggregate of
- * all admins of this user and its profiles if admin is null. If the password is
- * expired, this will return the time since the password expired as a negative number.
- * If admin is null, then a composite of all expiration timeouts is returned
- * - which will be the minimum of all timeouts.
+ * Get the current password expiration time for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account. If admin is {@code null}, then a composite
+ * of all expiration times is returned - which will be the minimum of all of them.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * the password expiration for the parent profile.
*
* @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
- * @return The password expiration time, in ms.
+ * @return The password expiration time, in milliseconds since epoch.
*/
public long getPasswordExpiration(@Nullable ComponentName admin) {
if (mService != null) {
@@ -1742,8 +1871,14 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current password history length for all admins of this
- * user and its profiles or a particular one.
+ * Retrieve the current password history length for a particular admin or all admins that
+ * set retrictions on this user and its participating profiles. Restrictions on profiles that
+ * have a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
* @return The length of the password history
@@ -1777,13 +1912,18 @@ public class DevicePolicyManager {
/**
* Determine whether the current password the user has set is sufficient
- * to meet the policy requirements (quality, minimum length) that have been
- * requested by the admins of this user and its profiles that don't have a separate challenge.
+ * to meet the policy requirements (e.g. quality, minimum length) that have been
+ * requested by the admins of this user and its participating profiles.
+ * Restrictions on profiles that have a separate challenge are not taken into account.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to determine
+ * if the password set on the parent profile is sufficient.
+ *
* @return Returns true if the password meets the current requirements, else false.
*/
public boolean isActivePasswordSufficient() {
@@ -1799,7 +1939,7 @@ public class DevicePolicyManager {
/**
* Determine whether the current profile password the user has set is sufficient
- * to meet the policy requirements (quality, minimum length) that have been
+ * to meet the policy requirements (e.g. quality, minimum length) that have been
* requested by the admins of the parent user and its profiles.
*
* @param userHandle the userId of the profile to check the password for.
@@ -1821,14 +1961,32 @@ public class DevicePolicyManager {
* Retrieve the number of times the user has failed at entering a
* password since that last successful password entry.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * the number of failed password attemts for the parent user.
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call
* this method; if it has not, a security exception will be thrown.
*/
public int getCurrentFailedPasswordAttempts() {
+ return getCurrentFailedPasswordAttempts(myUserId());
+ }
+
+ /**
+ * Retrieve the number of times the given user has failed at entering a
+ * password since that last successful password entry.
+ *
+ * <p>The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call this method; if it has
+ * not and it is not the system uid, a security exception will be thrown.
+ *
+ * @hide
+ */
+ public int getCurrentFailedPasswordAttempts(int userHandle) {
if (mService != null) {
try {
- return mService.getCurrentFailedPasswordAttempts(myUserId(), mParentInstance);
+ return mService.getCurrentFailedPasswordAttempts(userHandle, mParentInstance);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -1855,7 +2013,7 @@ public class DevicePolicyManager {
/**
* Setting this to a value greater than zero enables a built-in policy
- * that will perform a device wipe after too many incorrect
+ * that will perform a device or profile wipe after too many incorrect
* device-unlock passwords have been entered. This built-in policy combines
* watching for failed passwords and wiping the device, and requires
* that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
@@ -1866,11 +2024,15 @@ public class DevicePolicyManager {
* failure to a server), you should implement
* {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)}
* instead. Do not use this API, because if the maximum count is reached,
- * the device will be wiped immediately, and your callback will not be invoked.
+ * the device or profile will be wiped immediately, and your callback will not be invoked.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * a value on the parent profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param num The number of failed password attempts at which point the
- * device will wipe its data.
+ * device or profile will be wiped.
*/
public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
if (mService != null) {
@@ -1883,9 +2045,15 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current maximum number of login attempts that are allowed
- * before the device wipes itself, for all admins of this user and its profiles
- * or a particular one.
+ * Retrieve the current maximum number of login attempts that are allowed before the device
+ * or profile is wiped, for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have a separate challenge are
+ * not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * the value for the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
*/
@@ -2002,6 +2170,10 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeMs The new desired maximum time to lock in milliseconds.
* A value of 0 means there is no restriction.
@@ -2017,8 +2189,14 @@ public class DevicePolicyManager {
}
/**
- * Retrieve the current maximum time to unlock for all admins of this user
- * and its profiles or a particular one.
+ * Retrieve the current maximum time to unlock for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
* @return time in milliseconds for the given admin or the minimum value (strictest) of
@@ -2047,6 +2225,10 @@ public class DevicePolicyManager {
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
* this method; if it has not, a security exception will be thrown.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to lock
+ * the parent profile.
*/
public void lockNow() {
if (mService != null) {
@@ -2504,8 +2686,16 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner to install a certificate and private key pair. The
- * keypair will be visible to all apps within the profile.
+ * Called by a device or profile owner, or delegated certificate installer, to install a
+ * certificate and corresponding private key. All apps within the profile will be able to access
+ * the certificate and use the private key, given direct user approval.
+ *
+ * <p>Access to the installed credentials will not be granted to the caller of this API without
+ * direct user approval. This is for security - should a certificate installer become
+ * compromised, certificates it had already installed will be protected.
+ *
+ * <p>If the installer must have access to the credentials, call
+ * {@link #installKeyPair(ComponentName, PrivateKey, Certificate, String, boolean)} instead.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
@@ -2517,11 +2707,35 @@ public class DevicePolicyManager {
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate cert, @NonNull String alias) {
+ return installKeyPair(admin, privKey, cert, alias, false);
+ }
+
+ /**
+ * Called by a device or profile owner, or delegated certificate installer, to install a
+ * certificate and corresponding private key. All apps within the profile will be able to access
+ * the certificate and use the private key, given direct user approval.
+ *
+ * <p>The caller of this API may grant itself access to the credential immediately, without user
+ * approval. It is a best practice not to request this unless strictly necessary since it opens
+ * up additional security vulnerabilities.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if calling from a delegated certificate installer.
+ * @param privKey The private key to install.
+ * @param cert The certificate to install.
+ * @param alias The private key alias under which to install the certificate. If a certificate
+ * with that alias already exists, it will be overwritten.
+ * @param requestAccess {@code true} to request that the calling app be granted access to the
+ * credentials immediately. Otherwise, access to the credentials will be gated by user approval.
+ * @return {@code true} if the keys were installed, {@code false} otherwise.
+ */
+ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
+ @NonNull Certificate cert, @NonNull String alias, boolean requestAccess) {
try {
final byte[] pemCert = Credentials.convertToPem(cert);
final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
.getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
- return mService.installKeyPair(admin, pkcs8Key, pemCert, alias);
+ return mService.installKeyPair(admin, pkcs8Key, pemCert, alias, requestAccess);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
@@ -2533,8 +2747,8 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner to remove all user credentials installed under a given
- * alias.
+ * Called by a device or profile owner, or delegated certificate installer, to remove all user
+ * credentials installed under a given alias.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
@@ -2545,7 +2759,7 @@ public class DevicePolicyManager {
try {
return mService.removeKeyPair(admin, alias);
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
return false;
}
@@ -2570,6 +2784,11 @@ public class DevicePolicyManager {
* Delegated certificate installer is a per-user state. The delegated access is persistent until
* it is later cleared by calling this method with a null value or uninstallling the certificate
* installer.
+ *<p>
+ * <b>Note:</b>Starting from {@link android.os.Build.VERSION_CODES#N}, if the caller
+ * application's target SDK version is {@link android.os.Build.VERSION_CODES#N} or newer, the
+ * supplied certificate installer package must be installed when calling this API,
+ * otherwise an {@link IllegalArgumentException} will be thrown.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param installerPackage The package name of the certificate installer which will be given
@@ -2863,17 +3082,25 @@ public class DevicePolicyManager {
* this method; if it has not, a security exception will be thrown.
*
* <p>Calling this from a managed profile before version
- * {@link android.os.Build.VERSION_CODES#M} will throw a security exception.
- *
- * <p>From version {@link android.os.Build.VERSION_CODES#M} a profile owner can set:
+ * {@link android.os.Build.VERSION_CODES#M} will throw a security exception. From version
+ * {@link android.os.Build.VERSION_CODES#M} the profile owner of a managed profile can set:
* <ul>
- * <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}
- * these will affect the profile's parent user.
- * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} this will affect notifications
- * generated by applications in the managed profile.
+ * <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which affects the parent user, but only if there
+ * is no separate challenge set on the managed profile.
+ * <li>{@link #KEYGUARD_DISABLE_FINGERPRINT} which affects the managed profile challenge if
+ * there is one, or the parent user otherwise.
+ * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} which affects notifications
+ * generated by applications in the managed profile.
* </ul>
- * <p>Requests to disable other features on a managed profile will be ignored. The admin
- * can check which features have been disabled by calling
+ *
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} and {@link #KEYGUARD_DISABLE_FINGERPRINT} can also be
+ * set on the {@link DevicePolicyManager} instance returned by
+ * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the
+ * parent profile.
+ *
+ * <p>Requests to disable other features on a managed profile will be ignored.
+ *
+ * <p>The admin can check which features have been disabled by calling
* {@link #getKeyguardDisabledFeatures(ComponentName)}
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -2895,7 +3122,13 @@ public class DevicePolicyManager {
/**
* Determine whether or not features have been disabled in keyguard either by the calling
- * admin, if specified, or all admins.
+ * admin, if specified, or all admins that set retrictions on this user and its participating
+ * profiles. Restrictions on profiles that have a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to check whether any
* admins have disabled features in keyguard.
* @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)}
@@ -2939,31 +3172,6 @@ public class DevicePolicyManager {
}
/**
- * Returns the DeviceAdminInfo as defined by the administrator's package info &amp; meta-data
- * @hide
- */
- public DeviceAdminInfo getAdminInfo(@NonNull ComponentName cn) {
- ActivityInfo ai;
- try {
- ai = mContext.getPackageManager().getReceiverInfo(cn,
- PackageManager.GET_META_DATA);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to retrieve device policy " + cn, e);
- return null;
- }
-
- ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = ai;
-
- try {
- return new DeviceAdminInfo(mContext, ri);
- } catch (XmlPullParserException | IOException e) {
- Log.w(TAG, "Unable to parse device policy " + cn, e);
- return null;
- }
- }
-
- /**
* @hide
*/
public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) {
@@ -3018,13 +3226,39 @@ public class DevicePolicyManager {
}
/**
+ * @hide
+ */
+ public void reportFailedFingerprintAttempt(int userHandle) {
+ if (mService != null) {
+ try {
+ mService.reportFailedFingerprintAttempt(userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void reportSuccessfulFingerprintAttempt(int userHandle) {
+ if (mService != null) {
+ try {
+ mService.reportSuccessfulFingerprintAttempt(userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
* Should be called when keyguard has been dismissed.
* @hide
*/
- public void reportKeyguardDismissed() {
+ public void reportKeyguardDismissed(int userHandle) {
if (mService != null) {
try {
- mService.reportKeyguardDismissed();
+ mService.reportKeyguardDismissed(userHandle);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -3035,10 +3269,10 @@ public class DevicePolicyManager {
* Should be called when keyguard view has been shown to the user.
* @hide
*/
- public void reportKeyguardSecured() {
+ public void reportKeyguardSecured(int userHandle) {
if (mService != null) {
try {
- mService.reportKeyguardSecured();
+ mService.reportKeyguardSecured(userHandle);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -3425,27 +3659,31 @@ public class DevicePolicyManager {
}
/**
- * Called by device or profile owners for setting the package suspended for this user.
- * A suspended package will not be started by the package manager, its notifications will
- * be hidden and it will not show up in recents. The package must already be installed.
+ * Called by device or profile owners to suspend packages for this user.
+ *
+ * <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 device.
+ *
+ * <p>The package must already be installed.
*
* @param admin The name of the admin component to check.
- * @param packageName The package name of the app to suspend or unsuspend.
- * @param suspended If set to {@code true} than the package will be suspended, if set to
- * {@code false} the package will be unsuspended.
- * @return boolean {@code true} if the operation was successfully performed, {@code false}
- * otherwise.
+ * @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.
*/
- public boolean setPackageSuspended(@NonNull ComponentName admin, String packageName,
+ public String[] setPackagesSuspended(@NonNull ComponentName admin, String[] packageNames,
boolean suspended) {
if (mService != null) {
try {
- return mService.setPackageSuspended(admin, packageName, suspended);
+ return mService.setPackagesSuspended(admin, packageNames, suspended);
} catch (RemoteException re) {
- Log.w(TAG, "Failed talking with device policy service", re);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
}
}
- return false;
+ return packageNames;
}
/**
@@ -3453,14 +3691,15 @@ public class DevicePolicyManager {
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The name of the package to retrieve the suspended status of.
- * @return boolean {@code true} if the package is suspended, {@code false} otherwise.
+ * @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.
*/
public boolean getPackageSuspended(@NonNull ComponentName admin, String packageName) {
if (mService != null) {
try {
return mService.getPackageSuspended(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
}
return false;
@@ -3650,6 +3889,9 @@ public class DevicePolicyManager {
* <p>
* This permission is persistent until it is later cleared by calling this method with a
* {@code null} value or uninstalling the managing package.
+ * <p>
+ * The supplied application restriction managing package must be installed when calling this
+ * API, otherwise an {@link IllegalArgumentException} will be thrown.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The package name which will be given access to application restrictions
@@ -4310,14 +4552,10 @@ public class DevicePolicyManager {
* user could not be created.
*
* @deprecated From {@link android.os.Build.VERSION_CODES#M}
+ * @removed From {@link android.os.Build.VERSION_CODES#N}
*/
@Deprecated
public UserHandle createUser(@NonNull ComponentName admin, String name) {
- try {
- return mService.createUser(admin, name);
- } catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- }
return null;
}
@@ -4347,16 +4585,11 @@ public class DevicePolicyManager {
* user could not be created.
*
* @deprecated From {@link android.os.Build.VERSION_CODES#M}
+ * @removed From {@link android.os.Build.VERSION_CODES#N}
*/
@Deprecated
public UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name,
String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) {
- try {
- return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
- adminExtras);
- } catch (RemoteException re) {
- Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
- }
return null;
}
@@ -5564,6 +5797,25 @@ public class DevicePolicyManager {
}
/**
+ * @hide
+ *
+ * Sets the color used for customization.
+ *
+ * @param color The 32bit representation of the color to be used.
+ * @param userId which user to set the color to.
+ * @RequiresPermission(allOf = {
+ * Manifest.permission.MANAGE_USERS,
+ * Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ */
+ public void setOrganizationColorForUser(@ColorInt int color, @UserIdInt int userId) {
+ try {
+ mService.setOrganizationColorForUser(color, userId);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ }
+ }
+
+ /**
* Called by a profile owner of a managed profile to retrieve the color used for customization.
* This color is used as background color of the confirm credentials screen for that user.
*
@@ -5652,6 +5904,7 @@ public class DevicePolicyManager {
* return {@link #STATE_USER_UNMANAGED}
* @hide
*/
+ @SystemApi
@UserProvisioningState
public int getUserProvisioningState() {
if (mService != null) {
@@ -5703,7 +5956,7 @@ public class DevicePolicyManager {
try {
mService.setAffiliationIds(admin, new ArrayList<String>(ids));
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
}
@@ -5718,8 +5971,36 @@ public class DevicePolicyManager {
try {
return mService != null && mService.isAffiliatedUser();
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ * Returns whether the uninstall for {@code packageName} for the current user is in queue
+ * to be started
+ * @param packageName the package to check for
+ * @return whether the uninstall intent for {@code packageName} is pending
+ */
+ public boolean isUninstallInQueue(String packageName) {
+ try {
+ return mService.isUninstallInQueue(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
return false;
}
}
+
+ /**
+ * @hide
+ * @param packageName the package containing active DAs to be uninstalled
+ */
+ public void uninstallPackageWithActiveAdmins(String packageName) {
+ try {
+ mService.uninstallPackageWithActiveAdmins(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c6a53443b51c..b7a16aa0dc07 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -116,9 +116,10 @@ interface IDevicePolicyManager {
int numbers, int symbols, int nonletter, int userHandle);
void reportFailedPasswordAttempt(int userHandle);
void reportSuccessfulPasswordAttempt(int userHandle);
-
- void reportKeyguardDismissed();
- void reportKeyguardSecured();
+ void reportFailedFingerprintAttempt(int userHandle);
+ void reportSuccessfulFingerprintAttempt(int userHandle);
+ void reportKeyguardDismissed(int userHandle);
+ void reportKeyguardSecured(int userHandle);
boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
@@ -137,14 +138,15 @@ interface IDevicePolicyManager {
boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
String getDeviceOwnerLockScreenInfo();
- boolean setPackageSuspended(in ComponentName admin, String packageName, boolean suspended);
+ String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
boolean getPackageSuspended(in ComponentName admin, String packageName);
boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, in String[] aliases);
void enforceCanManageCaCerts(in ComponentName admin);
- boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias);
+ boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer,
+ String alias, boolean requestAccess);
boolean removeKeyPair(in ComponentName who, String alias);
void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);
@@ -184,8 +186,6 @@ interface IDevicePolicyManager {
boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden);
boolean isApplicationHidden(in ComponentName admin, in String packageName);
- UserHandle createUser(in ComponentName who, in String name);
- UserHandle createAndInitializeUser(in ComponentName who, in String name, in String profileOwnerName, in ComponentName profileOwnerComponent, in Bundle adminExtras);
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);
@@ -276,6 +276,7 @@ interface IDevicePolicyManager {
boolean isSeparateProfileChallengeAllowed(int userHandle);
void setOrganizationColor(in ComponentName admin, in int color);
+ void setOrganizationColorForUser(in int color, in int userId);
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
@@ -293,4 +294,7 @@ interface IDevicePolicyManager {
boolean getDeviceLoggingEnabled(in ComponentName admin);
ParceledListSlice retrieveDeviceLogs(in ComponentName admin);
ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin);
+
+ boolean isUninstallInQueue(String packageName);
+ void uninstallPackageWithActiveAdmins(String packageName);
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 63f142552c28..aeb315611686 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -308,14 +308,31 @@ public abstract class BackupAgent extends ContextWrapper {
final String packageName = getPackageName();
final ApplicationInfo appInfo = getApplicationInfo();
- String rootDir = new File(appInfo.dataDir).getCanonicalPath();
- String filesDir = getFilesDir().getCanonicalPath();
- String nobackupDir = getNoBackupFilesDir().getCanonicalPath();
- String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
- String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
- String cacheDir = getCacheDir().getCanonicalPath();
- String codeCacheDir = getCodeCacheDir().getCanonicalPath();
- String libDir = (appInfo.nativeLibraryDir != null)
+ // System apps have control over where their default storage context
+ // is pointed, so we're always explicit when building paths.
+ final Context ceContext = createCredentialEncryptedStorageContext();
+ final String rootDir = ceContext.getDataDir().getCanonicalPath();
+ final String filesDir = ceContext.getFilesDir().getCanonicalPath();
+ final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
+ final String databaseDir = ceContext.getDatabasePath("foo").getParentFile()
+ .getCanonicalPath();
+ final String sharedPrefsDir = ceContext.getSharedPreferencesPath("foo").getParentFile()
+ .getCanonicalPath();
+ final String cacheDir = ceContext.getCacheDir().getCanonicalPath();
+ final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
+
+ final Context deContext = createDeviceEncryptedStorageContext();
+ final String deviceRootDir = deContext.getDataDir().getCanonicalPath();
+ final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
+ final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath();
+ final String deviceDatabaseDir = deContext.getDatabasePath("foo").getParentFile()
+ .getCanonicalPath();
+ final String deviceSharedPrefsDir = deContext.getSharedPreferencesPath("foo")
+ .getParentFile().getCanonicalPath();
+ final String deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
+ final String deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
+
+ final String libDir = (appInfo.nativeLibraryDir != null)
? new File(appInfo.nativeLibraryDir).getCanonicalPath()
: null;
@@ -325,30 +342,48 @@ public abstract class BackupAgent extends ContextWrapper {
final ArraySet<String> traversalExcludeSet = new ArraySet<String>();
// Add the directories we always exclude.
+ traversalExcludeSet.add(filesDir);
+ traversalExcludeSet.add(noBackupDir);
+ traversalExcludeSet.add(databaseDir);
+ traversalExcludeSet.add(sharedPrefsDir);
traversalExcludeSet.add(cacheDir);
traversalExcludeSet.add(codeCacheDir);
- traversalExcludeSet.add(nobackupDir);
+
+ traversalExcludeSet.add(deviceFilesDir);
+ traversalExcludeSet.add(deviceNoBackupDir);
+ traversalExcludeSet.add(deviceDatabaseDir);
+ traversalExcludeSet.add(deviceSharedPrefsDir);
+ traversalExcludeSet.add(deviceCacheDir);
+ traversalExcludeSet.add(deviceCodeCacheDir);
+
if (libDir != null) {
traversalExcludeSet.add(libDir);
}
- traversalExcludeSet.add(databaseDir);
- traversalExcludeSet.add(sharedPrefsDir);
- traversalExcludeSet.add(filesDir);
-
// Root dir first.
applyXmlFiltersAndDoFullBackupForDomain(
packageName, FullBackup.ROOT_TREE_TOKEN, manifestIncludeMap,
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(rootDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_ROOT_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceRootDir);
+
// Data dir next.
traversalExcludeSet.remove(filesDir);
applyXmlFiltersAndDoFullBackupForDomain(
- packageName, FullBackup.DATA_TREE_TOKEN, manifestIncludeMap,
+ packageName, FullBackup.FILES_TREE_TOKEN, manifestIncludeMap,
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(filesDir);
+ traversalExcludeSet.remove(deviceFilesDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_FILES_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceFilesDir);
+
// Database directory.
traversalExcludeSet.remove(databaseDir);
applyXmlFiltersAndDoFullBackupForDomain(
@@ -356,6 +391,12 @@ public abstract class BackupAgent extends ContextWrapper {
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(databaseDir);
+ traversalExcludeSet.remove(deviceDatabaseDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_DATABASE_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceDatabaseDir);
+
// SharedPrefs.
traversalExcludeSet.remove(sharedPrefsDir);
applyXmlFiltersAndDoFullBackupForDomain(
@@ -363,6 +404,12 @@ public abstract class BackupAgent extends ContextWrapper {
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(sharedPrefsDir);
+ traversalExcludeSet.remove(deviceSharedPrefsDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceSharedPrefsDir);
+
// getExternalFilesDir() location associated with this app. Technically there should
// not be any files here if the app does not properly have permission to access
// external storage, but edge cases happen. fullBackupFileTree() catches
@@ -445,27 +492,49 @@ public abstract class BackupAgent extends ContextWrapper {
*/
public final void fullBackupFile(File file, FullBackupDataOutput output) {
// Look up where all of our various well-defined dir trees live on this device
- String mainDir;
- String filesDir;
- String nbFilesDir;
- String dbDir;
- String spDir;
- String cacheDir;
- String codeCacheDir;
- String libDir;
+ final String rootDir;
+ final String filesDir;
+ final String nbFilesDir;
+ final String dbDir;
+ final String spDir;
+ final String cacheDir;
+ final String codeCacheDir;
+ final String deviceRootDir;
+ final String deviceFilesDir;
+ final String deviceNbFilesDir;
+ final String deviceDbDir;
+ final String deviceSpDir;
+ final String deviceCacheDir;
+ final String deviceCodeCacheDir;
+ final String libDir;
+
String efDir = null;
String filePath;
ApplicationInfo appInfo = getApplicationInfo();
try {
- mainDir = new File(appInfo.dataDir).getCanonicalPath();
- filesDir = getFilesDir().getCanonicalPath();
- nbFilesDir = getNoBackupFilesDir().getCanonicalPath();
- dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
- spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
- cacheDir = getCacheDir().getCanonicalPath();
- codeCacheDir = getCodeCacheDir().getCanonicalPath();
+ // System apps have control over where their default storage context
+ // is pointed, so we're always explicit when building paths.
+ final Context ceContext = createCredentialEncryptedStorageContext();
+ rootDir = ceContext.getDataDir().getCanonicalPath();
+ filesDir = ceContext.getFilesDir().getCanonicalPath();
+ nbFilesDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
+ dbDir = ceContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
+ spDir = ceContext.getSharedPreferencesPath("foo").getParentFile().getCanonicalPath();
+ cacheDir = ceContext.getCacheDir().getCanonicalPath();
+ codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
+
+ final Context deContext = createDeviceEncryptedStorageContext();
+ deviceRootDir = deContext.getDataDir().getCanonicalPath();
+ deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
+ deviceNbFilesDir = deContext.getNoBackupFilesDir().getCanonicalPath();
+ deviceDbDir = deContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
+ deviceSpDir = deContext.getSharedPreferencesPath("foo").getParentFile()
+ .getCanonicalPath();
+ deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
+ deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
+
libDir = (appInfo.nativeLibraryDir == null)
? null
: new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -489,8 +558,11 @@ public abstract class BackupAgent extends ContextWrapper {
if (filePath.startsWith(cacheDir)
|| filePath.startsWith(codeCacheDir)
- || filePath.startsWith(libDir)
- || filePath.startsWith(nbFilesDir)) {
+ || filePath.startsWith(nbFilesDir)
+ || filePath.startsWith(deviceCacheDir)
+ || filePath.startsWith(deviceCodeCacheDir)
+ || filePath.startsWith(deviceNbFilesDir)
+ || filePath.startsWith(libDir)) {
Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
return;
}
@@ -504,11 +576,23 @@ public abstract class BackupAgent extends ContextWrapper {
domain = FullBackup.SHAREDPREFS_TREE_TOKEN;
rootpath = spDir;
} else if (filePath.startsWith(filesDir)) {
- domain = FullBackup.DATA_TREE_TOKEN;
+ domain = FullBackup.FILES_TREE_TOKEN;
rootpath = filesDir;
- } else if (filePath.startsWith(mainDir)) {
+ } else if (filePath.startsWith(rootDir)) {
domain = FullBackup.ROOT_TREE_TOKEN;
- rootpath = mainDir;
+ rootpath = rootDir;
+ } else if (filePath.startsWith(deviceDbDir)) {
+ domain = FullBackup.DEVICE_DATABASE_TREE_TOKEN;
+ rootpath = deviceDbDir;
+ } else if (filePath.startsWith(deviceSpDir)) {
+ domain = FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN;
+ rootpath = deviceSpDir;
+ } else if (filePath.startsWith(deviceFilesDir)) {
+ domain = FullBackup.DEVICE_FILES_TREE_TOKEN;
+ rootpath = deviceFilesDir;
+ } else if (filePath.startsWith(deviceRootDir)) {
+ domain = FullBackup.DEVICE_ROOT_TREE_TOKEN;
+ rootpath = deviceRootDir;
} else if ((efDir != null) && filePath.startsWith(efDir)) {
domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
rootpath = efDir;
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 2268400ed573..7fcca0969f75 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -468,7 +468,7 @@ public class BackupManager {
*
* @param packages List of package names to backup.
* @param observer The {@link BackupObserver} to receive callbacks during the backup
- * operation.
+ * operation. Could be {@code null}.
* @return {@link BackupManager#SUCCESS} on success; nonzero on error.
* @exception IllegalArgumentException on null or empty {@code packages} param.
*
@@ -479,8 +479,9 @@ public class BackupManager {
checkServiceBinder();
if (sService != null) {
try {
- BackupObserverWrapper observerWrapper =
- new BackupObserverWrapper(mContext, observer);
+ BackupObserverWrapper observerWrapper = observer == null
+ ? null
+ : new BackupObserverWrapper(mContext, observer);
return sService.requestBackup(packages, observerWrapper);
} catch (RemoteException e) {
Log.e(TAG, "requestBackup() couldn't connect");
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index ac23b6888dd0..da81d19ca3cb 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -501,7 +501,7 @@ public class BackupTransport {
* @param packageName ID of package to provide the quota.
* @param isFullBackup If set, transport should return limit for full data backup, otherwise
* for key-value backup.
- * @return Current limit on full data backup size in bytes.
+ * @return Current limit on backup size in bytes.
*/
public long getBackupQuota(String packageName, boolean isFullBackup) {
return Long.MAX_VALUE;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 9ea2ba286754..cdc80e3ba3c1 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -55,13 +55,22 @@ public class FullBackup {
public static final String APK_TREE_TOKEN = "a";
public static final String OBB_TREE_TOKEN = "obb";
+
public static final String ROOT_TREE_TOKEN = "r";
- public static final String DATA_TREE_TOKEN = "f";
+ public static final String FILES_TREE_TOKEN = "f";
public static final String NO_BACKUP_TREE_TOKEN = "nb";
public static final String DATABASE_TREE_TOKEN = "db";
public static final String SHAREDPREFS_TREE_TOKEN = "sp";
- public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
public static final String CACHE_TREE_TOKEN = "c";
+
+ public static final String DEVICE_ROOT_TREE_TOKEN = "d_r";
+ public static final String DEVICE_FILES_TREE_TOKEN = "d_f";
+ public static final String DEVICE_NO_BACKUP_TREE_TOKEN = "d_nb";
+ public static final String DEVICE_DATABASE_TREE_TOKEN = "d_db";
+ public static final String DEVICE_SHAREDPREFS_TREE_TOKEN = "d_sp";
+ public static final String DEVICE_CACHE_TREE_TOKEN = "d_c";
+
+ public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
public static final String SHARED_STORAGE_TOKEN = "shared";
public static final String APPS_PREFIX = "apps/";
@@ -201,10 +210,18 @@ public class FullBackup {
private final File DATABASE_DIR;
private final File ROOT_DIR;
private final File SHAREDPREF_DIR;
- private final File EXTERNAL_DIR;
private final File CACHE_DIR;
private final File NOBACKUP_DIR;
+ private final File DEVICE_FILES_DIR;
+ private final File DEVICE_DATABASE_DIR;
+ private final File DEVICE_ROOT_DIR;
+ private final File DEVICE_SHAREDPREF_DIR;
+ private final File DEVICE_CACHE_DIR;
+ private final File DEVICE_NOBACKUP_DIR;
+
+ private final File EXTERNAL_DIR;
+
final int mFullBackupContent;
final PackageManager mPackageManager;
final String mPackageName;
@@ -214,7 +231,7 @@ public class FullBackup {
*/
String tokenToDirectoryPath(String domainToken) {
try {
- if (domainToken.equals(FullBackup.DATA_TREE_TOKEN)) {
+ if (domainToken.equals(FullBackup.FILES_TREE_TOKEN)) {
return FILES_DIR.getCanonicalPath();
} else if (domainToken.equals(FullBackup.DATABASE_TREE_TOKEN)) {
return DATABASE_DIR.getCanonicalPath();
@@ -224,14 +241,26 @@ public class FullBackup {
return SHAREDPREF_DIR.getCanonicalPath();
} else if (domainToken.equals(FullBackup.CACHE_TREE_TOKEN)) {
return CACHE_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.NO_BACKUP_TREE_TOKEN)) {
+ return NOBACKUP_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_FILES_TREE_TOKEN)) {
+ return DEVICE_FILES_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_DATABASE_TREE_TOKEN)) {
+ return DEVICE_DATABASE_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_ROOT_TREE_TOKEN)) {
+ return DEVICE_ROOT_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN)) {
+ return DEVICE_SHAREDPREF_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_CACHE_TREE_TOKEN)) {
+ return DEVICE_CACHE_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_NO_BACKUP_TREE_TOKEN)) {
+ return DEVICE_NOBACKUP_DIR.getCanonicalPath();
} else if (domainToken.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
if (EXTERNAL_DIR != null) {
return EXTERNAL_DIR.getCanonicalPath();
} else {
return null;
}
- } else if (domainToken.equals(FullBackup.NO_BACKUP_TREE_TOKEN)) {
- return NOBACKUP_DIR.getCanonicalPath();
}
// Not a supported location
Log.i(TAG, "Unrecognized domain " + domainToken);
@@ -257,12 +286,25 @@ public class FullBackup {
mFullBackupContent = context.getApplicationInfo().fullBackupContent;
mPackageManager = context.getPackageManager();
mPackageName = context.getPackageName();
- FILES_DIR = context.getFilesDir();
- DATABASE_DIR = context.getDatabasePath("foo").getParentFile();
- ROOT_DIR = new File(context.getApplicationInfo().dataDir);
- SHAREDPREF_DIR = context.getSharedPrefsFile("foo").getParentFile();
- CACHE_DIR = context.getCacheDir();
- NOBACKUP_DIR = context.getNoBackupFilesDir();
+
+ // System apps have control over where their default storage context
+ // is pointed, so we're always explicit when building paths.
+ final Context ceContext = context.createCredentialEncryptedStorageContext();
+ FILES_DIR = ceContext.getFilesDir();
+ DATABASE_DIR = ceContext.getDatabasePath("foo").getParentFile();
+ ROOT_DIR = ceContext.getDataDir();
+ SHAREDPREF_DIR = ceContext.getSharedPreferencesPath("foo").getParentFile();
+ CACHE_DIR = ceContext.getCacheDir();
+ NOBACKUP_DIR = ceContext.getNoBackupFilesDir();
+
+ final Context deContext = context.createDeviceEncryptedStorageContext();
+ DEVICE_FILES_DIR = deContext.getFilesDir();
+ DEVICE_DATABASE_DIR = deContext.getDatabasePath("foo").getParentFile();
+ DEVICE_ROOT_DIR = deContext.getDataDir();
+ DEVICE_SHAREDPREF_DIR = deContext.getSharedPreferencesPath("foo").getParentFile();
+ DEVICE_CACHE_DIR = deContext.getCacheDir();
+ DEVICE_NOBACKUP_DIR = deContext.getNoBackupFilesDir();
+
if (android.os.Process.myUid() != Process.SYSTEM_UID) {
EXTERNAL_DIR = context.getExternalFilesDir(null);
} else {
@@ -403,6 +445,13 @@ public class FullBackup {
Log.v(TAG_XML_PARSER, "...automatically generated "
+ canonicalJournalPath + ". Ignore if nonexistent.");
}
+ final String canonicalWalPath =
+ canonicalFile.getCanonicalPath() + "-wal";
+ activeSet.add(canonicalWalPath);
+ if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
+ Log.v(TAG_XML_PARSER, "...automatically generated "
+ + canonicalWalPath + ". Ignore if nonexistent.");
+ }
}
// Special case for sharedpref files (not dirs) also add ".xml" suffix file.
@@ -485,11 +534,19 @@ public class FullBackup {
if ("root".equals(xmlDomain)) {
return FullBackup.ROOT_TREE_TOKEN;
} else if ("file".equals(xmlDomain)) {
- return FullBackup.DATA_TREE_TOKEN;
+ return FullBackup.FILES_TREE_TOKEN;
} else if ("database".equals(xmlDomain)) {
return FullBackup.DATABASE_TREE_TOKEN;
} else if ("sharedpref".equals(xmlDomain)) {
return FullBackup.SHAREDPREFS_TREE_TOKEN;
+ } else if ("device_root".equals(xmlDomain)) {
+ return FullBackup.DEVICE_ROOT_TREE_TOKEN;
+ } else if ("device_file".equals(xmlDomain)) {
+ return FullBackup.DEVICE_FILES_TREE_TOKEN;
+ } else if ("device_database".equals(xmlDomain)) {
+ return FullBackup.DEVICE_DATABASE_TREE_TOKEN;
+ } else if ("device_sharedpref".equals(xmlDomain)) {
+ return FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN;
} else if ("external".equals(xmlDomain)) {
return FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
} else {
@@ -542,6 +599,14 @@ public class FullBackup {
return ROOT_DIR;
} else if ("sharedpref".equals(domain)) {
return SHAREDPREF_DIR;
+ } else if ("device_file".equals(domain)) {
+ return DEVICE_FILES_DIR;
+ } else if ("device_database".equals(domain)) {
+ return DEVICE_DATABASE_DIR;
+ } else if ("device_root".equals(domain)) {
+ return DEVICE_ROOT_DIR;
+ } else if ("device_sharedpref".equals(domain)) {
+ return DEVICE_SHAREDPREF_DIR;
} else if ("external".equals(domain)) {
return EXTERNAL_DIR;
} else {
diff --git a/core/java/android/app/job/IJobScheduler.aidl b/core/java/android/app/job/IJobScheduler.aidl
index f0c33023292b..3379f2ec7c9c 100644
--- a/core/java/android/app/job/IJobScheduler.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -24,7 +24,7 @@ import android.app.job.JobInfo;
*/
interface IJobScheduler {
int schedule(in JobInfo job);
- int scheduleAsPackage(in JobInfo job, String packageName, int userId);
+ int scheduleAsPackage(in JobInfo job, String packageName, int userId, String tag);
void cancel(int jobId);
void cancelAll();
List<JobInfo> getAllPendingJobs();
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 5398e7f2dc95..039c9d7c3c31 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -83,6 +83,38 @@ public class JobInfo implements Parcelable {
*/
public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
+ /**
+ * Default of {@link #getPriority}.
+ * @hide
+ */
+ public static final int PRIORITY_DEFAULT = 0;
+
+ /**
+ * Value of {@link #getPriority} for expedited syncs.
+ * @hide
+ */
+ public static final int PRIORITY_SYNC_EXPEDITED = 10;
+
+ /**
+ * Value of {@link #getPriority} for first time initialization syncs.
+ * @hide
+ */
+ public static final int PRIORITY_SYNC_INITIALIZATION = 20;
+
+ /**
+ * Value of {@link #getPriority} for a foreground app (overrides the supplied
+ * JobInfo priority if it is smaller).
+ * @hide
+ */
+ public static final int PRIORITY_FOREGROUND_APP = 30;
+
+ /**
+ * Value of {@link #getPriority} for the current top app (overrides the supplied
+ * JobInfo priority if it is smaller).
+ * @hide
+ */
+ public static final int PRIORITY_TOP_APP = 40;
+
private final int jobId;
private final PersistableBundle extras;
private final ComponentName service;
@@ -406,7 +438,7 @@ public class JobInfo implements Parcelable {
private int mJobId;
private PersistableBundle mExtras = PersistableBundle.EMPTY;
private ComponentName mJobService;
- private int mPriority;
+ private int mPriority = PRIORITY_DEFAULT;
// Requirements.
private boolean mRequiresCharging;
private boolean mRequiresDeviceIdle;
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 5e1a425606f3..d1e563f90f2d 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -68,10 +68,11 @@ public abstract class JobScheduler {
* @param packageName The package on behalf of which the job is to be scheduled. This will be
* used to track battery usage and appIdleState.
* @param userId User on behalf of whom this job is to be scheduled.
+ * @param tag Debugging tag for dumps associated with this job (instead of the service class)
* @return {@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}
* @hide
*/
- public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId);
+ public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag);
/**
* Cancel a job that is pending in the JobScheduler.
diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java
index 940a5305fe55..95a8ccf7caf3 100644
--- a/core/java/android/app/job/JobService.java
+++ b/core/java/android/app/job/JobService.java
@@ -46,10 +46,10 @@ public abstract class JobService extends Service {
* Job services must be protected with this permission:
*
* <pre class="prettyprint">
- * <service android:name="MyJobService"
- * android:permission="android.permission.BIND_JOB_SERVICE" >
+ * &#60;service android:name="MyJobService"
+ * android:permission="android.permission.BIND_JOB_SERVICE" &#62;
* ...
- * </service>
+ * &#60;/service&#62;
* </pre>
*
* <p>If a job service is declared in the manifest but not protected with this
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 999d8260cad3..0f5cb6f4b8e1 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,8 +16,6 @@
package android.app.trust;
-import com.android.internal.widget.LockPatternUtils;
-
import android.Manifest;
import android.annotation.RequiresPermission;
import android.os.Handler;
@@ -26,7 +24,8 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.ArrayMap;
-import android.util.Log;
+
+import com.android.internal.widget.LockPatternUtils;
/**
* See {@link com.android.server.trust.TrustManagerService}
@@ -62,7 +61,7 @@ public class TrustManager {
try {
mService.setDeviceLockedForUser(userId, locked);
} catch (RemoteException e) {
- onError(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -77,7 +76,7 @@ public class TrustManager {
try {
mService.reportUnlockAttempt(successful, userId);
} catch (RemoteException e) {
- onError(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -90,7 +89,7 @@ public class TrustManager {
try {
mService.reportEnabledTrustAgentsChanged(userId);
} catch (RemoteException e) {
- onError(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -103,7 +102,7 @@ public class TrustManager {
try {
mService.reportKeyguardShowingChanged();
} catch (RemoteException e) {
- onError(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -134,7 +133,7 @@ public class TrustManager {
mService.registerTrustListener(iTrustListener);
mTrustListeners.put(trustListener, iTrustListener);
} catch (RemoteException e) {
- onError(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -149,7 +148,7 @@ public class TrustManager {
try {
mService.unregisterTrustListener(iTrustListener);
} catch (RemoteException e) {
- onError(e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -163,16 +162,10 @@ public class TrustManager {
try {
return mService.isTrustUsuallyManaged(userId);
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
-
-
- private void onError(Exception e) {
- Log.e(TAG, "Error while calling TrustManagerService", e);
- }
-
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index a9328bce0612..342c2858ab0f 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -33,4 +33,5 @@ interface IUsageStatsManager {
void setAppInactive(String packageName, boolean inactive, int userId);
boolean isAppInactive(String packageName, int userId);
void whitelistAppTemporarily(String packageName, long duration, int userId);
+ void onCarrierPrivilegedAppsChanged();
}
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 13aeef0058bb..2e3aca46f904 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -25,9 +25,15 @@ import android.net.ConnectivityManager;
import android.net.DataUsageRequest;
import android.net.NetworkIdentity;
import android.net.NetworkTemplate;
+import android.net.INetworkStatsService;
+import android.os.Binder;
import android.os.Build;
+import android.os.Message;
+import android.os.Messenger;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
/**
@@ -75,16 +81,26 @@ import android.util.Log;
* not included.
*/
public class NetworkStatsManager {
- private final static String TAG = "NetworkStatsManager";
+ private static final String TAG = "NetworkStatsManager";
+ private static final boolean DBG = false;
+
+ /** @hide */
+ public static final int CALLBACK_LIMIT_REACHED = 0;
+ /** @hide */
+ public static final int CALLBACK_RELEASED = 1;
private final Context mContext;
+ private final INetworkStatsService mService;
/**
* {@hide}
*/
public NetworkStatsManager(Context context) {
mContext = context;
+ mService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
}
+
/**
* Query network usage statistics summaries. Result is summarised data usage for the whole
* device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
@@ -322,7 +338,40 @@ public class NetworkStatsManager {
checkNotNull(policy, "DataUsagePolicy cannot be null");
checkNotNull(callback, "DataUsageCallback cannot be null");
- // TODO: Implement stub.
+ final Looper looper;
+ if (handler == null) {
+ looper = Looper.myLooper();
+ } else {
+ looper = handler.getLooper();
+ }
+
+ if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy);
+
+ NetworkTemplate[] templates;
+ if (policy.subscriberIds == null || policy.subscriberIds.length == 0) {
+ templates = new NetworkTemplate[1];
+ templates[0] = createTemplate(policy.networkType, null /* subscriberId */);
+ } else {
+ templates = new NetworkTemplate[policy.subscriberIds.length];
+ for (int i = 0; i < policy.subscriberIds.length; i++) {
+ templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]);
+ }
+ }
+ DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
+ templates, policy.uids, policy.thresholdInBytes);
+ try {
+ CallbackHandler callbackHandler = new CallbackHandler(looper, callback);
+ callback.request = mService.registerDataUsageCallback(
+ mContext.getOpPackageName(), request, new Messenger(callbackHandler),
+ new Binder());
+ if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request);
+
+ if (callback.request == null) {
+ Log.e(TAG, "Request from callback is null; should not happen");
+ }
+ } catch (RemoteException e) {
+ if (DBG) Log.d(TAG, "Remote exception when registering callback");
+ }
}
/**
@@ -331,9 +380,15 @@ public class NetworkStatsManager {
* @param callback The {@link DataUsageCallback} used when registering.
*/
public void unregisterDataUsageCallback(DataUsageCallback callback) {
- checkNotNull(callback, "DataUsageCallback cannot be null");
-
- // TODO: Implement stub.
+ if (callback == null || callback.request == null
+ || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
+ throw new IllegalArgumentException("Invalid DataUsageCallback");
+ }
+ try {
+ mService.unregisterDataUsageRequest(callback.request);
+ } catch (RemoteException e) {
+ if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
+ }
}
/**
@@ -366,4 +421,38 @@ public class NetworkStatsManager {
}
return template;
}
+
+ private static class CallbackHandler extends Handler {
+ private DataUsageCallback mCallback;
+ CallbackHandler(Looper looper, DataUsageCallback callback) {
+ super(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ DataUsageRequest request =
+ (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
+
+ switch (message.what) {
+ case CALLBACK_LIMIT_REACHED: {
+ if (mCallback != null) {
+ mCallback.onLimitReached();
+ } else {
+ Log.e(TAG, "limit reached with released callback for " + request);
+ }
+ break;
+ }
+ case CALLBACK_RELEASED: {
+ if (DBG) Log.d(TAG, "callback released for " + request);
+ mCallback = null;
+ break;
+ }
+ }
+ }
+
+ private static Object getObject(Message msg, String key) {
+ return msg.getData().getParcelable(key);
+ }
+ }
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index c74b0f2d8e43..2aeecfabd48c 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -267,4 +267,15 @@ public final class UsageStatsManager {
} catch (RemoteException re) {
}
}
+
+ /**
+ * Inform usage stats that the carrier privileged apps access rules have changed.
+ * @hide
+ */
+ public void onCarrierPrivilegedAppsChanged() {
+ try {
+ mService.onCarrierPrivilegedAppsChanged();
+ } catch (RemoteException re) {
+ }
+ }
}
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index bed91ecafb96..cd8f1260b590 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -376,7 +376,13 @@ public class AppWidgetHostView extends FrameLayout {
* AppWidget provider. Will animate into these new views as needed
*/
public void updateAppWidget(RemoteViews remoteViews) {
+ applyRemoteViews(remoteViews);
+ }
+ /**
+ * @hide
+ */
+ protected void applyRemoteViews(RemoteViews remoteViews) {
if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
boolean recycled = false;
@@ -573,8 +579,9 @@ public class AppWidgetHostView extends FrameLayout {
/**
* Build a {@link Context} cloned into another package name, usually for the
* purposes of reading remote resources.
+ * @hide
*/
- private Context getRemoteContext() {
+ protected Context getRemoteContext() {
try {
// Return if cloned successfully, otherwise default
return mContext.createApplicationContext(
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 278c9d6f8699..9f654c25e2c5 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -472,9 +472,8 @@ public class AppWidgetManager {
}
try {
mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -495,9 +494,8 @@ public class AppWidgetManager {
}
try {
mService.updateAppWidgetOptions(mPackageName, appWidgetId, options);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -518,9 +516,8 @@ public class AppWidgetManager {
}
try {
return mService.getAppWidgetOptions(mPackageName, appWidgetId);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -581,7 +578,7 @@ public class AppWidgetManager {
try {
mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
} catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -635,9 +632,8 @@ public class AppWidgetManager {
}
try {
mService.updateAppWidgetProvider(provider, views);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -654,9 +650,8 @@ public class AppWidgetManager {
}
try {
mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -764,9 +759,8 @@ public class AppWidgetManager {
convertSizesToPixels(info);
}
return providers.getList();
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -787,9 +781,8 @@ public class AppWidgetManager {
convertSizesToPixels(info);
}
return info;
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -918,9 +911,8 @@ public class AppWidgetManager {
}
try {
return mService.hasBindAppWidgetPermission(packageName, userId);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -939,9 +931,8 @@ public class AppWidgetManager {
}
try {
return mService.hasBindAppWidgetPermission(packageName, UserHandle.myUserId());
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -979,9 +970,8 @@ public class AppWidgetManager {
}
try {
mService.setBindAppWidgetPermission(packageName, userId, permission);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1005,9 +995,8 @@ public class AppWidgetManager {
}
try {
mService.bindRemoteViewsService(packageName, appWidgetId, intent, connection);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1029,9 +1018,8 @@ public class AppWidgetManager {
}
try {
mService.unbindRemoteViewsService(packageName, appWidgetId, intent);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1048,9 +1036,8 @@ public class AppWidgetManager {
}
try {
return mService.getAppWidgetIds(provider);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1063,8 +1050,8 @@ public class AppWidgetManager {
}
try {
return mService.isBoundWidgetPackage(packageName, userId);
- } catch (RemoteException re) {
- throw new RuntimeException("system server dead?", re);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1076,9 +1063,8 @@ public class AppWidgetManager {
try {
return mService.bindAppWidgetId(mPackageName, appWidgetId,
profileId, provider, options);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
index 8d8d2f59c677..829685b83b5b 100644
--- a/core/java/android/auditing/SecurityLog.java
+++ b/core/java/android/auditing/SecurityLog.java
@@ -64,7 +64,8 @@ public class SecurityLog {
public static final int TAG_SYNC_SEND_FILE = SecurityLogTags.SECURITY_ADB_SYNC_SEND;
/**
* Indicate that an app process was started. The log entry contains the following
- * information about the process in order, accessible via {@link SecurityEvent#getData()}}:
+ * information about the process encapsulated in an {@link Object} array, accessible via
+ * {@link SecurityEvent#getData()}:
* process name (String), exact start time (long), app Uid (integer), app Pid (integer),
* seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
*/
@@ -77,8 +78,10 @@ public class SecurityLog {
SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
/**
* Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
- * contains the attempt result (integer, 1 for successful, 0 for unsuccessful), accessible via
- * {@link SecurityEvent#getData()}}
+ * contains the following information about the attempt encapsulated in an {@link Object} array,
+ * accessible via {@link SecurityEvent#getData()}:
+ * attempt result (integer, 1 for successful, 0 for unsuccessful), strength of auth method
+ * (integer, 1 if strong auth method was used, 0 otherwise)
*/
public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/auditing/SecurityLogTags.logtags
index cf858940058b..ccc37995972c 100644
--- a/core/java/android/auditing/SecurityLogTags.logtags
+++ b/core/java/android/auditing/SecurityLogTags.logtags
@@ -8,5 +8,5 @@ option java_package android.auditing
210004 security_adb_sync_send (path|3)
210005 security_app_process_start (process|3),(start_time|2|3),(uid|1),(pid|1),(seinfo|3),(sha256|3)
210006 security_keyguard_dismissed
-210007 security_keyguard_dismiss_auth_attempt (success|1)
+210007 security_keyguard_dismiss_auth_attempt (success|1),(method_strength|1)
210008 security_keyguard_secured
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index e67da2bfe7f8..1266f73a2f44 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -122,6 +122,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
}
getService().setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -132,7 +133,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
return getService().getPrimaryClip(mContext.getOpPackageName());
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -144,7 +145,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
return getService().getPrimaryClipDescription(mContext.getOpPackageName());
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -155,7 +156,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
return getService().hasPrimaryClip(mContext.getOpPackageName());
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -166,6 +167,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
getService().addPrimaryClipChangedListener(
mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
mPrimaryClipChangedListeners.add(what);
@@ -180,6 +182,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
getService().removePrimaryClipChangedListener(
mPrimaryClipChangedServiceListener);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -213,7 +216,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
return getService().hasClipboardText(mContext.getOpPackageName());
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4918914ec9d5..b935b256b880 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -811,6 +811,25 @@ public abstract class Context {
public abstract File getSharedPreferencesPath(String name);
/**
+ * Returns the absolute path to the directory on the filesystem where all
+ * private files belonging to this app are stored. This is the top-level
+ * directory under which {@link #getFilesDir()}, {@link #getCacheDir()}, etc
+ * are contained. Apps should <em>not</em> create any files or directories
+ * as direct children of this directory, since it's a reserved namespace
+ * belonging to the platform. Instead, use {@link #getDir(String, int)} or
+ * other storage APIs.
+ * <p>
+ * The returned path may change over time if the calling app is moved to an
+ * adopted storage device, so only relative paths should be persisted.
+ * <p>
+ * No additional permissions are required for the calling app to read or
+ * write files under the returned path.
+ *
+ * @see #getDir(String, int)
+ */
+ public abstract File getDataDir();
+
+ /**
* Returns the absolute path to the directory on the filesystem where files
* created with {@link #openFileOutput} are stored.
* <p>
@@ -2534,6 +2553,17 @@ public abstract class Context {
}
/**
+ * Same as {@link #bindService(Intent, ServiceConnection, int, UserHandle)}, but with an
+ * explicit non-null Handler to run the ServiceConnection callbacks on.
+ *
+ * @hide
+ */
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
@@ -2833,6 +2863,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.os.RecoverySystem} for accessing the recovery system
+ * service.
+ *
+ * @see #getSystemService
+ * @hide
+ */
+ public static final String RECOVERY_SERVICE = "recovery";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.view.WindowManager} for accessing the system's window
* manager.
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 61b87a957d2a..323c9bfe8099 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -212,6 +212,11 @@ public class ContextWrapper extends Context {
}
@Override
+ public File getDataDir() {
+ return mBase.getDataDir();
+ }
+
+ @Override
public File getFilesDir() {
return mBase.getFilesDir();
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7dc74010aa77..09fa5e11829b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,24 +16,13 @@
package android.content;
-import android.content.pm.ApplicationInfo;
-import android.os.ResultReceiver;
-import android.os.ShellCommand;
-import android.provider.MediaStore;
-import android.util.ArraySet;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.AnyRes;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.content.pm.ActivityInfo;
-
-import static android.content.ContentProvider.maybeAddUserId;
-
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -41,21 +30,24 @@ import android.content.res.TypedArray;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.ResultReceiver;
+import android.os.ShellCommand;
import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
+import android.provider.MediaStore;
import android.provider.OpenableColumns;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
-
import com.android.internal.util.XmlUtils;
-
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -71,6 +63,8 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Set;
+import static android.content.ContentProvider.maybeAddUserId;
+
/**
* An intent is an abstract description of an operation to be performed. It
* can be used with {@link Context#startActivity(Intent) startActivity} to
@@ -759,6 +753,14 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.shortcut.ICON_RESOURCE";
/**
+ * An activity that provides a user interface for adjusting application preferences.
+ * Optional but recommended settings for all applications which have settings.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_APPLICATION_PREFERENCES
+ = "android.intent.action.APPLICATION_PREFERENCES";
+
+ /**
* Represents a shortcut/live folder icon resource.
*
* @see Intent#ACTION_CREATE_SHORTCUT
@@ -3028,6 +3030,17 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.MANAGED_PROFILE_REMOVED";
/**
+ * Broadcast sent to the primary user when the credential-encrypted private storage for
+ * an associated managed profile is unlocked. Carries an extra {@link #EXTRA_USER} that
+ * specifies the UserHandle of the profile that was unlocked. Only applications (for example
+ * Launchers) that need to display merged content across both primary and managed profiles
+ * need to worry about this broadcast. This is only sent to registered receivers,
+ * not manifest receivers.
+ */
+ public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
+ "android.intent.action.MANAGED_PROFILE_UNLOCKED";
+
+ /**
* Broadcast sent to the primary user when an associated managed profile's availability has
* changed. This includes when the user toggles the profile's quiet mode. Carries an extra
* {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
@@ -3176,38 +3189,6 @@ public class Intent implements Parcelable, Cloneable {
ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
/**
- * Activity Action: Give access to a standard storage directory after obtaining the user's
- * approval.
- * <p>
- * When invoked, the system will ask the user to grant access to the requested directory (and
- * its descendants).
- * <p>
- * To gain access to descendant (child, grandchild, etc) documents, use
- * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)} and
- * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
- * <p>
- * Input: full path to a standard directory, in the form of
- * {@code STORAGE_ROOT + STANDARD_DIRECTORY}, where {@code STORAGE_ROOT} is the physical path of
- * a storage container, and {@code STANDARD_DIRECTORY} is one of
- * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS},
- * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS},
- * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES},
- * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS},
- * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}
- * <p>
- * For example, to open the "Pictures" folder in the default external storage, the intent's data
- * would be: {@code Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
- * Environment.DIRECTORY_PICTURES))}.
- * <p>
- * Output: The URI representing the requested directory tree.
- *
- * @see DocumentsContract
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String
- ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
-
- /**
* Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or
* exisiting sensor being disconnected.
*
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index a7744e7a1208..6893067e060b 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -422,7 +422,7 @@ public class RestrictionsManager {
return mService.getApplicationRestrictions(mContext.getPackageName());
}
} catch (RemoteException re) {
- Log.w(TAG, "Couldn't reach service");
+ throw re.rethrowFromSystemServer();
}
return null;
}
@@ -439,7 +439,7 @@ public class RestrictionsManager {
return mService.hasRestrictionsProvider();
}
} catch (RemoteException re) {
- Log.w(TAG, "Couldn't reach service");
+ throw re.rethrowFromSystemServer();
}
return false;
}
@@ -477,7 +477,7 @@ public class RestrictionsManager {
request);
}
} catch (RemoteException re) {
- Log.w(TAG, "Couldn't reach service");
+ throw re.rethrowFromSystemServer();
}
}
@@ -487,7 +487,7 @@ public class RestrictionsManager {
return mService.createLocalApprovalIntent();
}
} catch (RemoteException re) {
- Log.w(TAG, "Couldn't reach service");
+ throw re.rethrowFromSystemServer();
}
return null;
}
@@ -519,7 +519,7 @@ public class RestrictionsManager {
mService.notifyPermissionResponse(packageName, response);
}
} catch (RemoteException re) {
- Log.w(TAG, "Couldn't reach service");
+ throw re.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 43a0cc77d492..14ef61ce63d4 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -178,6 +178,11 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
/**
+ * Activity is does not support resizing, but we are forcing it to be resizeable.
+ * @hide
+ */
+ public static final int RESIZE_MODE_FORCE_RESIZEABLE = 4;
+ /**
* Value indicating if the resizing mode the activity supports.
* See {@link android.R.attr#resizeableActivity}.
* @hide
@@ -784,9 +789,27 @@ public class ActivityInfo extends ComponentInfo
}
}
+ /**
+ * Returns true if the activity's orientation is fixed.
+ * @hide
+ */
+ boolean isFixedOrientation() {
+ return screenOrientation == SCREEN_ORIENTATION_LANDSCAPE
+ || screenOrientation == SCREEN_ORIENTATION_PORTRAIT
+ || screenOrientation == SCREEN_ORIENTATION_SENSOR_LANDSCAPE
+ || screenOrientation == SCREEN_ORIENTATION_SENSOR_PORTRAIT
+ || screenOrientation == SCREEN_ORIENTATION_REVERSE_LANDSCAPE
+ || screenOrientation == SCREEN_ORIENTATION_REVERSE_PORTRAIT
+ || screenOrientation == SCREEN_ORIENTATION_USER_LANDSCAPE
+ || screenOrientation == SCREEN_ORIENTATION_USER_PORTRAIT
+ || screenOrientation == SCREEN_ORIENTATION_LOCKED;
+ }
+
/** @hide */
public static boolean isResizeableMode(int mode) {
- return mode == RESIZE_MODE_RESIZEABLE || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ return mode == RESIZE_MODE_RESIZEABLE
+ || mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
+ || mode == RESIZE_MODE_FORCE_RESIZEABLE;
}
/** @hide */
@@ -800,6 +823,8 @@ public class ActivityInfo extends ComponentInfo
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";
default:
return "unknown=" + mode;
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index c79dae5dd913..ad174f6da061 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -523,6 +523,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES = 1 << 11;
/**
+ * Value for {@link #privateFlags}: {@code true} means the OS should go ahead and
+ * run full-data backup operations for the app even when it is in a
+ * foreground-equivalent run state. Defaults to {@code false} if unspecified.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
@@ -1038,10 +1046,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
deviceEncryptedDataDir = Environment
- .getDataUserDeviceEncryptedPackageDirectory(volumeUuid, userId, packageName)
+ .getDataUserDePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
credentialEncryptedDataDir = Environment
- .getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
+ .getDataUserCePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
index 79fa32791a31..7671f72cbeac 100644
--- a/core/java/android/content/pm/FeatureInfo.java
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -20,9 +20,18 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * A single feature that can be requested by an application. This corresponds
- * to information collected from the
- * AndroidManifest.xml's {@code <uses-feature>} tag.
+ * Definition of a single optional hardware or software feature of an Android
+ * device.
+ * <p>
+ * This object is used to represent both features supported by a device and
+ * features requested by an app. Apps can request that certain features be
+ * available as a prerequisite to being installed through the
+ * {@code uses-feature} tag in their manifests.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#N}, features can have a
+ * version, which must always be backwards compatible. That is, a device
+ * claiming to support version 3 of a specific feature must support apps
+ * requesting version 1 of that feature.
*/
public class FeatureInfo implements Parcelable {
/**
@@ -31,7 +40,17 @@ public class FeatureInfo implements Parcelable {
* in {@link #reqGlEsVersion}.
*/
public String name;
-
+
+ /**
+ * If this object represents a feature supported by a device, this is the
+ * maximum version of this feature supported by the device. The device
+ * implicitly supports all older versions of this feature.
+ * <p>
+ * If this object represents a feature requested by an app, this is the
+ * minimum version of the feature required by the app.
+ */
+ public int version;
+
/**
* Default value for {@link #reqGlEsVersion};
*/
@@ -59,15 +78,17 @@ public class FeatureInfo implements Parcelable {
public FeatureInfo(FeatureInfo orig) {
name = orig.name;
+ version = orig.version;
reqGlEsVersion = orig.reqGlEsVersion;
flags = orig.flags;
}
+ @Override
public String toString() {
if (name != null) {
return "FeatureInfo{"
+ Integer.toHexString(System.identityHashCode(this))
- + " " + name + " fl=0x" + Integer.toHexString(flags) + "}";
+ + " " + name + " v=" + version + " fl=0x" + Integer.toHexString(flags) + "}";
} else {
return "FeatureInfo{"
+ Integer.toHexString(System.identityHashCode(this))
@@ -76,21 +97,25 @@ public class FeatureInfo implements Parcelable {
}
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(name);
+ dest.writeInt(version);
dest.writeInt(reqGlEsVersion);
dest.writeInt(flags);
}
- public static final Creator<FeatureInfo> CREATOR =
- new Creator<FeatureInfo>() {
+ public static final Creator<FeatureInfo> CREATOR = new Creator<FeatureInfo>() {
+ @Override
public FeatureInfo createFromParcel(Parcel source) {
return new FeatureInfo(source);
}
+ @Override
public FeatureInfo[] newArray(int size) {
return new FeatureInfo[size];
}
@@ -98,6 +123,7 @@ public class FeatureInfo implements Parcelable {
private FeatureInfo(Parcel source) {
name = source.readString();
+ version = source.readInt();
reqGlEsVersion = source.readInt();
flags = source.readInt();
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 593fe2aef1e1..d6b674c0edee 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -283,7 +283,8 @@ interface IPackageManager {
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
- boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId);
+ String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended, int userId);
+ boolean isPackageSuspendedForUser(String packageName, int userId);
/**
* Backup/restore support - only the system uid may use these.
@@ -416,7 +417,7 @@ interface IPackageManager {
*/
FeatureInfo[] getSystemAvailableFeatures();
- boolean hasSystemFeature(String name);
+ boolean hasSystemFeature(String name, int version);
void enterSafeMode();
boolean isSafeMode();
@@ -534,4 +535,8 @@ interface IPackageManager {
boolean isEphemeralApplication(String packageName, int userId);
boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
+
+ String getServicesSystemSharedLibraryPackageName();
+
+ boolean isPackageDeviceAdminOnAnyUser(String packageName);
}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8c7d327720a3..e443d5073c54 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -171,7 +171,7 @@ public class LauncherApps {
try {
activities = mService.getLauncherActivities(packageName, user);
} catch (RemoteException re) {
- throw new RuntimeException("Failed to call LauncherAppsService", re);
+ throw re.rethrowFromSystemServer();
}
if (activities == null) {
return Collections.EMPTY_LIST;
@@ -208,7 +208,7 @@ public class LauncherApps {
return info;
}
} catch (RemoteException re) {
- throw new RuntimeException("Failed to call LauncherAppsService", re);
+ throw re.rethrowFromSystemServer();
}
return null;
}
@@ -229,7 +229,7 @@ public class LauncherApps {
try {
mService.startActivityAsUser(component, sourceBounds, opts, user);
} catch (RemoteException re) {
- // Oops!
+ throw re.rethrowFromSystemServer();
}
}
@@ -247,7 +247,7 @@ public class LauncherApps {
try {
mService.showAppDetailsAsUser(component, sourceBounds, opts, user);
} catch (RemoteException re) {
- // Oops!
+ throw re.rethrowFromSystemServer();
}
}
@@ -263,7 +263,7 @@ public class LauncherApps {
try {
return mService.isPackageEnabled(packageName, user);
} catch (RemoteException re) {
- throw new RuntimeException("Failed to call LauncherAppsService", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -282,7 +282,7 @@ public class LauncherApps {
try {
return mService.getApplicationInfo(packageName, flags, user);
} catch (RemoteException re) {
- throw new RuntimeException("Failed to call LauncherAppsService", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -298,7 +298,7 @@ public class LauncherApps {
try {
return mService.isActivityEnabled(component, user);
} catch (RemoteException re) {
- throw new RuntimeException("Failed to call LauncherAppsService", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -327,6 +327,7 @@ public class LauncherApps {
try {
mService.addOnAppsChangedListener(mAppsChangedListener);
} catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
}
@@ -346,6 +347,7 @@ public class LauncherApps {
try {
mService.removeOnAppsChangedListener(mAppsChangedListener);
} catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 32830053fae2..2cbb7825ec80 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -301,7 +301,7 @@ public class PackageInstaller {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -321,7 +321,7 @@ public class PackageInstaller {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -337,7 +337,7 @@ public class PackageInstaller {
try {
mInstaller.updateSessionAppIcon(sessionId, appIcon);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -353,7 +353,7 @@ public class PackageInstaller {
final String val = (appLabel != null) ? appLabel.toString() : null;
mInstaller.updateSessionAppLabel(sessionId, val);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -370,7 +370,7 @@ public class PackageInstaller {
try {
mInstaller.abandonSession(sessionId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -385,7 +385,7 @@ public class PackageInstaller {
try {
return mInstaller.getSessionInfo(sessionId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -403,7 +403,7 @@ public class PackageInstaller {
try {
return mInstaller.getAllSessions(mUserId).getList();
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -414,7 +414,7 @@ public class PackageInstaller {
try {
return mInstaller.getMySessions(mInstallerPackageName, mUserId).getList();
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -427,7 +427,7 @@ public class PackageInstaller {
try {
mInstaller.uninstall(packageName, mInstallerPackageName, 0, statusReceiver, mUserId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -436,7 +436,7 @@ public class PackageInstaller {
try {
mInstaller.setPermissionsResult(sessionId, accepted);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -611,7 +611,7 @@ public class PackageInstaller {
try {
mInstaller.registerCallback(delegate, mUserId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
mDelegates.add(delegate);
}
@@ -634,7 +634,7 @@ public class PackageInstaller {
try {
mInstaller.unregisterCallback(delegate);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
i.remove();
}
@@ -681,7 +681,7 @@ public class PackageInstaller {
try {
mSession.setClientProgress(progress);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -690,7 +690,7 @@ public class PackageInstaller {
try {
mSession.addClientProgress(progress);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -734,7 +734,7 @@ public class PackageInstaller {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -767,7 +767,7 @@ public class PackageInstaller {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -790,7 +790,7 @@ public class PackageInstaller {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -810,7 +810,7 @@ public class PackageInstaller {
try {
mSession.commit(statusReceiver);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -823,7 +823,7 @@ public class PackageInstaller {
try {
mSession.close();
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -837,7 +837,7 @@ public class PackageInstaller {
try {
mSession.abandon();
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 08deedb9fb65..4dd8155f1b10 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -602,7 +602,8 @@ public abstract class PackageManager {
/**
* Flag parameter for {@link #installPackage} to indicate that it is okay
* to install an update to an app where the newly installed app has a lower
- * version code than the currently installed app.
+ * version code than the currently installed app. This is permitted only if
+ * the currently installed app is marked debuggable.
*
* @hide
*/
@@ -1233,6 +1234,14 @@ public abstract class PackageManager {
public static final int MOVE_FAILED_OPERATION_PENDING = -7;
/**
+ * Error code that is passed to the {@link IPackageMoveObserver} if the
+ * specified package cannot be moved since it contains a device admin.
+ *
+ * @hide
+ */
+ public static final int MOVE_FAILED_DEVICE_ADMIN = -8;
+
+ /**
* Flag parameter for {@link #movePackage} to indicate that
* the package should be moved to internal storage if its
* been installed on external media.
@@ -1565,6 +1574,48 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: 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 hardware features limits it supports.
+ * <p>
+ * Level 0 includes the base Vulkan requirements as well as:
+ * <ul><li>{@code VkPhysicalDeviceFeatures::textureCompressionETC2}</li></ul>
+ * <p>
+ * Level 1 additionally includes:
+ * <ul>
+ * <li>{@code VkPhysicalDeviceFeatures::fullDrawIndexUint32}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::imageCubeArray}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::independentBlend}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::geometryShader}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::tessellationShader}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::sampleRateShading}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::textureCompressionASTC_LDR}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::fragmentStoresAndAtomics}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::shaderImageGatherExtended}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::shaderUniformBufferArrayDynamicIndexing}</li>
+ * <li>{@code VkPhysicalDeviceFeatures::shaderSampledImageArrayDynamicIndexing}</li>
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: 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
+ * uses the same encoding as Vulkan version numbers:
+ * <ul>
+ * <li>Major version number in bits 31-22</li>
+ * <li>Minor version number in bits 21-12</li>
+ * <li>Patch version number in bits 11-0</li>
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device includes an accelerometer.
*/
@SdkConstant(SdkConstantType.FEATURE)
@@ -2327,6 +2378,28 @@ public abstract class PackageManager {
public static final int MASK_PERMISSION_FLAGS = 0xFF;
/**
+ * This is a library that contains components apps can invoke. For
+ * example, a services for apps to bind to, or standard chooser UI,
+ * etc. This library is versioned and backwards compatible. Clients
+ * should check its version via {@link android.ext.services.Version
+ * #getVersionCode()} and avoid calling APIs added in later versions.
+ *
+ * @hide
+ */
+ public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
+
+ /**
+ * This is a library that contains components apps can dynamically
+ * load. For example, new widgets, helper classes, etc. This library
+ * is versioned and backwards compatible. Clients should check its
+ * version via {@link android.ext.shared.Version#getVersionCode()}
+ * and avoid calling APIs added in later versions.
+ *
+ * @hide
+ */
+ public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
+
+ /**
* Retrieve overall information about an application package that is
* installed on the system.
*
@@ -3145,7 +3218,7 @@ public abstract class PackageManager {
*/
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
- throw new NullPointerException("permission cannot be null or empty");
+ throw new IllegalArgumentException("permission cannot be null or empty");
}
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
@@ -3365,6 +3438,15 @@ public abstract class PackageManager {
public abstract String[] getSystemSharedLibraryNames();
/**
+ * Get the name of the package hosting the services shared library.
+ *
+ * @return The library host package.
+ *
+ * @hide
+ */
+ public abstract @Nullable String getServicesSystemSharedLibraryPackageName();
+
+ /**
* Get a list of features that are available on the
* system.
*
@@ -3374,15 +3456,27 @@ public abstract class PackageManager {
public abstract FeatureInfo[] getSystemAvailableFeatures();
/**
- * Check whether the given feature name is one of the available
- * features as returned by {@link #getSystemAvailableFeatures()}.
+ * Check whether the given feature name is one of the available features as
+ * returned by {@link #getSystemAvailableFeatures()}. This tests for the
+ * presence of <em>any</em> version of the given feature name; use
+ * {@link #hasSystemFeature(String, int)} to check for a minimum version.
*
- * @return Returns true if the devices supports the feature, else
- * false.
+ * @return Returns true if the devices supports the feature, else false.
*/
public abstract boolean hasSystemFeature(String name);
/**
+ * Check whether the given feature name and version is one of the available
+ * features as returned by {@link #getSystemAvailableFeatures()}. Since
+ * features are defined to always be backwards compatible, this returns true
+ * if the available feature version is greater than or equal to the
+ * requested version.
+ *
+ * @return Returns true if the devices supports the feature, else false.
+ */
+ public abstract boolean hasSystemFeature(String name, int version);
+
+ /**
* Determine the best action to perform for a given Intent. This is how
* {@link Intent#resolveActivity} finds an activity if a class has not
* been explicitly specified.
@@ -4008,7 +4102,7 @@ public abstract class PackageManager {
*
* @return A list of {@link InstrumentationInfo} objects containing one
* entry for each matching instrumentation. If there are no
- * instrumentation available, returns and empty list.
+ * instrumentation available, returns an empty list.
*
* @see #GET_META_DATA
*/
@@ -5259,19 +5353,34 @@ public abstract class PackageManager {
public abstract boolean isSignedByExactly(String packageName, KeySet ks);
/**
- * Puts the package in a suspended state, making the package un-runnable,
- * but it doesn't remove the data or the actual package file. The application notifications
- * will be hidden and also the application will not show up in recents.
+ * Puts the package in a suspended state, where attempts at starting activities are denied.
+ *
+ * <p>It doesn't remove the data or the actual package file. The application notifications
+ * will be hidden, the application will not show up in recents, will not be able to show
+ * toasts or dialogs or ring the device.
*
- * @param packageName The name of the package to set the suspended status.
- * @param suspended If set to {@code true} than the package will be suspended, if set to
- * {@code false} the package will be unsuspended.
+ * @param packageNames The names of the packages to set the suspended status.
+ * @param suspended If set to {@code true} than the packages will be suspended, if set to
+ * {@code false} the packages will be unsuspended.
* @param userId The user id.
*
+ * @return an array of package names for which the suspended status is not set as requested in
+ * this method.
+ *
+ * @hide
+ */
+ public abstract String[] setPackagesSuspendedAsUser(
+ String[] packageNames, boolean suspended, @UserIdInt int userId);
+
+ /**
+ * @see #setPackageSuspendedAsUser(String, boolean, int)
+ * @param packageName The name of the package to get the suspended status of.
+ * @param userId The user id.
+ * @return {@code true} if the package is suspended or {@code false} if the package is not
+ * suspended or could not be found.
* @hide
*/
- public abstract boolean setPackageSuspendedAsUser(
- String packageName, boolean suspended, @UserIdInt int userId);
+ public abstract boolean isPackageSuspendedForUser(String packageName, int userId);
/** {@hide} */
public static boolean isMoveStatusFinished(int status) {
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 8bf20bfa5207..7fe7f84e0ec9 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -59,12 +59,6 @@ public abstract class PackageManagerInternal {
public abstract void setLocationPackagesProvider(PackagesProvider provider);
/**
- * Sets the input method packages provider.
- * @param provider The packages provider.
- */
- public abstract void setImePackagesProvider(PackagesProvider provider);
-
- /**
* Sets the voice interaction packages provider.
* @param provider The packages provider.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 72ace1583b4a..ce6ddfd31d19 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -80,6 +80,7 @@ import libcore.io.IoUtils;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+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_UNRESIZEABLE;
@@ -337,7 +338,7 @@ public class PackageParser {
public final boolean coreApp;
public final boolean multiArch;
- public final String abiOverride;
+ public final boolean use32bitAbi;
public final boolean extractNativeLibs;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
@@ -354,7 +355,7 @@ public class PackageParser {
this.splitRevisionCodes = splitRevisionCodes;
this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch;
- this.abiOverride = baseApk.abiOverride;
+ this.use32bitAbi = baseApk.use32bitAbi;
this.extractNativeLibs = baseApk.extractNativeLibs;
}
@@ -382,12 +383,12 @@ public class PackageParser {
public final Signature[] signatures;
public final boolean coreApp;
public final boolean multiArch;
- public final String abiOverride;
+ public final boolean use32bitAbi;
public final boolean extractNativeLibs;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
- Signature[] signatures, boolean coreApp, boolean multiArch, String abiOverride,
+ Signature[] signatures, boolean coreApp, boolean multiArch, boolean use32bitAbi,
boolean extractNativeLibs) {
this.codePath = codePath;
this.packageName = packageName;
@@ -399,7 +400,7 @@ public class PackageParser {
this.signatures = signatures;
this.coreApp = coreApp;
this.multiArch = multiArch;
- this.abiOverride = abiOverride;
+ this.use32bitAbi = use32bitAbi;
this.extractNativeLibs = extractNativeLibs;
}
}
@@ -843,8 +844,7 @@ public class PackageParser {
}
pkg.setCodePath(packageDir.getAbsolutePath());
- pkg.setCpuAbiOverride(lite.abiOverride);
-
+ pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
@@ -875,7 +875,7 @@ public class PackageParser {
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.setCodePath(apkFile.getAbsolutePath());
- pkg.setCpuAbiOverride(lite.abiOverride);
+ pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
@@ -1380,7 +1380,7 @@ public class PackageParser {
int revisionCode = 0;
boolean coreApp = false;
boolean multiArch = false;
- String abiOverride = null;
+ boolean use32bitAbi = false;
boolean extractNativeLibs = true;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
@@ -1421,8 +1421,8 @@ public class PackageParser {
if ("multiArch".equals(attr)) {
multiArch = attrs.getAttributeBooleanValue(i, false);
}
- if ("abiOverride".equals(attr)) {
- abiOverride = attrs.getAttributeValue(i);
+ if ("use32bitAbi".equals(attr)) {
+ use32bitAbi = attrs.getAttributeBooleanValue(i, false);
}
if ("extractNativeLibs".equals(attr)) {
extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
@@ -1433,7 +1433,7 @@ public class PackageParser {
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
- abiOverride, extractNativeLibs);
+ use32bitAbi, extractNativeLibs);
}
/**
@@ -2127,6 +2127,8 @@ public class PackageParser {
// that may change.
fi.name = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
+ fi.version = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0);
if (fi.name == null) {
fi.reqGlEsVersion = sa.getInt(
com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
@@ -2667,8 +2669,9 @@ public class PackageParser {
if (allowBackup) {
ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
- // backupAgent, killAfterRestore, fullBackupContent and restoreAnyVersion are only
- // relevant if backup is possible for the given application.
+ // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
+ // and restoreAnyVersion are only relevant if backup is possible for the
+ // given application.
String backupAgent = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
Configuration.NATIVE_CONFIG_VERSION);
@@ -2694,6 +2697,11 @@ public class PackageParser {
false)) {
ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground,
+ false)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+ }
}
TypedValue v = sa.peekValue(
@@ -3447,9 +3455,8 @@ public class PackageParser {
}
} else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
- } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED
- && (a.info.flags & FLAG_IMMERSIVE) == 0) {
- a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS;
+ } else if (!a.info.isFixedOrientation() && (a.info.flags & FLAG_IMMERSIVE) == 0) {
+ a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
@@ -4740,6 +4747,12 @@ public class PackageParser {
* and prods fields out of {@code this.applicationInfo}.
*/
public String cpuAbiOverride;
+ /**
+ * The install time abi override to choose 32bit abi's when multiple abi's
+ * are present. This is only meaningfull for multiarch applications.
+ * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
+ */
+ public boolean use32bitAbi;
public Package(String packageName) {
this.packageName = packageName;
@@ -4872,12 +4885,12 @@ public class PackageParser {
}
}
- public void setCpuAbiOverride(String cpuAbiOverride) {
- this.cpuAbiOverride = cpuAbiOverride;
+ public void setUse32bitAbi(boolean use32bitAbi) {
+ this.use32bitAbi = use32bitAbi;
if (childPackages != null) {
final int packageCount = childPackages.size();
for (int i = 0; i < packageCount; i++) {
- childPackages.get(i).cpuAbiOverride = cpuAbiOverride;
+ childPackages.get(i).use32bitAbi = use32bitAbi;
}
}
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 9da2ba9ce59d..984a960b5308 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -145,11 +146,12 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_COSTS_MONEY = 1<<0;
/**
- * Flag for {@link #flags}, corresponding to <code>hidden</code>
+ * Flag for {@link #flags}, corresponding to <code>removed</code>
* value of {@link android.R.attr#permissionFlags}.
* @hide
*/
- public static final int FLAG_HIDDEN = 1<<1;
+ @SystemApi
+ public static final int FLAG_REMOVED = 1<<1;
/**
* Flag for {@link #flags}, indicating that this permission has been
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 9cf467534daf..3139151b78a0 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -73,6 +73,9 @@ public class UserInfo implements Parcelable {
/**
* Indicates that this user is disabled.
+ *
+ * <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users
+ * are disabled as their removal is in progress to indicate that they shouldn't be re-entered.
*/
public static final int FLAG_DISABLED = 0x00000040;
@@ -171,6 +174,10 @@ public class UserInfo implements Parcelable {
* @return true if this user can be switched to.
**/
public boolean supportsSwitchTo() {
+ if (isEphemeral() && !isEnabled()) {
+ // Don't support switching to an ephemeral user with removal in progress.
+ return false;
+ }
// TODO remove fw.show_hidden_users when we have finished developing managed profiles.
return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 915fae0ff6b5..a54f40fc0814 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -68,6 +68,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
import java.util.Locale;
/**
@@ -119,6 +120,9 @@ public class Resources {
private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
sPreloadedComplexColors = new LongSparseArray<>();
+ /** Size of the cyclical cache used to map XML files to blocks. */
+ private static final int XML_BLOCK_CACHE_SIZE = 4;
+
// Pool of TypedArrays targeted to this Resources object.
final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
@@ -154,8 +158,9 @@ public class Resources {
// Cyclical cache used for recently-accessed XML files.
private int mLastCachedXmlBlockIndex = -1;
- private final String[] mCachedXmlBlockFiles = new String[4];
- private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
+ private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
+ private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
+ private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
final AssetManager mAssets;
final ClassLoader mClassLoader;
@@ -769,7 +774,6 @@ public class Resources {
* @deprecated Use {@link #getDrawable(int, Theme)} instead.
*/
@Deprecated
- @Nullable
public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
final Drawable d = getDrawable(id, null);
if (d != null && d.canApplyTheme()) {
@@ -794,7 +798,6 @@ public class Resources {
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
*/
- @Nullable
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
throws NotFoundException {
final TypedValue value = obtainTempTypedValue(id);
@@ -832,7 +835,6 @@ public class Resources {
* @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
*/
@Deprecated
- @Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density)
throws NotFoundException {
return getDrawableForDensity(id, density, null);
@@ -852,7 +854,6 @@ public class Resources {
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
*/
- @Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
final TypedValue value = obtainTempTypedValue(id);
try {
@@ -2343,18 +2344,18 @@ public class Resources {
* tools.
*/
public final void flushLayoutCache() {
- final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
- final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
- synchronized (cachedXmlBlockFiles) {
- final int num = cachedXmlBlockFiles.length;
- for (int i = 0; i < num; i++) {
+ synchronized (mCachedXmlBlocks) {
+ Arrays.fill(mCachedXmlBlockCookies, 0);
+ Arrays.fill(mCachedXmlBlockFiles, null);
+
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
final XmlBlock oldBlock = cachedXmlBlocks[i];
if (oldBlock != null) {
oldBlock.close();
}
- cachedXmlBlockFiles[i] = null;
- cachedXmlBlocks[i] = null;
}
+ Arrays.fill(cachedXmlBlocks, null);
}
}
@@ -2856,13 +2857,14 @@ public class Resources {
int assetCookie, @NonNull String type) throws NotFoundException {
if (id != 0) {
try {
- final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
- final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
- synchronized (cachedXmlBlockFiles) {
+ synchronized (mCachedXmlBlocks) {
+ final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
// First see if this block is in our cache.
final int num = cachedXmlBlockFiles.length;
for (int i = 0; i < num; i++) {
- if (cachedXmlBlockFiles[i] != null
+ if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
&& cachedXmlBlockFiles[i].equals(file)) {
return cachedXmlBlocks[i].newParser();
}
@@ -2878,6 +2880,7 @@ public class Resources {
if (oldBlock != null) {
oldBlock.close();
}
+ cachedXmlBlockCookies[pos] = assetCookie;
cachedXmlBlockFiles[pos] = file;
cachedXmlBlocks[pos] = block;
return block.newParser();
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 6067577453c9..da49b64f82dd 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -426,7 +426,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
@@ -444,13 +446,13 @@ public class TypedArray {
return defValue;
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
- throw new UnsupportedOperationException("Can't convert to color: type=0x"
- + Integer.toHexString(type));
+ throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ + " to color: type=0x" + Integer.toHexString(type));
}
/**
@@ -541,7 +543,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
@@ -551,13 +555,13 @@ public class TypedArray {
return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
- throw new UnsupportedOperationException("Can't convert to integer: type=0x"
- + Integer.toHexString(type));
+ throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ + " to integer: type=0x" + Integer.toHexString(type));
}
/**
@@ -587,7 +591,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
@@ -597,13 +603,13 @@ public class TypedArray {
data[index + AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
- throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
- + Integer.toHexString(type));
+ throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ + " to dimension: type=0x" + Integer.toHexString(type));
}
/**
@@ -634,7 +640,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
@@ -644,13 +652,13 @@ public class TypedArray {
data[index + AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
- throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
- + Integer.toHexString(type));
+ throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ + " to dimension: type=0x" + Integer.toHexString(type));
}
/**
@@ -682,7 +690,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
@@ -692,13 +702,13 @@ public class TypedArray {
data[index+AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
- throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
- + Integer.toHexString(type));
+ throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ + " to dimension: type=0x" + Integer.toHexString(type));
}
/**
@@ -724,7 +734,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
@@ -735,9 +747,9 @@ public class TypedArray {
data[index+AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
throw new UnsupportedOperationException(getPositionDescription()
@@ -800,7 +812,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
+ final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
+
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
@@ -810,13 +824,13 @@ public class TypedArray {
data[index+AssetManager.STYLE_DATA], base, pbase);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
- getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+ getValueAt(index, value);
throw new UnsupportedOperationException(
- "Failed to resolve attribute at index " + index + ": " + value);
+ "Failed to resolve attribute at index " + attrIndex + ": " + value);
}
- throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
- + Integer.toHexString(type));
+ throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ + " to fraction: type=0x" + Integer.toHexString(type));
}
/**
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 02d4e59af6e4..3dbe437a6c43 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -19,6 +19,7 @@ package android.hardware;
import android.app.ActivityThread;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.job.JobInfo;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Point;
@@ -177,19 +178,27 @@ public class Camera {
private static final int NO_ERROR = 0;
/**
+ * @deprecated This broadcast is no longer delivered by the system; use
+ * {@link android.app.job.JobInfo.Builder JobInfo.Builder}.{@link android.app.job.JobInfo.Builder#addTriggerContentUri}
+ * instead.
* Broadcast Action: A new picture is taken by the camera, and the entry of
* the picture has been added to the media store.
* {@link android.content.Intent#getData} is URI of the picture.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
/**
+ * @deprecated This broadcast is no longer delivered by the system; use
+ * {@link android.app.job.JobInfo.Builder JobInfo.Builder}.{@link android.app.job.JobInfo.Builder#addTriggerContentUri}
+ * instead.
* Broadcast Action: A new video is recorded by the camera, and the entry
* of the video has been added to the media store.
* {@link android.content.Intent#getData} is URI of the video.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
/**
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 766868da9193..8724a96ee30a 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -847,6 +847,9 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* to make forward progress from the partial results and avoid waiting for the completed
* result.</p>
*
+ * <p>For a particular request, {@link #onCaptureProgressed} may happen before or after
+ * {@link #onCaptureStarted}.</p>
+ *
* <p>Each request will generate at least {@code 1} partial results, and at most
* {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
*
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 8be49e8f3ccf..6cc7fece2898 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1269,6 +1269,11 @@ public final class StreamConfigurationMap {
private Size[] getInternalFormatSizes(int format, int dataspace,
boolean output, boolean highRes) {
+ // All depth formats are non-high-res.
+ if (dataspace == HAL_DATASPACE_DEPTH && highRes) {
+ return new Size[0];
+ }
+
SparseIntArray formatsMap =
!output ? mInputFormats :
dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
@@ -1287,6 +1292,8 @@ public final class StreamConfigurationMap {
StreamConfiguration[] configurations =
(dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+ StreamConfigurationDuration[] minFrameDurations =
+ (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : mMinFrameDurations;
for (StreamConfiguration config : configurations) {
int fmt = config.getFormat();
@@ -1295,8 +1302,8 @@ public final class StreamConfigurationMap {
// Filter slow high-res output formats; include for
// highRes, remove for !highRes
long duration = 0;
- for (int i = 0; i < mMinFrameDurations.length; i++) {
- StreamConfigurationDuration d = mMinFrameDurations[i];
+ for (int i = 0; i < minFrameDurations.length; i++) {
+ StreamConfigurationDuration d = minFrameDurations[i];
if (d.getFormat() == fmt &&
d.getWidth() == config.getSize().getWidth() &&
d.getHeight() == config.getSize().getHeight()) {
@@ -1304,7 +1311,8 @@ public final class StreamConfigurationMap {
break;
}
}
- if (highRes != (duration > DURATION_20FPS_NS)) {
+ if (dataspace != HAL_DATASPACE_DEPTH &&
+ highRes != (duration > DURATION_20FPS_NS)) {
continue;
}
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 121a187b3639..93da3e5af4e9 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -132,8 +132,7 @@ public final class DisplayManagerGlobal {
return info;
}
} catch (RemoteException ex) {
- Log.e(TAG, "Could not get display information from display manager.", ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -159,8 +158,7 @@ public final class DisplayManagerGlobal {
return displayIds;
}
} catch (RemoteException ex) {
- Log.e(TAG, "Could not get display ids from display manager.", ex);
- return new int[] { Display.DEFAULT_DISPLAY };
+ throw ex.rethrowFromSystemServer();
}
}
@@ -237,8 +235,7 @@ public final class DisplayManagerGlobal {
try {
mDm.registerCallback(mCallback);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to register callback with display manager service.", ex);
- mCallback = null;
+ throw ex.rethrowFromSystemServer();
}
}
}
@@ -267,7 +264,7 @@ public final class DisplayManagerGlobal {
try {
mDm.startWifiDisplayScan();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
}
@@ -279,7 +276,7 @@ public final class DisplayManagerGlobal {
try {
mDm.stopWifiDisplayScan();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+ throw ex.rethrowFromSystemServer();
}
} else if (mWifiDisplayScanNestCount < 0) {
Log.wtf(TAG, "Wifi display scan nest count became negative: "
@@ -297,7 +294,7 @@ public final class DisplayManagerGlobal {
try {
mDm.connectWifiDisplay(deviceAddress);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -305,7 +302,7 @@ public final class DisplayManagerGlobal {
try {
mDm.pauseWifiDisplay();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to pause Wifi display.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -313,7 +310,7 @@ public final class DisplayManagerGlobal {
try {
mDm.resumeWifiDisplay();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to resume Wifi display.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -321,7 +318,7 @@ public final class DisplayManagerGlobal {
try {
mDm.disconnectWifiDisplay();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -333,8 +330,7 @@ public final class DisplayManagerGlobal {
try {
mDm.renameWifiDisplay(deviceAddress, alias);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
- + " with alias " + alias + ".", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -346,7 +342,7 @@ public final class DisplayManagerGlobal {
try {
mDm.forgetWifiDisplay(deviceAddress);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to forget Wifi display.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -354,8 +350,7 @@ public final class DisplayManagerGlobal {
try {
return mDm.getWifiDisplayStatus();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to get Wifi display status.", ex);
- return new WifiDisplayStatus();
+ throw ex.rethrowFromSystemServer();
}
}
@@ -363,7 +358,7 @@ public final class DisplayManagerGlobal {
try {
mDm.requestColorTransform(displayId, colorTransformId);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to request color transform.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -385,8 +380,7 @@ public final class DisplayManagerGlobal {
displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
context.getPackageName(), name, width, height, densityDpi, surface, flags);
} catch (RemoteException ex) {
- Log.e(TAG, "Could not create virtual display: " + name, ex);
- return null;
+ throw ex.rethrowFromSystemServer();
}
if (displayId < 0) {
Log.e(TAG, "Could not create virtual display: " + name);
@@ -399,6 +393,7 @@ public final class DisplayManagerGlobal {
try {
mDm.releaseVirtualDisplay(callbackWrapper);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
return null;
}
@@ -409,7 +404,7 @@ public final class DisplayManagerGlobal {
try {
mDm.setVirtualDisplaySurface(token, surface);
} catch (RemoteException ex) {
- Log.w(TAG, "Failed to set virtual display surface.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -418,7 +413,7 @@ public final class DisplayManagerGlobal {
try {
mDm.resizeVirtualDisplay(token, width, height, densityDpi);
} catch (RemoteException ex) {
- Log.w(TAG, "Failed to resize virtual display.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
@@ -426,7 +421,7 @@ public final class DisplayManagerGlobal {
try {
mDm.releaseVirtualDisplay(token);
} catch (RemoteException ex) {
- Log.w(TAG, "Failed to release virtual display.", ex);
+ throw ex.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index aa697eadcbca..13ba6cc37d22 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -211,6 +211,9 @@ 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;
@@ -242,6 +245,7 @@ public abstract class DisplayManagerInternal {
boostScreenBrightness = other.boostScreenBrightness;
dozeScreenBrightness = other.dozeScreenBrightness;
dozeScreenState = other.dozeScreenState;
+ useTwilight = other.useTwilight;
}
@Override
@@ -262,7 +266,8 @@ public abstract class DisplayManagerInternal {
&& lowPowerMode == other.lowPowerMode
&& boostScreenBrightness == other.boostScreenBrightness
&& dozeScreenBrightness == other.dozeScreenBrightness
- && dozeScreenState == other.dozeScreenState;
+ && dozeScreenState == other.dozeScreenState
+ && useTwilight == other.useTwilight;
}
@Override
@@ -282,7 +287,8 @@ public abstract class DisplayManagerInternal {
+ ", lowPowerMode=" + lowPowerMode
+ ", boostScreenBrightness=" + boostScreenBrightness
+ ", dozeScreenBrightness=" + dozeScreenBrightness
- + ", dozeScreenState=" + Display.stateToString(dozeScreenState);
+ + ", dozeScreenState=" + Display.stateToString(dozeScreenState)
+ + ", useTwilight=" + useTwilight;
}
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 9f8c28ee1216..abd02f0ecc9b 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -40,6 +40,7 @@ import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
@@ -655,8 +656,23 @@ public class FingerprintManager {
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
if (mService != null) try {
- return mService.hasEnrolledFingerprints(UserHandle.myUserId(),
- mContext.getOpPackageName());
+ return mService.hasEnrolledFingerprints(
+ UserHandle.myUserId(), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(allOf = {
+ USE_FINGERPRINT,
+ INTERACT_ACROSS_USERS})
+ public boolean hasEnrolledFingerprints(int userId) {
+ if (mService != null) try {
+ return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
}
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index 597efa566d2c..dcc336966810 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -26,10 +26,20 @@ oneway interface IRecognitionStatusCallback {
* Called when the keyphrase is spoken.
*
* @param recognitionEvent Object containing data relating to the
- * recognition event such as trigger audio data, if it was requested
- * and is available.
+ * keyphrase recognition event such as keyphrase
+ * extras.
*/
- void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent);
+ void onKeyphraseDetected(in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent);
+
+ /**
+ * Called when a generic sound trigger event is witnessed.
+ *
+ * @param recognitionEvent Object containing data relating to the
+ * recognition event such as trigger audio data (if
+ * requested).
+ */
+
+ void onGenericSoundTriggerDetected(in SoundTrigger.GenericRecognitionEvent recognitionEvent);
/**
* Called when the detection fails due to an error.
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index fec64ea338ea..325a9addc8ff 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -20,7 +20,7 @@ parcelable SoundTrigger.ConfidenceLevel;
parcelable SoundTrigger.Keyphrase;
parcelable SoundTrigger.RecognitionEvent;
parcelable SoundTrigger.KeyphraseRecognitionEvent;
-parcelable SoundTrigger.GenericSoundRecognitionEvent;
+parcelable SoundTrigger.GenericRecognitionEvent;
parcelable SoundTrigger.KeyphraseRecognitionExtra;
parcelable SoundTrigger.KeyphraseSoundModel;
parcelable SoundTrigger.GenericSoundModel;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 882908a9f46e..cc2b7643d3e6 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -595,7 +595,7 @@ public class SoundTrigger {
}
};
- private static RecognitionEvent fromParcel(Parcel in) {
+ protected static RecognitionEvent fromParcel(Parcel in) {
int status = in.readInt();
int soundModelHandle = in.readInt();
boolean captureAvailable = in.readByte() == 1;
@@ -980,7 +980,7 @@ public class SoundTrigger {
public static final Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
= new Parcelable.Creator<KeyphraseRecognitionEvent>() {
public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
- return KeyphraseRecognitionEvent.fromParcel(in);
+ return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
}
public KeyphraseRecognitionEvent[] newArray(int size) {
@@ -988,7 +988,7 @@ public class SoundTrigger {
}
};
- private static KeyphraseRecognitionEvent fromParcel(Parcel in) {
+ private static KeyphraseRecognitionEvent fromParcelForKeyphrase(Parcel in) {
int status = in.readInt();
int soundModelHandle = in.readInt();
boolean captureAvailable = in.readByte() == 1;
@@ -1094,6 +1094,40 @@ public class SoundTrigger {
captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
data);
}
+
+ public static final Parcelable.Creator<GenericRecognitionEvent> CREATOR
+ = new Parcelable.Creator<GenericRecognitionEvent>() {
+ public GenericRecognitionEvent createFromParcel(Parcel in) {
+ return GenericRecognitionEvent.fromParcelForGeneric(in);
+ }
+
+ public GenericRecognitionEvent[] newArray(int size) {
+ return new GenericRecognitionEvent[size];
+ }
+ };
+
+ private static GenericRecognitionEvent fromParcelForGeneric(Parcel in) {
+ RecognitionEvent event = RecognitionEvent.fromParcel(in);
+ return new GenericRecognitionEvent(event.status, event.soundModelHandle,
+ event.captureAvailable, event.captureSession, event.captureDelayMs,
+ event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass()) return false;
+ RecognitionEvent other = (RecognitionEvent) obj;
+ return super.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return "GenericRecognitionEvent ::" + super.toString();
+ }
}
/**
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 1e3bcd0fc796..3792e5c03756 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -302,8 +302,7 @@ public class UsbManager {
}
return result;
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getDeviceList", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -347,8 +346,7 @@ public class UsbManager {
return new UsbAccessory[] { accessory };
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getAccessoryList", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -362,8 +360,7 @@ public class UsbManager {
try {
return mService.openAccessory(accessory);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in openAccessory", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -380,8 +377,7 @@ public class UsbManager {
try {
return mService.hasDevicePermission(device);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in hasPermission", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -398,8 +394,7 @@ public class UsbManager {
try {
return mService.hasAccessoryPermission(accessory);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in hasPermission", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -425,7 +420,7 @@ public class UsbManager {
try {
mService.requestDevicePermission(device, mContext.getPackageName(), pi);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in requestPermission", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -451,7 +446,7 @@ public class UsbManager {
try {
mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in requestPermission", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -466,7 +461,7 @@ public class UsbManager {
try {
mService.grantDevicePermission(device, Process.myUid());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in grantPermission", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -486,8 +481,7 @@ public class UsbManager {
try {
return mService.isFunctionEnabled(function);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in setCurrentFunction", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -517,7 +511,7 @@ public class UsbManager {
try {
mService.setCurrentFunction(function);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in setCurrentFunction", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -533,7 +527,7 @@ public class UsbManager {
try {
mService.setUsbDataUnlocked(unlocked);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in setUsbDataUnlocked", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -554,9 +548,8 @@ public class UsbManager {
try {
return mService.getPorts();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getPorts", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -573,9 +566,8 @@ public class UsbManager {
try {
return mService.getPortStatus(port.getId());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getPortStatus", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -604,7 +596,7 @@ public class UsbManager {
try {
mService.setPortRoles(port.getId(), powerRole, dataRole);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in setPortRole", e);
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/net/BaseDhcpStateMachine.java b/core/java/android/net/BaseDhcpStateMachine.java
deleted file mode 100644
index a25847daa8f2..000000000000
--- a/core/java/android/net/BaseDhcpStateMachine.java
+++ /dev/null
@@ -1,35 +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 android.net;
-
-import com.android.internal.util.StateMachine;
-
-/**
- * Interface that must be implemented by DHCP state machines.
- *
- * This is an abstract class instead of a Java interface so that callers can just declare an object
- * of this type and be able to call all the methods defined by either StateMachine or this class.
- *
- * @hide
- */
-public abstract class BaseDhcpStateMachine extends StateMachine {
- protected BaseDhcpStateMachine(String tag) {
- super(tag);
- }
- public abstract void registerForPreDhcpNotification();
- public abstract void doQuit();
-}
diff --git a/core/java/android/net/ConnectivityMetricsEvent.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
new file mode 100644
index 000000000000..da175614b588
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ConnectivityMetricsEvent;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
new file mode 100644
index 000000000000..d040a8563440
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+@SystemApi
+public class ConnectivityMetricsEvent implements Parcelable {
+
+ /** The time when this event was collected, as returned by System.currentTimeMillis(). */
+ final public long timestamp;
+
+ /** The subsystem that generated the event. One of the COMPONENT_TAG_xxx constants. */
+ final public int componentTag;
+
+ /** The subsystem-specific event ID. */
+ final public int eventTag;
+
+ /** Opaque event-specific data. */
+ final public Parcelable data;
+
+ public ConnectivityMetricsEvent(long timestamp, int componentTag,
+ int eventTag, Parcelable data) {
+ this.timestamp = timestamp;
+ this.componentTag = componentTag;
+ this.eventTag = eventTag;
+ this.data = data;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<ConnectivityMetricsEvent> CREATOR
+ = new Parcelable.Creator<ConnectivityMetricsEvent> (){
+ public ConnectivityMetricsEvent createFromParcel(Parcel source) {
+ final long timestamp = source.readLong();
+ final int componentTag = source.readInt();
+ final int eventTag = source.readInt();
+ final Parcelable data = source.readParcelable(null);
+ return new ConnectivityMetricsEvent(timestamp, componentTag,
+ eventTag, data);
+ }
+
+ public ConnectivityMetricsEvent[] newArray(int size) {
+ return new ConnectivityMetricsEvent[size];
+ }
+ };
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(timestamp);
+ dest.writeInt(componentTag);
+ dest.writeInt(eventTag);
+ dest.writeParcelable(data, 0);
+ }
+
+ public String toString() {
+ return String.format("ConnectivityMetricsEvent(%d, %d, %d)", timestamp,
+ componentTag, eventTag);
+ }
+}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
new file mode 100644
index 000000000000..3ef805017f14
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/** {@hide} */
+public class ConnectivityMetricsLogger {
+ private static String TAG = "ConnectivityMetricsLogger";
+ private static final boolean DBG = true;
+
+ public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
+
+ // Component Tags
+ public static final int COMPONENT_TAG_CONNECTIVITY = 1;
+ public static final int COMPONENT_TAG_BLUETOOTH = 2;
+ public static final int COMPONENT_TAG_WIFI = 3;
+ public static final int COMPONENT_TAG_TELECOM = 4;
+ public static final int COMPONENT_TAG_TELEPHONY = 5;
+
+ private IConnectivityMetricsLogger mService;
+
+ public ConnectivityMetricsLogger() {
+ mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
+ CONNECTIVITY_METRICS_LOGGER_SERVICE));
+ }
+
+ public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
+ if (mService == null) {
+ if (DBG) {
+ Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
+ }
+ } else {
+ try {
+ mService.logEvent(new ConnectivityMetricsEvent(timestamp, componentTag, eventTag, data));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error logging event " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java
index 0e46f4c0cbdf..5e96cc1fe04a 100644
--- a/core/java/android/net/DataUsageRequest.java
+++ b/core/java/android/net/DataUsageRequest.java
@@ -34,6 +34,11 @@ public class DataUsageRequest implements Parcelable {
/**
* @hide
*/
+ public static final String PARCELABLE_KEY = "DataUsageRequest";
+
+ /**
+ * @hide
+ */
public static final int REQUEST_ID_UNSET = 0;
/**
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
deleted file mode 100644
index 73ef78e12794..000000000000
--- a/core/java/android/net/DhcpStateMachine.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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 com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.DhcpResults;
-import android.net.NetworkUtils;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.util.Log;
-
-/**
- * StateMachine that interacts with the native DHCP client and can talk to
- * a controller that also needs to be a StateMachine
- *
- * The DhcpStateMachine provides the following features:
- * - Wakeup and renewal using the native DHCP client (which will not renew
- * on its own when the device is in suspend state and this can lead to device
- * holding IP address beyond expiry)
- * - A notification right before DHCP request or renewal is started. This
- * can be used for any additional setup before DHCP. For example, wifi sets
- * BT-Wifi coex settings right before DHCP is initiated
- *
- * @hide
- */
-public class DhcpStateMachine extends BaseDhcpStateMachine {
-
- private static final String TAG = "DhcpStateMachine";
- private static final boolean DBG = false;
-
-
- /* A StateMachine that controls the DhcpStateMachine */
- private StateMachine mController;
-
- private Context mContext;
- private BroadcastReceiver mBroadcastReceiver;
- private AlarmManager mAlarmManager;
- private PendingIntent mDhcpRenewalIntent;
- private PowerManager.WakeLock mDhcpRenewWakeLock;
- private static final String WAKELOCK_TAG = "DHCP";
-
- //Remember DHCP configuration from first request
- private DhcpResults mDhcpResults;
-
- private static final int DHCP_RENEW = 0;
- private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
-
- //Used for sanity check on setting up renewal
- private static final int MIN_RENEWAL_TIME_SECS = 5 * 60; // 5 minutes
-
- private final String mInterfaceName;
- private boolean mRegisteredForPreDhcpNotification = false;
-
- private static final int BASE = Protocol.BASE_DHCP;
-
- /* Commands from controller to start/stop DHCP */
- public static final int CMD_START_DHCP = BASE + 1;
- public static final int CMD_STOP_DHCP = BASE + 2;
- public static final int CMD_RENEW_DHCP = BASE + 3;
-
- /* Notification from DHCP state machine prior to DHCP discovery/renewal */
- public static final int CMD_PRE_DHCP_ACTION = BASE + 4;
- /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
- * success/failure */
- public static final int CMD_POST_DHCP_ACTION = BASE + 5;
- /* Notification from DHCP state machine before quitting */
- public static final int CMD_ON_QUIT = BASE + 6;
-
- /* Command from controller to indicate DHCP discovery/renewal can continue
- * after pre DHCP action is complete */
- public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 7;
-
- /* Command from ourselves to see if DHCP results are available */
- private static final int CMD_GET_DHCP_RESULTS = BASE + 8;
-
- /* Message.arg1 arguments to CMD_POST_DHCP notification */
- public static final int DHCP_SUCCESS = 1;
- public static final int DHCP_FAILURE = 2;
-
- private State mDefaultState = new DefaultState();
- private State mStoppedState = new StoppedState();
- private State mWaitBeforeStartState = new WaitBeforeStartState();
- private State mRunningState = new RunningState();
- private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
- private State mPollingState = new PollingState();
-
- private DhcpStateMachine(Context context, StateMachine controller, String intf) {
- super(TAG);
-
- mContext = context;
- mController = controller;
- mInterfaceName = intf;
-
- mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
- Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
- mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
-
- PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
- mDhcpRenewWakeLock.setReferenceCounted(false);
-
- mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- //DHCP renew
- if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
- //Lock released after 40s in worst case scenario
- mDhcpRenewWakeLock.acquire(40000);
- sendMessage(CMD_RENEW_DHCP);
- }
- };
- mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
-
- addState(mDefaultState);
- addState(mStoppedState, mDefaultState);
- addState(mWaitBeforeStartState, mDefaultState);
- addState(mPollingState, mDefaultState);
- addState(mRunningState, mDefaultState);
- addState(mWaitBeforeRenewalState, mDefaultState);
-
- setInitialState(mStoppedState);
- }
-
- public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
- String intf) {
- DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
- dsm.start();
- return dsm;
- }
-
- /**
- * This sends a notification right before DHCP request/renewal so that the
- * controller can do certain actions before DHCP packets are sent out.
- * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
- * to indicate DHCP can continue
- *
- * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
- * handling during Dhcp
- */
- @Override
- public void registerForPreDhcpNotification() {
- mRegisteredForPreDhcpNotification = true;
- }
-
- /**
- * Quit the DhcpStateMachine.
- *
- * @hide
- */
- @Override
- public void doQuit() {
- quit();
- }
-
- protected void onQuitting() {
- mController.sendMessage(CMD_ON_QUIT);
- }
-
- class DefaultState extends State {
- @Override
- public void exit() {
- mContext.unregisterReceiver(mBroadcastReceiver);
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_RENEW_DHCP:
- Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
- mDhcpRenewWakeLock.release();
- break;
- default:
- Log.e(TAG, "Error! unhandled message " + message);
- break;
- }
- return HANDLED;
- }
- }
-
-
- class StoppedState extends State {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- if (!NetworkUtils.stopDhcp(mInterfaceName)) {
- Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
- }
- mDhcpResults = null;
- }
-
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = HANDLED;
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_START_DHCP:
- if (mRegisteredForPreDhcpNotification) {
- /* Notify controller before starting DHCP */
- mController.sendMessage(CMD_PRE_DHCP_ACTION);
- transitionTo(mWaitBeforeStartState);
- } else {
- if (runDhcpStart()) {
- transitionTo(mRunningState);
- }
- }
- break;
- case CMD_STOP_DHCP:
- //ignore
- break;
- default:
- retValue = NOT_HANDLED;
- break;
- }
- return retValue;
- }
- }
-
- class WaitBeforeStartState extends State {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- }
-
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = HANDLED;
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_PRE_DHCP_ACTION_COMPLETE:
- if (runDhcpStart()) {
- transitionTo(mRunningState);
- } else {
- transitionTo(mPollingState);
- }
- break;
- case CMD_STOP_DHCP:
- transitionTo(mStoppedState);
- break;
- case CMD_START_DHCP:
- //ignore
- break;
- default:
- retValue = NOT_HANDLED;
- break;
- }
- return retValue;
- }
- }
-
- class PollingState extends State {
- private static final long MAX_DELAY_SECONDS = 32;
- private long delaySeconds;
-
- private void scheduleNextResultsCheck() {
- sendMessageDelayed(obtainMessage(CMD_GET_DHCP_RESULTS), delaySeconds * 1000);
- delaySeconds *= 2;
- if (delaySeconds > MAX_DELAY_SECONDS) {
- delaySeconds = MAX_DELAY_SECONDS;
- }
- }
-
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, "Entering " + getName() + "\n");
- delaySeconds = 1;
- scheduleNextResultsCheck();
- }
-
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = HANDLED;
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_GET_DHCP_RESULTS:
- if (DBG) Log.d(TAG, "GET_DHCP_RESULTS on " + mInterfaceName);
- if (dhcpSucceeded()) {
- transitionTo(mRunningState);
- } else {
- scheduleNextResultsCheck();
- }
- break;
- case CMD_STOP_DHCP:
- transitionTo(mStoppedState);
- break;
- default:
- retValue = NOT_HANDLED;
- break;
- }
- return retValue;
- }
-
- @Override
- public void exit() {
- if (DBG) Log.d(TAG, "Exiting " + getName() + "\n");
- removeMessages(CMD_GET_DHCP_RESULTS);
- }
- }
-
- class RunningState extends State {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- }
-
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = HANDLED;
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_STOP_DHCP:
- mAlarmManager.cancel(mDhcpRenewalIntent);
- transitionTo(mStoppedState);
- break;
- case CMD_RENEW_DHCP:
- if (mRegisteredForPreDhcpNotification) {
- /* Notify controller before starting DHCP */
- mController.sendMessage(CMD_PRE_DHCP_ACTION);
- transitionTo(mWaitBeforeRenewalState);
- //mDhcpRenewWakeLock is released in WaitBeforeRenewalState
- } else {
- if (!runDhcpRenew()) {
- transitionTo(mStoppedState);
- }
- mDhcpRenewWakeLock.release();
- }
- break;
- case CMD_START_DHCP:
- //ignore
- break;
- default:
- retValue = NOT_HANDLED;
- }
- return retValue;
- }
- }
-
- class WaitBeforeRenewalState extends State {
- @Override
- public void enter() {
- if (DBG) Log.d(TAG, getName() + "\n");
- }
-
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = HANDLED;
- if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_STOP_DHCP:
- mAlarmManager.cancel(mDhcpRenewalIntent);
- transitionTo(mStoppedState);
- break;
- case CMD_PRE_DHCP_ACTION_COMPLETE:
- if (runDhcpRenew()) {
- transitionTo(mRunningState);
- } else {
- transitionTo(mStoppedState);
- }
- break;
- case CMD_START_DHCP:
- //ignore
- break;
- default:
- retValue = NOT_HANDLED;
- break;
- }
- return retValue;
- }
- @Override
- public void exit() {
- mDhcpRenewWakeLock.release();
- }
- }
-
- private boolean dhcpSucceeded() {
- DhcpResults dhcpResults = new DhcpResults();
- if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) {
- return false;
- }
-
- if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName);
- long leaseDuration = dhcpResults.leaseDuration; //int to long conversion
-
- //Sanity check for renewal
- if (leaseDuration >= 0) {
- //TODO: would be good to notify the user that his network configuration is
- //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
- if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
- leaseDuration = MIN_RENEWAL_TIME_SECS;
- }
- //Do it a bit earlier than half the lease duration time
- //to beat the native DHCP client and avoid extra packets
- //48% for one hour lease time = 29 minutes
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() +
- leaseDuration * 480, //in milliseconds
- mDhcpRenewalIntent);
- } else {
- //infinite lease time, no renewal needed
- }
-
- // Fill in any missing fields in dhcpResults from the previous results.
- // If mDhcpResults is null (i.e. this is the first server response),
- // this is a noop.
- dhcpResults.updateFromDhcpRequest(mDhcpResults);
- mDhcpResults = dhcpResults;
- mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults)
- .sendToTarget();
- return true;
- }
-
- private boolean runDhcpStart() {
- /* Stop any existing DHCP daemon before starting new */
- NetworkUtils.stopDhcp(mInterfaceName);
- mDhcpResults = null;
-
- if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
- if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) {
- Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " +
- NetworkUtils.getDhcpError());
- mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
- .sendToTarget();
- return false;
- }
- return true;
- }
-
- private boolean runDhcpRenew() {
- if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
- if (!NetworkUtils.startDhcpRenew(mInterfaceName) || !dhcpSucceeded()) {
- Log.e(TAG, "DHCP renew failed on " + mInterfaceName + ": " +
- NetworkUtils.getDhcpError());
- mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
- .sendToTarget();
- return false;
- }
- return true;
- }
-}
diff --git a/tools/aapt2/util/Comparators.h b/core/java/android/net/IConnectivityMetricsLogger.aidl
index 0ee0bf35457d..27786712a5c5 100644
--- a/tools/aapt2/util/Comparators.h
+++ b/core/java/android/net/IConnectivityMetricsLogger.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,17 @@
* limitations under the License.
*/
-#ifndef AAPT_UTIL_COMPARATORS_H
-#define AAPT_UTIL_COMPARATORS_H
+package android.net;
-#include "ConfigDescription.h"
-#include "ResourceTable.h"
+import android.net.ConnectivityMetricsEvent;
+import android.net.IConnectivityMetricsLoggerSubscriber;
-namespace aapt {
-namespace cmp {
+/** {@hide} */
+interface IConnectivityMetricsLogger {
-inline bool lessThanConfig(const ResourceConfigValue& a, const ConfigDescription& b) {
- return a.config < b;
-}
+ void logEvent(in ConnectivityMetricsEvent event);
+ void logEvents(in ConnectivityMetricsEvent[] events);
-inline bool lessThanType(const std::unique_ptr<ResourceTableType>& a, ResourceType b) {
- return a->type < b;
+ boolean subscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+ void unsubscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
}
-
-} // namespace cmp
-} // namespace aapt
-
-#endif /* AAPT_UTIL_COMPARATORS_H */
diff --git a/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
new file mode 100644
index 000000000000..a2c62cdaee97
--- /dev/null
+++ b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+import android.net.ConnectivityMetricsEvent;
+
+/** {@hide} */
+oneway interface IConnectivityMetricsLoggerSubscriber {
+
+ void onEvents(in ConnectivityMetricsEvent[] events);
+}
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 6436e4267655..2eea9408f96a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -16,10 +16,13 @@
package android.net;
+import android.net.DataUsageRequest;
import android.net.INetworkStatsSession;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.os.IBinder;
+import android.os.Messenger;
/** {@hide} */
interface INetworkStatsService {
@@ -57,4 +60,11 @@ interface INetworkStatsService {
/** Advise persistance threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
+ /** Registers a callback on data usage. */
+ DataUsageRequest registerDataUsageCallback(String callingPackage,
+ in DataUsageRequest request, in Messenger messenger, in IBinder binder);
+
+ /** Unregisters a callback on data usage. */
+ void unregisterDataUsageRequest(in DataUsageRequest request);
+
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index e88bc26851e7..9870e7b6fa0c 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -20,7 +20,12 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.BackupUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import java.util.Objects;
/**
@@ -30,6 +35,11 @@ import java.util.Objects;
* @hide
*/
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
+ /**
+ * Current Version of the Backup Serializer.
+ */
+ private static final int BACKUP_VERSION = 1;
+
public static final int CYCLE_NONE = -1;
public static final long WARNING_DISABLED = -1;
public static final long LIMIT_DISABLED = -1;
@@ -191,4 +201,41 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
return new NetworkPolicy[size];
}
};
+
+ public byte[] getBytesForBackup() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+
+ out.writeInt(BACKUP_VERSION);
+ out.write(template.getBytesForBackup());
+ out.writeInt(cycleDay);
+ BackupUtils.writeString(out, cycleTimezone);
+ out.writeLong(warningBytes);
+ out.writeLong(limitBytes);
+ out.writeLong(lastWarningSnooze);
+ out.writeLong(lastLimitSnooze);
+ out.writeInt(metered ? 1 : 0);
+ out.writeInt(inferred ? 1 : 0);
+ return baos.toByteArray();
+ }
+
+ public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
+ BackupUtils.BadVersionException {
+ int version = in.readInt();
+ if (version < 1 || version > BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+ }
+
+ NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
+ int cycleDay = in.readInt();
+ String cycleTimeZone = BackupUtils.readString(in);
+ long warningBytes = in.readLong();
+ long limitBytes = in.readLong();
+ long lastWarningSnooze = in.readLong();
+ long lastLimitSnooze = in.readLong();
+ boolean metered = in.readInt() == 1;
+ boolean inferred = in.readInt() == 1;
+ return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes,
+ lastWarningSnooze, lastLimitSnooze, metered, inferred);
+ }
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a83e72240310..94de93329294 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -106,6 +106,7 @@ public class NetworkPolicyManager {
try {
mService.setUidPolicy(uid, policy);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -118,6 +119,7 @@ public class NetworkPolicyManager {
try {
mService.addUidPolicy(uid, policy);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -130,6 +132,7 @@ public class NetworkPolicyManager {
try {
mService.removeUidPolicy(uid, policy);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -137,7 +140,7 @@ public class NetworkPolicyManager {
try {
return mService.getUidPolicy(uid);
} catch (RemoteException e) {
- return POLICY_NONE;
+ throw e.rethrowFromSystemServer();
}
}
@@ -145,7 +148,7 @@ public class NetworkPolicyManager {
try {
return mService.getUidsWithPolicy(policy);
} catch (RemoteException e) {
- return new int[0];
+ throw e.rethrowFromSystemServer();
}
}
@@ -153,6 +156,7 @@ public class NetworkPolicyManager {
try {
mService.registerListener(listener);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -160,6 +164,7 @@ public class NetworkPolicyManager {
try {
mService.unregisterListener(listener);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -167,6 +172,7 @@ public class NetworkPolicyManager {
try {
mService.setNetworkPolicies(policies);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -174,7 +180,7 @@ public class NetworkPolicyManager {
try {
return mService.getNetworkPolicies(mContext.getOpPackageName());
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -182,6 +188,7 @@ public class NetworkPolicyManager {
try {
mService.setRestrictBackground(restrictBackground);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -189,7 +196,7 @@ public class NetworkPolicyManager {
try {
return mService.getRestrictBackground();
} catch (RemoteException e) {
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -202,6 +209,7 @@ public class NetworkPolicyManager {
try {
mService.factoryReset(subscriber);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 3f36d65e577c..b6fe68af51ac 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -105,7 +105,8 @@ public class NetworkScoreManager {
/**
* Broadcast action: the active scorer has been changed. Scorer apps may listen to this to
* perform initialization once selected as the active scorer, or clean up unneeded resources
- * if another scorer has been selected. Note that it is unnecessary to clear existing scores as
+ * if another scorer has been selected. This is an explicit broadcast only sent to the
+ * previous scorer and new scorer. Note that it is unnecessary to clear existing scores as
* this is handled by the system.
*
* <p>The new scorer will be specified in {@link #EXTRA_NEW_SCORER}.
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index b7a411e4b646..5761d66dde87 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -28,15 +28,21 @@ import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
import static android.telephony.TelephonyManager.getNetworkClass;
+
import static com.android.internal.util.ArrayUtils.contains;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.BackupUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
@@ -47,6 +53,10 @@ import java.util.Objects;
* @hide
*/
public class NetworkTemplate implements Parcelable {
+ /**
+ * Current Version of the Backup Serializer.
+ */
+ private static final int BACKUP_VERSION = 1;
public static final int MATCH_MOBILE_ALL = 1;
@Deprecated
@@ -443,4 +453,31 @@ public class NetworkTemplate implements Parcelable {
return new NetworkTemplate[size];
}
};
+
+ public byte[] getBytesForBackup() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+
+ out.writeInt(BACKUP_VERSION);
+
+ out.writeInt(mMatchRule);
+ BackupUtils.writeString(out, mSubscriberId);
+ BackupUtils.writeString(out, mNetworkId);
+
+ return baos.toByteArray();
+ }
+
+ public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
+ throws IOException, BackupUtils.BadVersionException {
+ int version = in.readInt();
+ if (version < 1 || version > BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+ }
+
+ int matchRule = in.readInt();
+ String subscriberId = BackupUtils.readString(in);
+ String networkId = BackupUtils.readString(in);
+
+ return new NetworkTemplate(matchRule, subscriberId, networkId);
+ }
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4487cab9e182..c6d919f4d77e 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -57,90 +57,6 @@ public class NetworkUtils {
public native static int resetConnections(String interfaceName, int mask);
/**
- * Start the DHCP client daemon, in order to have it request addresses
- * for the named interface. This returns {@code true} if the DHCPv4 daemon
- * starts, {@code false} otherwise. This call blocks until such time as a
- * result is available or the default discovery timeout has been reached.
- * Callers should check {@link #getDhcpResults} to determine whether DHCP
- * succeeded or failed, and if it succeeded, to fetch the {@link DhcpResults}.
- * @param interfaceName the name of the interface to configure
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean startDhcp(String interfaceName);
-
- /**
- * Initiate renewal on the DHCP client daemon for the named interface. This
- * returns {@code true} if the DHCPv4 daemon has been notified, {@code false}
- * otherwise. This call blocks until such time as a result is available or
- * the default renew timeout has been reached. Callers should check
- * {@link #getDhcpResults} to determine whether DHCP succeeded or failed,
- * and if it succeeded, to fetch the {@link DhcpResults}.
- * @param interfaceName the name of the interface to configure
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean startDhcpRenew(String interfaceName);
-
- /**
- * Start the DHCP client daemon, in order to have it request addresses
- * for the named interface, and then configure the interface with those
- * addresses. This call blocks until it obtains a result (either success
- * or failure) from the daemon.
- * @param interfaceName the name of the interface to configure
- * @param dhcpResults if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public static boolean runDhcp(String interfaceName, DhcpResults dhcpResults) {
- return startDhcp(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
- }
-
- /**
- * Initiate renewal on the DHCP client daemon. This call blocks until it obtains
- * a result (either success or failure) from the daemon.
- * @param interfaceName the name of the interface to configure
- * @param dhcpResults if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults) {
- return startDhcpRenew(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
- }
-
- /**
- * Fetch results from the DHCP client daemon. This call returns {@code true} if
- * if there are results available to be read, {@code false} otherwise.
- * @param interfaceName the name of the interface to configure
- * @param dhcpResults if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean getDhcpResults(String interfaceName, DhcpResults dhcpResults);
-
- /**
- * Shut down the DHCP client daemon.
- * @param interfaceName the name of the interface for which the daemon
- * should be stopped
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean stopDhcp(String interfaceName);
-
- /**
- * Release the current DHCP lease.
- * @param interfaceName the name of the interface for which the lease should
- * be released
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean releaseDhcpLease(String interfaceName);
-
- /**
- * Return the last DHCP-related error message that was recorded.
- * <p/>NOTE: This string is not localized, but currently it is only
- * used in logging.
- * @return the most recent error message, if any
- */
- public native static String getDhcpError();
-
- /**
* Attaches a socket filter that accepts DHCP packets to the given socket.
*/
public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index e82485da32f7..ba8bd34bfc6d 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -310,7 +310,7 @@ public class TrafficStats {
try {
getStatsService().incrementOperationCount(uid, tag, operationCount);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -653,7 +653,7 @@ public class TrafficStats {
try {
return getStatsService().getDataLayerSnapshotForUid(uid);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -666,7 +666,7 @@ public class TrafficStats {
try {
return getStatsService().getMobileIfaces();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index acd780d9ecad..6f911ceb4bed 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -414,7 +414,7 @@ public final class NfcAdapter {
return false;
}
try {
- return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
+ return pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0);
} catch (RemoteException e) {
Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
return false;
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 23d05bda3633..b49288e6e59e 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -156,7 +156,7 @@ public final class CardEmulation {
throw new UnsupportedOperationException();
}
try {
- if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) {
Log.e(TAG, "This device does not support card emulation");
throw new UnsupportedOperationException();
}
diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
index d61ac02eb98e..42ccf20a584a 100644
--- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
+++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
@@ -77,7 +77,7 @@ public final class NfcFCardEmulation {
throw new UnsupportedOperationException();
}
try {
- if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) {
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 0)) {
Log.e(TAG, "This device does not support NFC-F card emulation");
throw new UnsupportedOperationException();
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b33e807235bf..8281279bec68 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -623,7 +623,7 @@ public abstract class BatteryStats implements Parcelable {
/**
* The statistics associated with a particular service.
*/
- public abstract class Serv {
+ public static abstract class Serv {
/**
* Returns the amount of time spent started.
@@ -2827,7 +2827,7 @@ public abstract class BatteryStats implements Parcelable {
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA, wifiOnTime / 1000,
- wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
+ wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0);
dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_WIFI_CONTROLLER_DATA,
getWifiControllerActivity(), which);
diff --git a/core/java/android/os/CpuUsageInfo.aidl b/core/java/android/os/CpuUsageInfo.aidl
new file mode 100644
index 000000000000..f81aefe4423f
--- /dev/null
+++ b/core/java/android/os/CpuUsageInfo.aidl
@@ -0,0 +1,18 @@
+/* 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 may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+parcelable CpuUsageInfo;
diff --git a/core/java/android/os/DeadSystemException.java b/core/java/android/os/DeadSystemException.java
new file mode 100644
index 000000000000..595365c55472
--- /dev/null
+++ b/core/java/android/os/DeadSystemException.java
@@ -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.os;
+
+/**
+ * The core Android system has died and is going through a runtime restart. All
+ * running apps will be promptly be killed.
+ */
+public class DeadSystemException extends DeadObjectException {
+ public DeadSystemException() {
+ super();
+ }
+}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index e58744bfd905..f3822413add3 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -98,13 +98,15 @@ public final class Debug
/**
* Default trace file path and file
*/
- private static final String DEFAULT_TRACE_PATH_PREFIX =
- Environment.getLegacyExternalStorageDirectory().getPath() + "/";
private static final String DEFAULT_TRACE_BODY = "dmtrace";
private static final String DEFAULT_TRACE_EXTENSION = ".trace";
- private static final String DEFAULT_TRACE_FILE_PATH =
- DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
- + DEFAULT_TRACE_EXTENSION;
+ private static class NoPreloadHolder {
+ private static final String DEFAULT_TRACE_PATH_PREFIX =
+ Environment.getLegacyExternalStorageDirectory().getPath() + "/";
+ private static final String DEFAULT_TRACE_FILE_PATH =
+ DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
+ + DEFAULT_TRACE_EXTENSION;
+ }
/**
@@ -942,7 +944,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* tracing.
*/
public static void startMethodTracing() {
- VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0, false, 0);
+ VMDebug.startMethodTracing(fixTraceName(null), 0, 0, false, 0);
}
/**
@@ -1032,9 +1034,9 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
*/
private static String fixTraceName(String traceName) {
if (traceName == null)
- traceName = DEFAULT_TRACE_FILE_PATH;
+ traceName = NoPreloadHolder.DEFAULT_TRACE_FILE_PATH;
if (traceName.charAt(0) != '/')
- traceName = DEFAULT_TRACE_PATH_PREFIX + traceName;
+ traceName = NoPreloadHolder.DEFAULT_TRACE_PATH_PREFIX + traceName;
if (!traceName.endsWith(DEFAULT_TRACE_EXTENSION))
traceName = traceName + DEFAULT_TRACE_EXTENSION;
@@ -2158,6 +2160,14 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
public static native void dumpNativeBacktraceToFile(int pid, String file);
/**
+ * Get description of unreachable native memory.
+ * @param limit the number of leaks to provide info on, 0 to only get a summary.
+ * @param contents true to include a hex dump of the contents of unreachable memory.
+ * @return the String containing a description of unreachable memory.
+ * @hide */
+ public static native String getUnreachableMemory(int limit, boolean contents);
+
+ /**
* Return a String describing the calling method and location at a particular stack depth.
* @param callStack the Thread stack
* @param depth the depth of stack to return information for.
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 2b144683dc70..0d940723b7d2 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -267,7 +267,11 @@ public class DropBoxManager {
* @param data value to store
*/
public void addText(String tag, String data) {
- try { mService.add(new Entry(tag, 0, data)); } catch (RemoteException e) {}
+ try {
+ mService.add(new Entry(tag, 0, data));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -279,7 +283,11 @@ public class DropBoxManager {
*/
public void addData(String tag, byte[] data, int flags) {
if (data == null) throw new NullPointerException("data == null");
- try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {}
+ try {
+ mService.add(new Entry(tag, 0, data, flags));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -297,7 +305,7 @@ public class DropBoxManager {
try {
mService.add(entry);
} catch (RemoteException e) {
- // ignore
+ throw e.rethrowFromSystemServer();
} finally {
entry.close();
}
@@ -312,7 +320,11 @@ public class DropBoxManager {
* @return whether events with that tag would be accepted
*/
public boolean isTagEnabled(String tag) {
- try { return mService.isTagEnabled(tag); } catch (RemoteException e) { return false; }
+ try {
+ return mService.isTagEnabled(tag);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -325,7 +337,11 @@ public class DropBoxManager {
* @return the next entry, or null if there are no more entries
*/
public Entry getNextEntry(String tag, long msec) {
- try { return mService.getNextEntry(tag, msec); } catch (RemoteException e) { return null; }
+ try {
+ return mService.getNextEntry(tag, msec);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
// TODO: It may be useful to have some sort of notification mechanism
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e841dfe2b2a3..1085b1e9dc6b 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -176,35 +176,37 @@ public class Environment {
return DIR_VENDOR_ROOT;
}
- /** {@hide} */
- @Deprecated
- public static File getSystemSecureDirectory() {
- return getDataSystemDirectory();
- }
-
- /** {@hide} */
- @Deprecated
- public static File getSecureDataDirectory() {
- return getDataDirectory();
- }
-
/**
- * Return the system directory for a user. This is for use by system services to store
- * files relating to the user. This directory will be automatically deleted when the user
- * is removed.
+ * Return the system directory for a user. This is for use by system
+ * services to store files relating to the user. This directory will be
+ * automatically deleted when the user is removed.
*
+ * @deprecated This directory is valid and still exists, but callers should
+ * <em>strongly</em> consider switching to
+ * {@link #getDataSystemCeDirectory(int)} which is protected
+ * with user credentials or
+ * {@link #getDataSystemDeDirectory(int)} which supports fast
+ * user wipe.
* @hide
*/
+ @Deprecated
public static File getUserSystemDirectory(int userId) {
return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
}
/**
- * Returns the config directory for a user. This is for use by system services to store files
- * relating to the user which should be readable by any app running as that user.
+ * Returns the config directory for a user. This is for use by system
+ * services to store files relating to the user which should be readable by
+ * any app running as that user.
*
+ * @deprecated This directory is valid and still exists, but callers should
+ * <em>strongly</em> consider switching to
+ * {@link #getDataMiscCeDirectory(int)} which is protected with
+ * user credentials or {@link #getDataMiscDeDirectory(int)}
+ * which supports fast user wipe.
* @hide
*/
+ @Deprecated
public static File getUserConfigDirectory(int userId) {
return new File(new File(new File(
getDataDirectory(), "misc"), "user"), Integer.toString(userId));
@@ -232,77 +234,72 @@ public class Environment {
}
/** {@hide} */
- public static File getDataSystemCredentialEncryptedDirectory() {
- return new File(getDataDirectory(), "system_ce");
+ public static File getDataSystemCeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
}
/** {@hide} */
- public static File getDataSystemCredentialEncryptedDirectory(int userId) {
- return new File(getDataSystemCredentialEncryptedDirectory(), String.valueOf(userId));
+ public static File getDataSystemDeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
}
/** {@hide} */
- public static File getDataAppDirectory(String volumeUuid) {
- return new File(getDataDirectory(volumeUuid), "app");
+ public static File getDataMiscDirectory() {
+ return new File(getDataDirectory(), "misc");
}
/** {@hide} */
- public static File getDataAppEphemeralDirectory(String volumeUuid) {
- return new File(getDataDirectory(volumeUuid), "app-ephemeral");
+ public static File getDataMiscCeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
}
/** {@hide} */
- @Deprecated
- public static File getDataUserDirectory(String volumeUuid) {
- return getDataUserCredentialEncryptedDirectory(volumeUuid);
+ public static File getDataMiscDeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
}
/** {@hide} */
- @Deprecated
- public static File getDataUserDirectory(String volumeUuid, int userId) {
- return getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
+ public static File getDataAppDirectory(String volumeUuid) {
+ return new File(getDataDirectory(volumeUuid), "app");
}
/** {@hide} */
- @Deprecated
- public static File getDataUserPackageDirectory(String volumeUuid, int userId,
- String packageName) {
- return getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName);
+ public static File getDataAppEphemeralDirectory(String volumeUuid) {
+ return new File(getDataDirectory(volumeUuid), "app-ephemeral");
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedDirectory(String volumeUuid) {
+ public static File getDataUserCeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user");
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedDirectory(String volumeUuid, int userId) {
- return new File(getDataUserCredentialEncryptedDirectory(volumeUuid),
- String.valueOf(userId));
+ public static File getDataUserCeDirectory(String volumeUuid, int userId) {
+ return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedPackageDirectory(String volumeUuid, int userId,
+ public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
String packageName) {
// TODO: keep consistent with installd
- return new File(getDataUserCredentialEncryptedDirectory(volumeUuid, userId), packageName);
+ return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedDirectory(String volumeUuid) {
+ public static File getDataUserDeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user_de");
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedDirectory(String volumeUuid, int userId) {
- return new File(getDataUserDeviceEncryptedDirectory(volumeUuid), String.valueOf(userId));
+ public static File getDataUserDeDirectory(String volumeUuid, int userId) {
+ return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedPackageDirectory(String volumeUuid, int userId,
+ public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
String packageName) {
// TODO: keep consistent with installd
- return new File(getDataUserDeviceEncryptedDirectory(volumeUuid, userId), packageName);
+ return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
}
/**
@@ -342,7 +339,7 @@ public class Environment {
* <p>
* Writing to this path requires the
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
- * and starting in read access requires the
+ * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read access requires the
* {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
* which is automatically granted if you hold the write permission.
* <p>
@@ -479,11 +476,6 @@ public class Environment {
public static String DIRECTORY_DOCUMENTS = "Documents";
/**
- * Standard directory in which user managed files are stored.
- */
- public static String DIRECTORY_HOME = "Home";
-
- /**
* List of standard storage directories.
* <p>
* Each of its values have its own constant:
@@ -498,7 +490,6 @@ public class Environment {
* <li>{@link #DIRECTORY_DOWNLOADS}
* <li>{@link #DIRECTORY_DCIM}
* <li>{@link #DIRECTORY_DOCUMENTS}
- * <li>{@link #DIRECTORY_HOME}
* </ul>
* @hide
*/
@@ -512,8 +503,7 @@ public class Environment {
DIRECTORY_MOVIES,
DIRECTORY_DOWNLOADS,
DIRECTORY_DCIM,
- DIRECTORY_DOCUMENTS,
- DIRECTORY_HOME
+ DIRECTORY_DOCUMENTS
};
/**
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index c2aca419836a..1b79497b1870 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -307,7 +307,11 @@ public class FileUtils {
}
}
- /**
+ public static void stringToFile(File file, String string) throws IOException {
+ stringToFile(file.getAbsolutePath(), string);
+ }
+
+ /**
* Writes string to file. Basically same as "echo -n $string > $filename"
*
* @param filename
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index bc317b672d9c..f48306a6737b 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -17,10 +17,12 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.content.Context;
+import android.util.Log;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
/**
* The HardwarePropertiesManager class provides a mechanism of accessing hardware state of a
* device: CPU, GPU and battery temperatures, CPU usage per core, fan speed, etc.
@@ -29,11 +31,7 @@ public class HardwarePropertiesManager {
private static final String TAG = HardwarePropertiesManager.class.getSimpleName();
- private static native void nativeInit();
-
- private static native float[] nativeGetFanSpeeds();
- private static native float[] nativeGetDeviceTemperatures(int type);
- private static native CpuUsageInfo[] nativeGetCpuUsages();
+ private final IHardwarePropertiesManager mService;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -54,9 +52,13 @@ public class HardwarePropertiesManager {
/** Temperature of battery in Celsius. */
public static final int DEVICE_TEMPERATURE_BATTERY = 2;
+ /** Calling app context. */
+ private final Context mContext;
+
/** @hide */
- public HardwarePropertiesManager() {
- nativeInit();
+ public HardwarePropertiesManager(Context context, IHardwarePropertiesManager service) {
+ mContext = context;
+ mService = service;
}
/**
@@ -67,16 +69,22 @@ public class HardwarePropertiesManager {
* @return an array of requested float device temperatures.
* Empty if platform doesn't provide the queried temperature.
*
- * @throws IllegalArgumentException if an incorrect temperature type is queried.
+ * @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type) {
switch (type) {
case DEVICE_TEMPERATURE_CPU:
case DEVICE_TEMPERATURE_GPU:
case DEVICE_TEMPERATURE_BATTERY:
- return nativeGetDeviceTemperatures(type);
+ try {
+ return mService.getDeviceTemperatures(mContext.getOpPackageName(), type);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get device temperatures", e);
+ return new float[0];
+ }
default:
- throw new IllegalArgumentException();
+ Log.w(TAG, "Unknown device temperature type.");
+ return new float[0];
}
}
@@ -85,18 +93,32 @@ public class HardwarePropertiesManager {
*
* @return an array of {@link android.os.CpuUsageInfo} for each core.
* Empty if CPU usage is not supported on this system.
+ *
+ * @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull CpuUsageInfo[] getCpuUsages() {
- return nativeGetCpuUsages();
+ try {
+ return mService.getCpuUsages(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get CPU usages", e);
+ return new CpuUsageInfo[0];
+ }
}
/**
* Return an array of fan speeds in RPM.
*
- * @return an arrat of float fan speeds. Empty if there is no fans or fan speed
- * not supported on this system.
+ * @return an array of float fan speeds in RPM. Empty if there are no fans or fan speed is not
+ * supported on this system.
+ *
+ * @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull float[] getFanSpeeds() {
- return nativeGetFanSpeeds();
+ try {
+ return mService.getFanSpeeds(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get fan speeds", e);
+ return new float[0];
+ }
}
}
diff --git a/core/java/android/os/IHardwarePropertiesManager.aidl b/core/java/android/os/IHardwarePropertiesManager.aidl
new file mode 100644
index 000000000000..bcf0dc85a5e1
--- /dev/null
+++ b/core/java/android/os/IHardwarePropertiesManager.aidl
@@ -0,0 +1,28 @@
+/*
+**
+** 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 may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+import android.os.CpuUsageInfo;
+
+/** @hide */
+
+interface IHardwarePropertiesManager {
+ float[] getDeviceTemperatures(String callingPackage, int type);
+ CpuUsageInfo[] getCpuUsages(String callingPackage);
+ float[] getFanSpeeds(String callingPackage);
+}
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
new file mode 100644
index 000000000000..12830a4996aa
--- /dev/null
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -0,0 +1,28 @@
+/* //device/java/android/android/os/IRecoverySystem.aidl
+**
+** 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 may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+import android.os.IRecoverySystemProgressListener;
+
+/** @hide */
+
+interface IRecoverySystem {
+ boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
+ boolean setupBcb(in String command);
+ boolean clearBcb();
+}
diff --git a/core/java/android/os/IRecoverySystemProgressListener.aidl b/core/java/android/os/IRecoverySystemProgressListener.aidl
new file mode 100644
index 000000000000..d6f712ea3240
--- /dev/null
+++ b/core/java/android/os/IRecoverySystemProgressListener.aidl
@@ -0,0 +1,24 @@
+/* //device/java/android/android/os/IRecoverySystemProgressListener.aidl
+**
+** 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 may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+/** @hide */
+
+oneway interface IRecoverySystemProgressListener {
+ void onProgress(int progress);
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 314b7d5491ff..369ec1572598 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -224,6 +224,8 @@ public final class PowerManager {
* This is used by Gaming and VR applications to ensure the device provides
* will provide consistent performance over a large amount of time.
* </p>
+ *
+ * {@hide}
*/
public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
@@ -385,9 +387,9 @@ public final class PowerManager {
public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
/**
- * The value to pass as the 'reason' argument to reboot() to
- * reboot into recovery mode (for applying system updates, doing
- * factory resets, etc.).
+ * The value to pass as the 'reason' argument to reboot() to reboot into
+ * recovery mode for tasks other than applying system updates, such as
+ * doing factory resets.
* <p>
* Requires the {@link android.Manifest.permission#RECOVERY}
* permission (in addition to
@@ -398,6 +400,18 @@ public final class PowerManager {
public static final String REBOOT_RECOVERY = "recovery";
/**
+ * The value to pass as the 'reason' argument to reboot() to reboot into
+ * recovery mode for applying system updates.
+ * <p>
+ * Requires the {@link android.Manifest.permission#RECOVERY}
+ * permission (in addition to
+ * {@link android.Manifest.permission#REBOOT}).
+ * </p>
+ * @hide
+ */
+ public static final String REBOOT_RECOVERY_UPDATE = "recovery-update";
+
+ /**
* The value to pass as the 'reason' argument to reboot() when device owner requests a reboot on
* the device.
* @hide
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b51d2dfb8694..9984755d316f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -823,6 +823,16 @@ public class Process {
}
/**
+ * Returns whether the given uid belongs to an application.
+ * @param uid A kernel uid.
+ * @return Whether the uid corresponds to an application sandbox running in
+ * a specific user.
+ */
+ public static boolean isApplicationUid(int uid) {
+ return UserHandle.isApp(uid);
+ }
+
+ /**
* Returns whether the current process is in an isolated sandbox.
* @hide
*/
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 154c9bbab312..ddcd63520549 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.SystemApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -66,15 +67,34 @@ public class RecoverySystem {
private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
/** Used to communicate with recovery. See bootable/recovery/recovery.cpp. */
- private static File RECOVERY_DIR = new File("/cache/recovery");
- private static File BLOCK_MAP_FILE = new File(RECOVERY_DIR, "block.map");
- private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
- private static File UNCRYPT_FILE = new File(RECOVERY_DIR, "uncrypt_file");
- private static File LOG_FILE = new File(RECOVERY_DIR, "log");
- private static String LAST_PREFIX = "last_";
+ private static final File RECOVERY_DIR = new File("/cache/recovery");
+ private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
+ private static final String LAST_PREFIX = "last_";
+
+ /**
+ * The recovery image uses this file to identify the location (i.e. blocks)
+ * of an OTA package on the /data partition. The block map file is
+ * generated by uncrypt.
+ *
+ * @hide
+ */
+ public static final File BLOCK_MAP_FILE = new File(RECOVERY_DIR, "block.map");
+
+ /**
+ * UNCRYPT_PACKAGE_FILE stores the filename to be uncrypt'd, which will be
+ * read by uncrypt.
+ *
+ * @hide
+ */
+ public static final File UNCRYPT_PACKAGE_FILE = new File(RECOVERY_DIR, "uncrypt_file");
// Length limits for reading files.
- private static int LOG_FILE_MAX_LENGTH = 64 * 1024;
+ private static final int LOG_FILE_MAX_LENGTH = 64 * 1024;
+
+ // Prevent concurrent execution of requests.
+ private static final Object sRequestLock = new Object();
+
+ private final IRecoverySystem mService;
/**
* Interface definition for a callback to be invoked regularly as
@@ -287,6 +307,89 @@ public class RecoverySystem {
}
/**
+ * Process a given package with uncrypt. No-op if the package is not on the
+ * /data partition.
+ *
+ * @param Context the Context to use
+ * @param packageFile the package to be processed
+ * @param listener an object to receive periodic progress updates as
+ * processing proceeds. May be null.
+ * @param handler the Handler upon which the callbacks will be
+ * executed.
+ *
+ * @throws IOException if there were any errors processing the package file.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void processPackage(Context context,
+ File packageFile,
+ final ProgressListener listener,
+ final Handler handler)
+ throws IOException {
+ String filename = packageFile.getCanonicalPath();
+ if (!filename.startsWith("/data/")) {
+ return;
+ }
+
+ RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+ IRecoverySystemProgressListener progressListener = null;
+ if (listener != null) {
+ final Handler progressHandler;
+ if (handler != null) {
+ progressHandler = handler;
+ } else {
+ progressHandler = new Handler(context.getMainLooper());
+ }
+ progressListener = new IRecoverySystemProgressListener.Stub() {
+ int lastProgress = 0;
+ long lastPublishTime = System.currentTimeMillis();
+
+ @Override
+ public void onProgress(final int progress) {
+ final long now = System.currentTimeMillis();
+ progressHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (progress > lastProgress &&
+ now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) {
+ lastProgress = progress;
+ lastPublishTime = now;
+ listener.onProgress(progress);
+ }
+ }
+ });
+ }
+ };
+ }
+
+ if (!rs.uncrypt(filename, progressListener)) {
+ throw new IOException("process package failed");
+ }
+ }
+
+ /**
+ * Process a given package with uncrypt. No-op if the package is not on the
+ * /data partition.
+ *
+ * @param Context the Context to use
+ * @param packageFile the package to be processed
+ * @param listener an object to receive periodic progress updates as
+ * processing proceeds. May be null.
+ *
+ * @throws IOException if there were any errors processing the package file.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void processPackage(Context context,
+ File packageFile,
+ final ProgressListener listener)
+ throws IOException {
+ processPackage(context, packageFile, listener, null);
+ }
+
+ /**
* Reboots the device in order to install the given update
* package.
* Requires the {@link android.Manifest.permission#REBOOT} permission.
@@ -301,30 +404,127 @@ public class RecoverySystem {
* fails, or if the reboot itself fails.
*/
public static void installPackage(Context context, File packageFile)
- throws IOException {
- String filename = packageFile.getCanonicalPath();
+ throws IOException {
+ installPackage(context, packageFile, false);
+ }
- FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE);
- try {
- uncryptFile.write(filename + "\n");
- } finally {
- uncryptFile.close();
- }
- // UNCRYPT_FILE needs to be readable by system server on bootup.
- if (!UNCRYPT_FILE.setReadable(true, false)) {
- Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath());
+ /**
+ * If the package hasn't been processed (i.e. uncrypt'd), set up
+ * UNCRYPT_PACKAGE_FILE and delete BLOCK_MAP_FILE to trigger uncrypt during the
+ * reboot.
+ *
+ * @param context the Context to use
+ * @param packageFile the update package to install. Must be on a
+ * partition mountable by recovery.
+ * @param processed if the package has been processed (uncrypt'd).
+ *
+ * @throws IOException if writing the recovery command file fails, or if
+ * the reboot itself fails.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void installPackage(Context context, File packageFile, boolean processed)
+ throws IOException {
+ synchronized (sRequestLock) {
+ LOG_FILE.delete();
+ // Must delete the file in case it was created by system server.
+ UNCRYPT_PACKAGE_FILE.delete();
+
+ String filename = packageFile.getCanonicalPath();
+ Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+
+ if (!processed && filename.startsWith("/data/")) {
+ FileWriter uncryptFile = new FileWriter(UNCRYPT_PACKAGE_FILE);
+ try {
+ uncryptFile.write(filename + "\n");
+ } finally {
+ uncryptFile.close();
+ }
+ // UNCRYPT_PACKAGE_FILE needs to be readable and writable by system server.
+ if (!UNCRYPT_PACKAGE_FILE.setReadable(true, false)
+ || !UNCRYPT_PACKAGE_FILE.setWritable(true, false)) {
+ Log.e(TAG, "Error setting permission for " + UNCRYPT_PACKAGE_FILE);
+ }
+
+ BLOCK_MAP_FILE.delete();
+ }
+
+ // If the package is on the /data partition, use the block map file as
+ // the package name instead.
+ if (filename.startsWith("/data/")) {
+ filename = "@/cache/recovery/block.map";
+ }
+
+ final String filenameArg = "--update_package=" + filename + "\n";
+ final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+ final String command = filenameArg + localeArg;
+
+ RecoverySystem rs = (RecoverySystem) context.getSystemService(
+ Context.RECOVERY_SERVICE);
+ if (!rs.setupBcb(command)) {
+ throw new IOException("Setup BCB failed");
+ }
+
+ // Having set up the BCB (bootloader control block), go ahead and reboot
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE);
+
+ throw new IOException("Reboot failed (no permissions?)");
}
- Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+ }
- // If the package is on the /data partition, write the block map file
- // into COMMAND_FILE instead.
+ /**
+ * Schedule to install the given package on next boot. The caller needs to
+ * ensure that the package must have been processed (uncrypt'd) if needed.
+ * It sets up the command in BCB (bootloader control block), which will
+ * be read by the bootloader and the recovery image.
+ *
+ * @param Context the Context to use.
+ * @param packageFile the package to be installed.
+ *
+ * @throws IOException if there were any errors setting up the BCB.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void scheduleUpdateOnBoot(Context context, File packageFile)
+ throws IOException {
+ String filename = packageFile.getCanonicalPath();
+
+ // If the package is on the /data partition, use the block map file as
+ // the package name instead.
if (filename.startsWith("/data/")) {
filename = "@/cache/recovery/block.map";
}
- final String filenameArg = "--update_package=" + filename;
- final String localeArg = "--locale=" + Locale.getDefault().toString();
- bootCommand(context, filenameArg, localeArg);
+ final String filenameArg = "--update_package=" + filename + "\n";
+ final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+ final String command = filenameArg + localeArg;
+
+ RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+ if (!rs.setupBcb(command)) {
+ throw new IOException("schedule update on boot failed");
+ }
+ }
+
+ /**
+ * Cancel any scheduled update by clearing up the BCB (bootloader control
+ * block).
+ *
+ * @param Context the Context to use.
+ *
+ * @throws IOException if there were any errors clearing up the BCB.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void cancelScheduledUpdate(Context context)
+ throws IOException {
+ RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+ if (!rs.clearBcb()) {
+ throw new IOException("cancel scheduled update failed");
+ }
}
/**
@@ -434,27 +634,28 @@ public class RecoverySystem {
* @throws IOException if something goes wrong.
*/
private static void bootCommand(Context context, String... args) throws IOException {
- RECOVERY_DIR.mkdirs(); // In case we need it
- COMMAND_FILE.delete(); // In case it's not writable
- LOG_FILE.delete();
+ synchronized (sRequestLock) {
+ LOG_FILE.delete();
- FileWriter command = new FileWriter(COMMAND_FILE);
- try {
+ StringBuilder command = new StringBuilder();
for (String arg : args) {
if (!TextUtils.isEmpty(arg)) {
- command.write(arg);
- command.write("\n");
+ command.append(arg);
+ command.append("\n");
}
}
- } finally {
- command.close();
- }
- // Having written the command file, go ahead and reboot
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- pm.reboot(PowerManager.REBOOT_RECOVERY);
+ // Write the command into BCB (bootloader control block).
+ RecoverySystem rs = (RecoverySystem) context.getSystemService(
+ Context.RECOVERY_SERVICE);
+ rs.setupBcb(command.toString());
- throw new IOException("Reboot failed (no permissions?)");
+ // Having set up the BCB, go ahead and reboot.
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ pm.reboot(PowerManager.REBOOT_RECOVERY);
+
+ throw new IOException("Reboot failed (no permissions?)");
+ }
}
/**
@@ -476,10 +677,10 @@ public class RecoverySystem {
// Only remove the OTA package if it's partially processed (uncrypt'd).
boolean reservePackage = BLOCK_MAP_FILE.exists();
- if (!reservePackage && UNCRYPT_FILE.exists()) {
+ if (!reservePackage && UNCRYPT_PACKAGE_FILE.exists()) {
String filename = null;
try {
- filename = FileUtils.readTextFile(UNCRYPT_FILE, 0, null);
+ filename = FileUtils.readTextFile(UNCRYPT_PACKAGE_FILE, 0, null);
} catch (IOException e) {
Log.e(TAG, "Error reading uncrypt file", e);
}
@@ -487,7 +688,7 @@ public class RecoverySystem {
// Remove the OTA package on /data that has been (possibly
// partially) processed. (Bug: 24973532)
if (filename != null && filename.startsWith("/data")) {
- if (UNCRYPT_FILE.delete()) {
+ if (UNCRYPT_PACKAGE_FILE.delete()) {
Log.i(TAG, "Deleted: " + filename);
} else {
Log.e(TAG, "Can't delete: " + filename);
@@ -499,13 +700,13 @@ public class RecoverySystem {
// the block map file (BLOCK_MAP_FILE) for a package. BLOCK_MAP_FILE
// will be created at the end of a successful uncrypt. If seeing this
// file, we keep the block map file and the file that contains the
- // package name (UNCRYPT_FILE). This is to reduce the work for GmsCore
- // to avoid re-downloading everything again.
+ // package name (UNCRYPT_PACKAGE_FILE). This is to reduce the work for
+ // GmsCore to avoid re-downloading everything again.
String[] names = RECOVERY_DIR.list();
for (int i = 0; names != null && i < names.length; i++) {
if (names[i].startsWith(LAST_PREFIX)) continue;
if (reservePackage && names[i].equals(BLOCK_MAP_FILE.getName())) continue;
- if (reservePackage && names[i].equals(UNCRYPT_FILE.getName())) continue;
+ if (reservePackage && names[i].equals(UNCRYPT_PACKAGE_FILE.getName())) continue;
recursiveDelete(new File(RECOVERY_DIR, names[i]));
}
@@ -533,6 +734,39 @@ public class RecoverySystem {
}
/**
+ * Talks to RecoverySystemService via Binder to trigger uncrypt.
+ */
+ private boolean uncrypt(String packageFile, IRecoverySystemProgressListener listener) {
+ try {
+ return mService.uncrypt(packageFile, listener);
+ } catch (RemoteException unused) {
+ }
+ return false;
+ }
+
+ /**
+ * Talks to RecoverySystemService via Binder to set up the BCB.
+ */
+ private boolean setupBcb(String command) {
+ try {
+ return mService.setupBcb(command);
+ } catch (RemoteException unused) {
+ }
+ return false;
+ }
+
+ /**
+ * Talks to RecoverySystemService via Binder to clear up the BCB.
+ */
+ private boolean clearBcb() {
+ try {
+ return mService.clearBcb();
+ } catch (RemoteException unused) {
+ }
+ return false;
+ }
+
+ /**
* Internally, recovery treats each line of the command file as a separate
* argv, so we only need to protect against newlines and nulls.
*/
@@ -546,5 +780,14 @@ public class RecoverySystem {
/**
* @removed Was previously made visible by accident.
*/
- public RecoverySystem() { }
+ public RecoverySystem() {
+ mService = null;
+ }
+
+ /**
+ * @hide
+ */
+ public RecoverySystem(IRecoverySystem service) {
+ mService = service;
+ }
}
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index 98d75233e8df..6d25fc17bd6a 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -15,6 +15,7 @@
*/
package android.os;
+
import android.util.AndroidException;
/**
@@ -33,4 +34,25 @@ public class RemoteException extends AndroidException {
public RuntimeException rethrowAsRuntimeException() {
throw new RuntimeException(this);
}
+
+ /**
+ * Rethrow this exception when we know it came from the system server. This
+ * gives us an opportunity to throw a nice clean
+ * {@link DeadSystemException} signal to avoid spamming logs with
+ * misleading stack traces.
+ * <p>
+ * Apps making calls into the system server may end up persisting internal
+ * state or making security decisions based on the perceived success or
+ * failure of a call, or any default values returned. For this reason, we
+ * want to strongly throw when there was trouble with the transaction.
+ *
+ * @hide
+ */
+ public RuntimeException rethrowFromSystemServer() {
+ if (this instanceof DeadObjectException) {
+ throw new RuntimeException(new DeadSystemException());
+ } else {
+ throw new RuntimeException(this);
+ }
+ }
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 91d88da8b733..e4a76db7a86c 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1517,7 +1517,11 @@ public final class StrictMode {
violationMaskSubset,
info);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+ if (e instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+ }
} finally {
// Restore the policy.
setThreadPolicyMask(savedPolicyMask);
@@ -1569,7 +1573,11 @@ public final class StrictMode {
info);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException handling StrictMode violation", e);
+ if (e instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ Log.e(TAG, "RemoteException handling StrictMode violation", e);
+ }
}
int outstanding = sDropboxCallsInFlight.decrementAndGet();
if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding);
@@ -1897,7 +1905,11 @@ public final class StrictMode {
violationMaskSubset,
info);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+ if (e instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+ }
} finally {
// Restore the policy.
setThreadPolicyMask(savedPolicyMask);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 24666fe71724..b3f44536214b 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -130,6 +130,15 @@ public final class UserHandle implements Parcelable {
}
/**
+ * Returns the user for a given uid.
+ * @param uid A uid for an application running in a particular user.
+ * @return A {@link UserHandle} for that user.
+ */
+ public static UserHandle getUserHandleForUid(int uid) {
+ return of(getUserId(uid));
+ }
+
+ /**
* Returns the user id for a given uid.
* @hide
*/
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index dc0e249d72ec..20b3798b56b8 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -36,7 +36,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.storage.StorageManager;
import android.provider.Settings;
-import android.util.Log;
import android.view.WindowManager.LayoutParams;
import com.android.internal.R;
@@ -379,8 +378,7 @@ public class UserManager {
* Specifies that the user is not allowed to make outgoing
* phone calls. Emergency calls are still permitted.
* The default value is <code>false</code>.
- * <p>This restriction has no effect on managed profiles since call intents are normally
- * forwarded to the primary user.
+ * <p>This restriction has no effect on managed profiles.
*
* <p>Key for user restrictions.
* <p>Type: Boolean
@@ -701,8 +699,7 @@ public class UserManager {
try {
return mService.getUserInfo(getUserHandle()).name;
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user name", re);
- return "";
+ throw re.rethrowFromSystemServer();
}
}
@@ -772,8 +769,7 @@ public class UserManager {
try {
return mService.isRestricted();
} catch (RemoteException re) {
- Log.w(TAG, "Could not check if user is limited ", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -785,8 +781,7 @@ public class UserManager {
try {
return mService.canHaveRestrictedProfile(userId);
} catch (RemoteException re) {
- Log.w(TAG, "Could not check if user can have restricted profile", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -848,8 +843,8 @@ public class UserManager {
public boolean isUserRunning(int userId) {
try {
return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
- } catch (RemoteException e) {
- return false;
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -865,8 +860,8 @@ public class UserManager {
// TODO: reconcile stopped vs stopping?
return ActivityManagerNative.getDefault().isUserRunning(
user.getIdentifier(), ActivityManager.FLAG_OR_STOPPED);
- } catch (RemoteException e) {
- return false;
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -894,8 +889,8 @@ public class UserManager {
try {
return ActivityManagerNative.getDefault().isUserRunning(
user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED);
- } catch (RemoteException e) {
- return false;
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -923,8 +918,8 @@ public class UserManager {
try {
return ActivityManagerNative.getDefault().isUserRunning(
user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
- } catch (RemoteException e) {
- return false;
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -969,8 +964,7 @@ public class UserManager {
try {
return mService.getUserInfo(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user info", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -991,8 +985,7 @@ public class UserManager {
try {
return mService.getUserRestrictions(userHandle.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user restrictions", re);
- return Bundle.EMPTY;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1008,9 +1001,7 @@ public class UserManager {
try {
return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not get base user restrictions for user " +
- userHandle.getIdentifier(), re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1066,7 +1057,7 @@ public class UserManager {
try {
mService.setUserRestriction(key, value, userHandle.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not set user restriction", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1093,8 +1084,7 @@ public class UserManager {
return mService.hasUserRestriction(restrictionKey,
userHandle.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not check user restrictions", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1141,12 +1131,14 @@ public class UserManager {
UserInfo user = null;
try {
user = mService.createUser(name, flags);
+ // TODO: Keep this in sync with
+ // UserManagerService.LocalService.createUserEvenWhenDisallowed
if (user != null && !user.isAdmin()) {
mService.setUserRestriction(DISALLOW_SMS, true, user.id);
mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
}
} catch (RemoteException re) {
- Log.w(TAG, "Could not create a user", re);
+ throw re.rethrowFromSystemServer();
}
return user;
}
@@ -1166,7 +1158,7 @@ public class UserManager {
Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
}
} catch (RemoteException re) {
- Log.w(TAG, "Could not create a user", re);
+ throw re.rethrowFromSystemServer();
}
return guest;
}
@@ -1187,8 +1179,7 @@ public class UserManager {
try {
return mService.createProfileForUser(name, flags, userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not create a user", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1210,10 +1201,9 @@ public class UserManager {
UserHandle.of(user.id));
}
return user;
- } catch (RemoteException e) {
- Log.w(TAG, "Could not create a restricted profile", e);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -1281,8 +1271,7 @@ public class UserManager {
try {
return mService.getSeedAccountName();
} catch (RemoteException re) {
- Log.w(TAG, "Could not get the seed account name", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1296,8 +1285,7 @@ public class UserManager {
try {
return mService.getSeedAccountType();
} catch (RemoteException re) {
- Log.w(TAG, "Could not get the seed account type", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1313,8 +1301,7 @@ public class UserManager {
try {
return mService.getSeedAccountOptions();
} catch (RemoteException re) {
- Log.w(TAG, "Could not get the seed account options", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1335,7 +1322,7 @@ public class UserManager {
mService.setSeedAccountData(userId, accountName, accountType, accountOptions,
/* persist= */ true);
} catch (RemoteException re) {
- Log.w(TAG, "Could not set the seed account data", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1348,7 +1335,7 @@ public class UserManager {
try {
mService.clearSeedAccountData();
} catch (RemoteException re) {
- Log.w(TAG, "Could not clear the seed account data", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1363,15 +1350,18 @@ public class UserManager {
try {
return mService.markGuestForDeletion(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not mark guest for deletion", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
/**
* Sets the user as enabled, if such an user exists.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * Note that the default is true, it's only that managed profiles might not be enabled.
+ *
+ * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * <p>Note that the default is true, it's only that managed profiles might not be enabled.
+ * Also ephemeral users can be disabled to indicate that their removal is in progress and they
+ * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled.
*
* @param userHandle the id of the profile to enable
* @hide
@@ -1379,8 +1369,8 @@ public class UserManager {
public void setUserEnabled(@UserIdInt int userHandle) {
try {
mService.setUserEnabled(userHandle);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not enable the profile", e);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -1402,8 +1392,7 @@ public class UserManager {
try {
return mService.getUsers(false);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user list", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1425,8 +1414,7 @@ public class UserManager {
}
return result;
} catch (RemoteException re) {
- Log.w(TAG, "Could not get users list", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1442,8 +1430,7 @@ public class UserManager {
try {
return mService.getUserAccount(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user account", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1459,7 +1446,7 @@ public class UserManager {
try {
mService.setUserAccount(userHandle, accountName);
} catch (RemoteException re) {
- Log.w(TAG, "Could not set user account", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1474,8 +1461,7 @@ public class UserManager {
try {
return mService.getPrimaryUser();
} catch (RemoteException re) {
- Log.w(TAG, "Could not get Primary user", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1512,8 +1498,7 @@ public class UserManager {
try {
return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne);
} catch (RemoteException re) {
- Log.w(TAG, "Could not check if we can add more managed profiles", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1532,8 +1517,7 @@ public class UserManager {
try {
return mService.getProfiles(userHandle, false /* enabledOnly */);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user list", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1548,8 +1532,7 @@ public class UserManager {
try {
return mService.isSameProfileGroup(userId, otherUserId);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user list", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1567,8 +1550,7 @@ public class UserManager {
try {
return mService.getProfiles(userHandle, true /* enabledOnly */);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user list", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1584,8 +1566,7 @@ public class UserManager {
try {
users = mService.getProfiles(UserHandle.myUserId(), true /* enabledOnly */);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user list", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
for (UserInfo info : users) {
UserHandle userHandle = new UserHandle(info.id);
@@ -1605,8 +1586,7 @@ public class UserManager {
try {
return mService.getCredentialOwnerProfile(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get credential owner", re);
- return -1;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1620,8 +1600,7 @@ public class UserManager {
try {
return mService.getProfileParent(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get profile parent", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1635,8 +1614,8 @@ public class UserManager {
public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) {
try {
mService.setQuietModeEnabled(userHandle, enableQuietMode);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not change the profile's quiet mode", e);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -1649,10 +1628,9 @@ public class UserManager {
public boolean isQuietModeEnabled(UserHandle userHandle) {
try {
return mService.isQuietModeEnabled(userHandle.getIdentifier());
- } catch (RemoteException e) {
- Log.w(TAG, "Could not query the profile's quiet mode", e);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -1737,8 +1715,7 @@ public class UserManager {
try {
return mService.getUsers(excludeDying);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user list", re);
- return null;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1752,8 +1729,7 @@ public class UserManager {
try {
return mService.removeUser(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not remove user ", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
@@ -1769,7 +1745,7 @@ public class UserManager {
try {
mService.setUserName(userHandle, name);
} catch (RemoteException re) {
- Log.w(TAG, "Could not set the user name ", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1783,7 +1759,7 @@ public class UserManager {
try {
mService.setUserIcon(userHandle, icon);
} catch (RemoteException re) {
- Log.w(TAG, "Could not set the user icon ", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -1808,7 +1784,7 @@ public class UserManager {
}
}
} catch (RemoteException re) {
- Log.w(TAG, "Could not get the user icon ", re);
+ throw re.rethrowFromSystemServer();
}
return null;
}
@@ -1864,9 +1840,8 @@ public class UserManager {
try {
return mService.getUserSerialNumber(userHandle);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get serial number for user " + userHandle);
+ throw re.rethrowFromSystemServer();
}
- return -1;
}
/**
@@ -1882,9 +1857,8 @@ public class UserManager {
try {
return mService.getUserHandle(userSerialNumber);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get userHandle for user " + userSerialNumber);
+ throw re.rethrowFromSystemServer();
}
- return -1;
}
/**
@@ -1910,9 +1884,8 @@ public class UserManager {
try {
return mService.getApplicationRestrictions(packageName);
} catch (RemoteException re) {
- Log.w(TAG, "Could not get application restrictions for package " + packageName);
+ throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -1922,9 +1895,8 @@ public class UserManager {
try {
return mService.getApplicationRestrictionsForUser(packageName, user.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier());
+ throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -1935,7 +1907,7 @@ public class UserManager {
try {
mService.setApplicationRestrictions(packageName, restrictions, user.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
+ throw re.rethrowFromSystemServer();
}
}
@@ -1959,7 +1931,7 @@ public class UserManager {
try {
mService.setDefaultGuestRestrictions(restrictions);
} catch (RemoteException re) {
- Log.w(TAG, "Could not set guest restrictions");
+ throw re.rethrowFromSystemServer();
}
}
@@ -1971,9 +1943,8 @@ public class UserManager {
try {
return mService.getDefaultGuestRestrictions();
} catch (RemoteException re) {
- Log.w(TAG, "Could not set guest restrictions");
+ throw re.rethrowFromSystemServer();
}
- return new Bundle();
}
/**
@@ -1986,8 +1957,7 @@ public class UserManager {
try {
return mService.getUserCreationTime(userHandle.getIdentifier());
} catch (RemoteException re) {
- Log.w(TAG, "Could not get user creation time", re);
- return 0;
+ throw re.rethrowFromSystemServer();
}
}
@@ -2003,8 +1973,7 @@ public class UserManager {
try {
return mService.someUserHasSeedAccount(accountName, accountType);
} catch (RemoteException re) {
- Log.w(TAG, "Could not check seed accounts", re);
- return false;
+ throw re.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 58a026904373..f399719fa1fc 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -17,6 +17,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.UserInfo;
import android.graphics.Bitmap;
/**
@@ -106,4 +107,23 @@ public abstract class UserManagerInternal {
* non-ephemeral users left.
*/
public abstract void removeAllUsers();
+
+ /**
+ * Called by the activity manager when the ephemeral user goes to background and its removal
+ * starts as a result.
+ *
+ * <p>It marks the ephemeral user as disabled in order to prevent it from being re-entered
+ * before its removal finishes.
+ *
+ * @param userId the ID of the ephemeral user.
+ */
+ public abstract void onEphemeralUserStop(int userId);
+
+ /**
+ * Same as UserManager.createUser(), but bypasses the check for DISALLOW_ADD_USER.
+ *
+ * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
+ * createAndManageUser is called by the device owner.
+ */
+ public abstract UserInfo createUserEvenWhenDisallowed(String name, int flags);
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index e7dfbd72292a..17df7080acf1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -332,7 +332,7 @@ public class StorageManager {
try {
mMountService.registerListener(delegate);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
mDelegates.add(delegate);
}
@@ -353,7 +353,7 @@ public class StorageManager {
try {
mMountService.unregisterListener(delegate);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
i.remove();
}
@@ -434,10 +434,8 @@ public class StorageManager {
} catch (IOException e) {
throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to mount OBB", e);
+ throw e.rethrowFromSystemServer();
}
-
- return false;
}
/**
@@ -469,10 +467,8 @@ public class StorageManager {
mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
return true;
} catch (RemoteException e) {
- Log.e(TAG, "Failed to mount OBB", e);
+ throw e.rethrowFromSystemServer();
}
-
- return false;
}
/**
@@ -487,10 +483,8 @@ public class StorageManager {
try {
return mMountService.isObbMounted(rawPath);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to check if OBB is mounted", e);
+ throw e.rethrowFromSystemServer();
}
-
- return false;
}
/**
@@ -508,10 +502,8 @@ public class StorageManager {
try {
return mMountService.getMountedObbPath(rawPath);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to find mounted path for OBB", e);
+ throw e.rethrowFromSystemServer();
}
-
- return null;
}
/** {@hide} */
@@ -519,7 +511,7 @@ public class StorageManager {
try {
return Arrays.asList(mMountService.getDisks());
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -605,7 +597,7 @@ public class StorageManager {
try {
return Arrays.asList(mMountService.getVolumes(0));
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -620,7 +612,7 @@ public class StorageManager {
}
return res;
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -629,7 +621,7 @@ public class StorageManager {
try {
return Arrays.asList(mMountService.getVolumeRecords(0));
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -672,7 +664,7 @@ public class StorageManager {
try {
mMountService.mount(volId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -681,7 +673,7 @@ public class StorageManager {
try {
mMountService.unmount(volId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -690,7 +682,7 @@ public class StorageManager {
try {
mMountService.format(volId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -699,7 +691,7 @@ public class StorageManager {
try {
return mMountService.benchmark(volId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -708,7 +700,7 @@ public class StorageManager {
try {
mMountService.partitionPublic(diskId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -717,7 +709,7 @@ public class StorageManager {
try {
mMountService.partitionPrivate(diskId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -726,7 +718,7 @@ public class StorageManager {
try {
mMountService.partitionMixed(diskId, ratio);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -759,7 +751,7 @@ public class StorageManager {
try {
mMountService.setVolumeNickname(fsUuid, nickname);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -769,7 +761,7 @@ public class StorageManager {
mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
VolumeRecord.USER_FLAG_INITED);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -779,7 +771,7 @@ public class StorageManager {
mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
VolumeRecord.USER_FLAG_SNOOZED);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -788,7 +780,7 @@ public class StorageManager {
try {
mMountService.forgetVolume(fsUuid);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -802,7 +794,7 @@ public class StorageManager {
try {
return mMountService.getPrimaryStorageUuid();
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -816,7 +808,7 @@ public class StorageManager {
try {
mMountService.setPrimaryStorageUuid(volumeUuid, callback);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -865,7 +857,12 @@ public class StorageManager {
}
}
- /** {@hide} */
+ /**
+ * Gets the list of shared/external storage volumes available to the current user.
+ *
+ * <p>It always contains the primary storage volume, plus any additional external volume(s)
+ * available in the device, such as SD cards or attached USB drives.
+ */
public @NonNull StorageVolume[] getVolumeList() {
return getVolumeList(mContext.getUserId(), 0);
}
@@ -895,7 +892,7 @@ public class StorageManager {
}
return mountService.getVolumeList(uid, packageName, flags);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -914,7 +911,9 @@ public class StorageManager {
return paths;
}
- /** {@hide} */
+ /**
+ * Gets the primary shared/external storage volume available to the current user.
+ */
public @NonNull StorageVolume getPrimaryVolume() {
return getPrimaryVolume(getVolumeList());
}
@@ -977,7 +976,7 @@ public class StorageManager {
try {
mMountService.createUserKey(userId, serialNumber, ephemeral);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -986,7 +985,7 @@ public class StorageManager {
try {
mMountService.destroyUserKey(userId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -995,7 +994,7 @@ public class StorageManager {
try {
mMountService.unlockUserKey(userId, serialNumber, token, secret);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1004,7 +1003,7 @@ public class StorageManager {
try {
mMountService.lockUserKey(userId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1013,7 +1012,7 @@ public class StorageManager {
try {
mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1022,7 +1021,7 @@ public class StorageManager {
try {
return mMountService.isUserKeyUnlocked(userId);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1057,7 +1056,8 @@ public class StorageManager {
}
}
}
- } catch (RemoteException ignored) {
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
return path;
}
@@ -1067,7 +1067,7 @@ public class StorageManager {
try {
return mMountService.mountAppFuse(name);
} catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 1408202a35ea..d860c7d8ad2e 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -16,11 +16,17 @@
package android.os.storage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.Intent;
import android.net.TrafficStats;
+import android.net.Uri;
+import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.provider.DocumentsContract;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -29,14 +35,47 @@ import java.io.CharArrayWriter;
import java.io.File;
/**
- * Information about a storage volume that may be mounted. This is a legacy
- * specialization of {@link VolumeInfo} which describes the volume for a
- * specific user.
+ * Information about a shared/external storage volume for a specific user.
+ *
+ * <p>
+ * A device always has one (and one only) primary storage volume, but it could have extra volumes,
+ * like SD cards and USB drives. This object represents the logical view of a storage
+ * volume for a specific user: different users might have different views for the same physical
+ * volume (for example, if the volume is a built-in emulated storage).
+ *
+ * <p>
+ * The storage volume is not necessarily mounted, applications should use {@link #getState()} to
+ * verify its state.
+ *
* <p>
- * This class may be deprecated in the future.
+ * Applications willing to read or write to this storage volume needs to get a permission from the
+ * user first, which can be achieved in the following ways:
*
- * @hide
+ * <ul>
+ * <li>To get access to standard directories (like the {@link Environment#DIRECTORY_PICTURES}), they
+ * can use the {@link #createAccessIntent(String)}. This is the recommend way, since it provides a
+ * simpler API and narrows the access to the given directory (and its descendants).
+ * <li>To get access to any directory (and its descendants), they can use the Storage Acess
+ * Framework APIs (such as {@link Intent#ACTION_OPEN_DOCUMENT} and
+ * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, although these APIs do not guarantee the user will
+ * select this specific volume.
+ * <li>To get read and write access to the primary storage volume, applications can declare the
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and
+ * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions respectively, with the
+ * latter including the former. This approach is discouraged, since users may be hesitant to grant
+ * broad access to all files contained on a storage device.
+ * </ul>
+ *
+ * <p>It can be obtained through {@link StorageManager#getVolumeList()} and
+ * {@link StorageManager#getPrimaryVolume()} and also as an extra in some broadcasts
+ * (see {@link #EXTRA_STORAGE_VOLUME}).
+ *
+ * <p>
+ * See {@link Environment#getExternalStorageDirectory()} for more info about shared/external
+ * storage semantics.
*/
+// NOTE: This is a legacy specialization of VolumeInfo which describes the volume for a specific
+// user, but is now part of the public API.
public class StorageVolume implements Parcelable {
private final String mId;
@@ -53,14 +92,36 @@ public class StorageVolume implements Parcelable {
private final String mFsUuid;
private final String mState;
- // StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
- // ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED,
- // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
- public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
+ /**
+ * Name of the {@link Parcelable} extra in the {@link Intent#ACTION_MEDIA_REMOVED},
+ * {@link Intent#ACTION_MEDIA_UNMOUNTED}, {@link Intent#ACTION_MEDIA_CHECKING},
+ * {@link Intent#ACTION_MEDIA_NOFS}, {@link Intent#ACTION_MEDIA_MOUNTED},
+ * {@link Intent#ACTION_MEDIA_SHARED}, {@link Intent#ACTION_MEDIA_BAD_REMOVAL},
+ * {@link Intent#ACTION_MEDIA_UNMOUNTABLE}, and {@link Intent#ACTION_MEDIA_EJECT} broadcast that
+ * contains a {@link StorageVolume}.
+ */
+ // Also sent on ACTION_MEDIA_UNSHARED, which is @hide
+ public static final String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
+
+ /**
+ * Name of the String extra used by {@link #createAccessIntent(String) createAccessIntent}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DIRECTORY_NAME = "android.os.storage.extra.DIRECTORY_NAME";
+
+ /**
+ * Name of the intent used by {@link #createAccessIntent(String) createAccessIntent}.
+ */
+ private static final String ACTION_OPEN_EXTERNAL_DIRECTORY =
+ "android.os.storage.action.OPEN_EXTERNAL_DIRECTORY";
+ /** {@hide} */
public static final int STORAGE_ID_INVALID = 0x00000000;
+ /** {@hide} */
public static final int STORAGE_ID_PRIMARY = 0x00010001;
+ /** {@hide} */
public StorageVolume(String id, int storageId, File path, String description, boolean primary,
boolean removable, boolean emulated, long mtpReserveSize, boolean allowMassStorage,
long maxFileSize, UserHandle owner, String fsUuid, String state) {
@@ -95,6 +156,7 @@ public class StorageVolume implements Parcelable {
mState = in.readString();
}
+ /** {@hide} */
public String getId() {
return mId;
}
@@ -103,17 +165,19 @@ public class StorageVolume implements Parcelable {
* Returns the mount path for the volume.
*
* @return the mount path
+ * @hide
*/
public String getPath() {
return mPath.toString();
}
+ /** {@hide} */
public File getPathFile() {
return mPath;
}
/**
- * Returns a user visible description of the volume.
+ * Returns a user-visible description of the volume.
*
* @return the volume description
*/
@@ -121,6 +185,10 @@ public class StorageVolume implements Parcelable {
return mDescription;
}
+ /**
+ * Returns true if the volume is the primary shared/external storage, which is the volume
+ * backed by {@link Environment#getExternalStorageDirectory()}.
+ */
public boolean isPrimary() {
return mPrimary;
}
@@ -148,6 +216,7 @@ public class StorageVolume implements Parcelable {
* this is also used for the storage_id column in the media provider.
*
* @return MTP storage ID
+ * @hide
*/
public int getStorageId() {
return mStorageId;
@@ -164,6 +233,7 @@ public class StorageVolume implements Parcelable {
* too close to full.
*
* @return MTP reserve space
+ * @hide
*/
public int getMtpReserveSpace() {
return (int) (mMtpReserveSize / TrafficStats.MB_IN_BYTES);
@@ -173,6 +243,7 @@ public class StorageVolume implements Parcelable {
* Returns true if this volume can be shared via USB mass storage.
*
* @return whether mass storage is allowed
+ * @hide
*/
public boolean allowMassStorage() {
return mAllowMassStorage;
@@ -182,22 +253,28 @@ public class StorageVolume implements Parcelable {
* Returns maximum file size for the volume, or zero if it is unbounded.
*
* @return maximum file size
+ * @hide
*/
public long getMaxFileSize() {
return mMaxFileSize;
}
+ /** {@hide} */
public UserHandle getOwner() {
return mOwner;
}
- public String getUuid() {
+ /**
+ * Gets the volume UUID, if any.
+ */
+ public @Nullable String getUuid() {
return mFsUuid;
}
/**
* Parse and return volume UUID as FAT volume ID, or return -1 if unable to
* parse or UUID is unknown.
+ * @hide
*/
public int getFatVolumeId() {
if (mFsUuid == null || mFsUuid.length() != 9) {
@@ -210,14 +287,57 @@ public class StorageVolume implements Parcelable {
}
}
+ /** {@hide} */
public String getUserLabel() {
return mDescription;
}
+ /**
+ * Returns the current state of the volume.
+ *
+ * @return one of {@link Environment#MEDIA_UNKNOWN}, {@link Environment#MEDIA_REMOVED},
+ * {@link Environment#MEDIA_UNMOUNTED}, {@link Environment#MEDIA_CHECKING},
+ * {@link Environment#MEDIA_NOFS}, {@link Environment#MEDIA_MOUNTED},
+ * {@link Environment#MEDIA_MOUNTED_READ_ONLY}, {@link Environment#MEDIA_SHARED},
+ * {@link Environment#MEDIA_BAD_REMOVAL}, or {@link Environment#MEDIA_UNMOUNTABLE}.
+ */
public String getState() {
return mState;
}
+ /**
+ * Builds an intent to give access to a standard storage directory after obtaining the user's
+ * approval.
+ * <p>
+ * When invoked, the system will ask the user to grant access to the requested directory (and
+ * its descendants). The result of the request will be returned to the activity through the
+ * {@code onActivityResult} method.
+ * <p>
+ * To gain access to descendants (child, grandchild, etc) documents, use
+ * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)}, or
+ * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
+ *
+ * <b>If your application only needs to store internal data, consider using
+ * {@link Context#getExternalFilesDirs(String) Context.getExternalFilesDirs},
+ * {@link Context#getExternalCacheDirs()}, or
+ * {@link Context#getExternalMediaDirs()}, which require no permissions to read or write.
+ *
+ * @param directoryName must be one of
+ * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS},
+ * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS},
+ * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES},
+ * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS},
+ * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}
+ *
+ * @see DocumentsContract
+ */
+ public Intent createAccessIntent(@NonNull String directoryName) {
+ final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
+ intent.putExtra(EXTRA_STORAGE_VOLUME, this);
+ intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
+ return intent;
+ }
+
@Override
public boolean equals(Object obj) {
if (obj instanceof StorageVolume && mPath != null) {
@@ -234,11 +354,23 @@ public class StorageVolume implements Parcelable {
@Override
public String toString() {
+ final StringBuilder buffer = new StringBuilder("StorageVolume: ").append(mDescription);
+ if (mFsUuid != null) {
+ buffer.append(" (").append(mFsUuid).append(")");
+ }
+ return buffer.toString();
+ }
+
+ /** {@hide} */
+ // TODO(b/26742218): find out where toString() is called internally and replace these calls by
+ // dump().
+ public String dump() {
final CharArrayWriter writer = new CharArrayWriter();
dump(new IndentingPrintWriter(writer, " ", 80));
return writer.toString();
}
+ /** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.println("StorageVolume:");
pw.increaseIndent();
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 5d64af577cba..d41bc070d6c1 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1494,11 +1494,9 @@ public class Preference implements Comparable<Preference> {
* @return True if the Preference is persistent. (This is not whether the
* value was persisted, since we may not necessarily commit if there
* will be a batch commit later.)
- * @see #getPersistedString(Set)
- *
- * @hide Pending API approval
+ * @see #getPersistedStringSet(Set)
*/
- protected boolean persistStringSet(Set<String> values) {
+ public boolean persistStringSet(Set<String> values) {
if (shouldPersist()) {
// Shouldn't store null
if (values.equals(getPersistedStringSet(null))) {
@@ -1527,10 +1525,8 @@ public class Preference implements Comparable<Preference> {
* @return The value from the SharedPreferences or the default return
* value.
* @see #persistStringSet(Set)
- *
- * @hide Pending API approval
*/
- protected Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
+ public Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
if (!shouldPersist()) {
return defaultReturnValue;
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 58f260cbe1cf..0540036f1a49 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -232,9 +232,8 @@ public final class PrintManager {
try {
return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting a print job info:" + printJobId, re);
+ throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -258,7 +257,7 @@ public final class PrintManager {
mService.addPrintJobStateChangeListener(wrappedListener, mAppId, mUserId);
mPrintJobStateChangeListeners.put(listener, wrappedListener);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error adding print job state change listener", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -288,7 +287,7 @@ public final class PrintManager {
try {
mService.removePrintJobStateChangeListener(wrappedListener, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error removing print job state change listener", re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -311,7 +310,7 @@ public final class PrintManager {
return new PrintJob(printJob, this);
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting print job", re);
+ throw re.rethrowFromSystemServer();
}
return null;
}
@@ -334,9 +333,8 @@ public final class PrintManager {
try {
return mService.getCustomPrinterIcon(printerId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting custom printer icon", re);
+ throw re.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -362,9 +360,8 @@ public final class PrintManager {
}
return printJobs;
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting print jobs", re);
+ throw re.rethrowFromSystemServer();
}
- return Collections.emptyList();
}
void cancelPrintJob(PrintJobId printJobId) {
@@ -375,7 +372,7 @@ public final class PrintManager {
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error canceling a print job: " + printJobId, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -387,7 +384,7 @@ public final class PrintManager {
try {
mService.restartPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error restarting a print job: " + printJobId, re);
+ throw re.rethrowFromSystemServer();
}
}
@@ -475,7 +472,7 @@ public final class PrintManager {
}
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error creating a print job", re);
+ throw re.rethrowFromSystemServer();
}
return null;
}
@@ -497,7 +494,7 @@ public final class PrintManager {
return enabledServices;
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting the enabled print services", re);
+ throw re.rethrowFromSystemServer();
}
return Collections.emptyList();
}
@@ -519,7 +516,7 @@ public final class PrintManager {
return installedServices;
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting the installed print services", re);
+ throw re.rethrowFromSystemServer();
}
return Collections.emptyList();
}
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index ea54f9203873..b9213513cc17 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -223,4 +223,98 @@ public class BlockedNumberContract {
return res != null && res.getBoolean(RES_CAN_BLOCK_NUMBERS, false);
}
+ /**
+ * <p>
+ * The contract between the blockednumber provider and the system.
+ * </p>
+ * <p>This is a wrapper over {@link BlockedNumberContract} that also manages the blocking
+ * behavior when the user contacts emergency services. See
+ * {@link #notifyEmergencyContact(Context)} for details. All methods are protected by
+ * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} and
+ * {@link android.Manifest.permission#WRITE_BLOCKED_NUMBERS} appropriately which ensure that
+ * only system can access the methods defined here.
+ * </p>
+ * @hide
+ */
+ public static class SystemContract {
+ /**
+ * A protected broadcast intent action for letting components with
+ * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppression
+ * status as returned by {@link #getBlockSuppressionStatus(Context)} has been updated.
+ */
+ public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED =
+ "android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED";
+
+ public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
+
+ public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression";
+
+ public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
+
+ public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
+ "get_block_suppression_status";
+
+ public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
+
+ public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
+ "blocking_suppressed_until_timestamp";
+
+ /**
+ * Notifies the provider that emergency services were contacted by the user.
+ * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
+ * of the contents of the provider for a duration defined by
+ * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}
+ * the provider unless {@link #endBlockSuppression(Context)} is called.
+ */
+ public static void notifyEmergencyContact(Context context) {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, null, null);
+ }
+
+ /**
+ * Notifies the provider to disable suppressing blocking. If emergency services were not
+ * contacted recently at all, calling this method is a no-op.
+ */
+ public static void endBlockSuppression(Context context) {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSION, null, null);
+ }
+
+ /**
+ * Returns {@code true} if {@code phoneNumber} is blocked taking
+ * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have
+ * not been contacted recently, this method is equivalent to
+ * {@link #isBlocked(Context, String)}.
+ */
+ public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
+ return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ }
+
+ public static BlockSuppressionStatus getBlockSuppressionStatus(Context context) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSION_STATUS, null, null);
+ return new BlockSuppressionStatus(res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false),
+ res.getLong(RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP, 0));
+ }
+
+ /**
+ * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
+ * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
+ * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+ */
+ public static class BlockSuppressionStatus {
+ public final boolean isSuppressed;
+ /**
+ * Timestamp in milliseconds from epoch.
+ */
+ public final long untilTimestampMillis;
+
+ public BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis) {
+ this.isSuppressed = isSuppressed;
+ this.untilTimestampMillis = untilTimestampMillis;
+ }
+ }
+ }
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index dfdd36d2e9cf..904b393efce7 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4982,6 +4982,17 @@ public final class ContactsContract {
*/
protected interface PhoneLookupColumns {
/**
+ * The ID of the data row.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA_ID = "data_id";
+ /**
+ * A reference to the {@link ContactsContract.Contacts#_ID} that this
+ * data belongs to.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String CONTACT_ID = "contact_id";
+ /**
* The phone number as the user entered it.
* <P>Type: TEXT</P>
*/
@@ -5055,6 +5066,18 @@ public final class ContactsContract {
* <td>Contact ID.</td>
* </tr>
* <tr>
+ * <td>long</td>
+ * <td>{@link #CONTACT_ID}</td>
+ * <td>read-only</td>
+ * <td>Contact ID.</td>
+ * </tr>
+ * <tr>
+ * <td>long</td>
+ * <td>{@link #DATA_ID}</td>
+ * <td>read-only</td>
+ * <td>Data ID.</td>
+ * </tr>
+ * <tr>
* <td>String</td>
* <td>{@link #LOOKUP_KEY}</td>
* <td>read-only</td>
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 8468040b1bad..370009893286 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -39,6 +39,7 @@ import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.RemoteException;
+import android.os.storage.StorageVolume;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
@@ -62,7 +63,8 @@ import java.util.List;
* All client apps must hold a valid URI permission grant to access documents,
* typically issued when a user makes a selection through
* {@link Intent#ACTION_OPEN_DOCUMENT}, {@link Intent#ACTION_CREATE_DOCUMENT},
- * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, or {@link Intent#ACTION_OPEN_EXTERNAL_DIRECTORY}.
+ * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, or
+ * {@link StorageVolume#createAccessIntent(String) StorageVolume.createAccessIntent}.
*
* @see DocumentsProvider
*/
@@ -358,6 +360,7 @@ public final class DocumentsContract {
* @see #COLUMN_MIME_TYPE
* @see DocumentsProvider#openTypedDocument(String, String, Bundle,
* android.os.CancellationSignal)
+ * @see DocumentsProvider#getDocumentStreamTypes(String, String)
*/
public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 9;
@@ -1201,7 +1204,7 @@ public final class DocumentsContract {
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
sourceDocumentUri.getAuthority());
try {
- return moveDocument(client, sourceParentDocumentUri, sourceDocumentUri,
+ return moveDocument(client, sourceDocumentUri, sourceParentDocumentUri,
targetParentDocumentUri);
} catch (Exception e) {
Log.w(TAG, "Failed to move document", e);
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 2250629bcc26..515f975bb578 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -316,7 +316,7 @@ public abstract class DocumentsProvider extends ContentProvider {
* @param parentDocumentId the parent of the document to move.
*/
@SuppressWarnings("unused")
- public boolean removeDocument(String documentId, String parentDocumentId)
+ public void removeDocument(String documentId, String parentDocumentId)
throws FileNotFoundException {
throw new UnsupportedOperationException("Remove not supported");
}
@@ -540,6 +540,7 @@ public abstract class DocumentsProvider extends ContentProvider {
* provider.
* @param signal used by the caller to signal if the request should be
* cancelled. May be null.
+ * @see #getDocumentStreamTypes(String, String)
*/
@SuppressWarnings("unused")
public AssetFileDescriptor openTypedDocument(
@@ -926,6 +927,7 @@ public abstract class DocumentsProvider extends ContentProvider {
*
* @see #openDocumentThumbnail(String, Point, CancellationSignal)
* @see #openTypedDocument(String, String, Bundle, CancellationSignal)
+ * @see #getDocumentStreamTypes(String, String)
*/
@Override
public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
@@ -938,6 +940,7 @@ public abstract class DocumentsProvider extends ContentProvider {
*
* @see #openDocumentThumbnail(String, Point, CancellationSignal)
* @see #openTypedDocument(String, String, Bundle, CancellationSignal)
+ * @see #getDocumentStreamTypes(String, String)
*/
@Override
public final AssetFileDescriptor openTypedAssetFile(
@@ -947,6 +950,55 @@ public abstract class DocumentsProvider extends ContentProvider {
}
/**
+ * Return a list of streamable MIME types matching the filter, which can be passed to
+ * {@link #openTypedDocument(String, String, Bundle, CancellationSignal)}.
+ *
+ * <p>The default implementation returns a MIME type provided by
+ * {@link #queryDocument(String, String[])} as long as it matches the filter and the document
+ * does not have the {@link Document#FLAG_VIRTUAL_DOCUMENT} flag set.
+ *
+ * @see #getStreamTypes(Uri, String)
+ * @see #openTypedDocument(String, String, Bundle, CancellationSignal)
+ */
+ public String[] getDocumentStreamTypes(String documentId, String mimeTypeFilter) {
+ Cursor cursor = null;
+ try {
+ cursor = queryDocument(documentId, null);
+ if (cursor.moveToFirst()) {
+ final String mimeType =
+ cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE));
+ final long flags =
+ cursor.getLong(cursor.getColumnIndexOrThrow(Document.COLUMN_FLAGS));
+ if ((flags & Document.FLAG_VIRTUAL_DOCUMENT) == 0 && mimeType != null &&
+ mimeTypeMatches(mimeTypeFilter, mimeType)) {
+ return new String[] { mimeType };
+ }
+ }
+ } catch (FileNotFoundException e) {
+ return null;
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ // No streamable MIME types.
+ return null;
+ }
+
+ /**
+ * Called by a client to determine the types of data streams that this content provider
+ * support for the given URI.
+ *
+ * <p>Overriding this method is deprecated. Override {@link #openTypedDocument} instead.
+ *
+ * @see #getDocumentStreamTypes(String, String)
+ */
+ @Override
+ public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+ enforceTree(uri);
+ return getDocumentStreamTypes(getDocumentId(uri), mimeTypeFilter);
+ }
+
+ /**
* @hide
*/
private final AssetFileDescriptor openTypedAssetFileImpl(
@@ -971,4 +1023,21 @@ public abstract class DocumentsProvider extends ContentProvider {
// For any other yet unhandled case, let the provider subclass handle it.
return openTypedDocument(documentId, mimeTypeFilter, opts, signal);
}
+
+ /**
+ * @hide
+ */
+ public static boolean mimeTypeMatches(String filter, String test) {
+ if (test == null) {
+ return false;
+ } else if (filter == null || "*/*".equals(filter)) {
+ return true;
+ } else if (filter.equals(test)) {
+ return true;
+ } else if (filter.endsWith("/*")) {
+ return filter.regionMatches(0, test, 0, filter.indexOf('/'));
+ } else {
+ return false;
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7830142d4e4b..cb45deb54922 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -58,6 +58,7 @@ import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LocaleList;
import android.util.Log;
import com.android.internal.util.ArrayUtils;
@@ -114,6 +115,21 @@ public final class Settings {
"android.settings.LOCATION_SOURCE_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of users.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_USER_SETTINGS =
+ "android.settings.USER_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of wireless controls
* such as Wi-Fi, Bluetooth and Mobile networks.
* <p>
@@ -201,6 +217,21 @@ public final class Settings {
"android.settings.ACCESSIBILITY_SETTINGS";
/**
+ * Activity Action: Launch the screen reader tutorial.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SCREEN_READER_TUTORIAL =
+ "android.settings.SCREEN_READER_TUTORIAL";
+
+
+ /**
* Activity Action: Show settings to control access to usage information.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -1203,6 +1234,8 @@ public final class Settings {
* Input: Nothing.
* <p>
* Output: Nothing.
+ *
+ * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
@@ -2039,6 +2072,8 @@ public final class Settings {
if (outConfig.fontScale < 0) {
outConfig.fontScale = 1;
}
+ outConfig.setLocales(LocaleList.forLanguageTags(
+ Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle)));
}
/**
@@ -2047,6 +2082,9 @@ public final class Settings {
*/
public static void clearConfiguration(Configuration inoutConfig) {
inoutConfig.fontScale = 0;
+ if (!inoutConfig.userSetLocale) {
+ inoutConfig.setLocales(LocaleList.getEmptyLocaleList());
+ }
}
/**
@@ -2064,12 +2102,15 @@ public final class Settings {
/** @hide */
public static boolean putConfigurationForUser(ContentResolver cr, Configuration config,
int userHandle) {
- return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle);
+ return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle) &&
+ Settings.System.putStringForUser(
+ cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle);
}
/** @hide */
public static boolean hasInterestingConfigurationChanges(int changes) {
- return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0;
+ return (changes & ActivityInfo.CONFIG_FONT_SCALE) != 0 ||
+ (changes & ActivityInfo.CONFIG_LOCALE) != 0;
}
/** @deprecated - Do not use */
@@ -2448,6 +2489,18 @@ public final class Settings {
};
/**
+ * The serialized system locale value.
+ *
+ * Do not use this value directory.
+ * To get system locale, use {@link android.util.LocaleList#getDefault} instead.
+ * To update system locale, use {@link com.android.internal.app.LocalePicker#updateLocales}
+ * instead.
+ * @hide
+ */
+ public static final String SYSTEM_LOCALES = "system_locales";
+
+
+ /**
* Name of an application package to be debugged.
*
* @deprecated Use {@link Global#DEBUG_APP} instead
@@ -2748,6 +2801,11 @@ public final class Settings {
*/
public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE);
+ /** {@hide} */
+ public static final String RINGTONE_CACHE = "ringtone_cache";
+ /** {@hide} */
+ public static final Uri RINGTONE_CACHE_URI = getUriFor(RINGTONE_CACHE);
+
/**
* Persistent store for the system-wide default notification sound.
*
@@ -2766,6 +2824,11 @@ public final class Settings {
*/
public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);
+ /** {@hide} */
+ public static final String NOTIFICATION_SOUND_CACHE = "notification_sound_cache";
+ /** {@hide} */
+ public static final Uri NOTIFICATION_SOUND_CACHE_URI = getUriFor(NOTIFICATION_SOUND_CACHE);
+
/**
* Persistent store for the system-wide default alarm alert.
*
@@ -2784,6 +2847,11 @@ public final class Settings {
*/
public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
+ /** {@hide} */
+ public static final String ALARM_ALERT_CACHE = "alarm_alert_cache";
+ /** {@hide} */
+ public static final Uri ALARM_ALERT_CACHE_URI = getUriFor(ALARM_ALERT_CACHE);
+
/**
* Persistent store for the system default media button event receiver.
*
@@ -4660,6 +4728,14 @@ public final class Settings {
"lock_screen_allow_private_notifications";
/**
+ * When set by a user, allows notification remote input atop a securely locked screen
+ * without having to unlock
+ * @hide
+ */
+ public static final String LOCK_SCREEN_ALLOW_REMOTE_INPUT =
+ "lock_screen_allow_remote_input";
+
+ /**
* Set by the system to track if the user needs to see the call to action for
* the lockscreen notification policy.
* @hide
@@ -5139,14 +5215,6 @@ public final class Settings {
public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
/**
- * Whether text-to-speech higher speech rate is enabled.
- * 0 = disabled.
- * 1 = enabled.
- * @hide
- */
- public static final String TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED =
- "tts_default_higher_speech_rate_enabled";
- /**
* Default text-to-speech language.
*
* @deprecated this setting is no longer in use, as of the Ice Cream
@@ -5907,11 +5975,50 @@ public final class Settings {
"camera_double_tap_power_gesture_disabled";
/**
- * Name of the package used as WebView provider (if unset the provider is instead determined
- * by the system).
+
+ /**
+ * Behavior of twilight on the device.
+ * One of {@link #TWILIGHT_MODE_LOCKED_OFF}, {@link #TWILIGHT_MODE_LOCKED_ON}
+ * or {@link #TWILIGHT_MODE_AUTO}.
* @hide
*/
- public static final String WEBVIEW_PROVIDER = "webview_provider";
+ public static final String TWILIGHT_MODE = "twilight_mode";
+
+ /**
+ * Twilight mode always off.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_LOCKED_OFF = 0;
+
+ /**
+ * Twilight mode always on.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_LOCKED_ON = 1;
+
+ /**
+ * Twilight mode auto.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_AUTO = 2;
+
+ /**
+ * Twilight mode auto, temporarily overriden to on.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_AUTO_OVERRIDE_OFF = 3;
+
+ /**
+ * Twilight mode auto, temporarily overriden to off.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_AUTO_OVERRIDE_ON = 4;
+
+ /**
+ * Whether brightness should automatically adjust based on twilight state.
+ * @hide
+ */
+ public static final String BRIGHTNESS_USE_TWILIGHT = "brightness_use_twilight";
/**
* This are the settings to be backed up.
@@ -5958,7 +6065,6 @@ public final class Settings {
ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
TTS_USE_DEFAULTS,
TTS_DEFAULT_RATE,
- TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED,
TTS_DEFAULT_PITCH,
TTS_DEFAULT_SYNTH,
TTS_DEFAULT_LANG,
@@ -6288,6 +6394,18 @@ public final class Settings {
public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
/**
+ * A semi-colon separated list of Bluetooth interoperability workarounds.
+ * Each entry is a partial Bluetooth device address string and an integer representing
+ * the feature to be disabled, separated by a comma. The integer must correspond
+ * to a interoperability feature as defined in "interop.h" in /system/bt.
+ * <p>
+ * Example: <br/>
+ * "00:11:22,0;01:02:03:04,2"
+ * @hide
+ */
+ public static final String BLUETOOTH_INTEROPERABILITY_LIST = "bluetooth_interoperability_list";
+
+ /**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
@@ -6724,6 +6842,16 @@ public final class Settings {
public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval";
/**
+ * Whether to disable the automatic scheduling of system updates.
+ * 1 = system updates won't be automatically scheduled (will always
+ * present notification instead).
+ * 0 = system updates will be automatically scheduled. (default)
+ * @hide
+ */
+ @SystemApi
+ public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
+
+ /**
* Whether the package manager should send package verification broadcasts for verifiers to
* review apps prior to installation.
* 1 = request apps to be verified prior to installation, if a verifier exists.
@@ -6940,6 +7068,28 @@ public final class Settings {
public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
"webview_data_reduction_proxy_key";
+ /**
+ * Whether or not the WebView fallback mechanism should be enabled.
+ * 0=disabled, 1=enabled.
+ * @hide
+ */
+ public static final String WEBVIEW_FALLBACK_LOGIC_ENABLED =
+ "webview_fallback_logic_enabled";
+
+ /**
+ * Name of the package used as WebView provider (if unset the provider is instead determined
+ * by the system).
+ * @hide
+ */
+ public static final String WEBVIEW_PROVIDER = "webview_provider";
+
+ /**
+ * Developer setting to enable WebView multiprocess rendering.
+ * @hide
+ */
+ @SystemApi
+ public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+
/**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
@@ -7739,13 +7889,20 @@ public final class Settings {
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
/**
- * If 1, the activity manager will aggressively finish activities and
+ * If not 0, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
* extended lifetime is used.
*/
public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
/**
+ * @hide
+ * If not 0, the activity manager will implement a looser version of background
+ * check that is more compatible with existing apps.
+ */
+ public static final String LENIENT_BACKGROUND_CHECK = "lenient_background_check";
+
+ /**
* Use Dock audio output for media:
* 0 = disabled
* 1 = enabled
@@ -7754,6 +7911,52 @@ public final class Settings {
public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
/**
+ * The surround sound formats AC3, DTS or IEC61937 are
+ * available for use if they are detected.
+ * This is the default mode.
+ *
+ * Note that AUTO is equivalent to ALWAYS for Android TVs and other
+ * devices that have an S/PDIF output. This is because S/PDIF
+ * is unidirectional and the TV cannot know if a decoder is
+ * connected. So it assumes they are always available.
+ * @hide
+ */
+ public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
+
+ /**
+ * AC3, DTS or IEC61937 are NEVER available, even if they
+ * are detected by the hardware. Those formats will not be
+ * reported.
+ *
+ * An example use case would be an AVR reports that it is capable of
+ * surround sound decoding but is broken. If NEVER is chosen
+ * then apps must use PCM output instead of encoded output.
+ * @hide
+ */
+ public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
+
+ /**
+ * AC3, DTS or IEC61937 are ALWAYS available, even if they
+ * are not detected by the hardware. Those formats will be
+ * reported as part of the HDMI output capability. Applications
+ * are then free to use either PCM or encoded output.
+ *
+ * An example use case would be a when TV was connected over
+ * TOS-link to an AVR. But the TV could not see it because TOS-link
+ * is unidirectional.
+ * @hide
+ */
+ public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
+
+ /**
+ * Set to ENCODED_SURROUND_OUTPUT_AUTO,
+ * ENCODED_SURROUND_OUTPUT_NEVER or
+ * ENCODED_SURROUND_OUTPUT_ALWAYS
+ * @hide
+ */
+ public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
+
+ /**
* Persisted safe headphone volume management state by AudioService
* @hide
*/
@@ -8028,6 +8231,15 @@ public final class Settings {
"uninstalled_ephemeral_app_cache_duration_millis";
/**
+ * Allows switching users when system user is locked.
+ * <p>
+ * Type: int
+ * @hide
+ */
+ public static final String ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED =
+ "allow_user_switching_when_system_user_locked";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -8060,6 +8272,7 @@ public final class Settings {
EMERGENCY_TONE,
CALL_AUTO_RETRY,
DOCK_AUDIO_MEDIA_ENABLED,
+ ENCODED_SURROUND_OUTPUT,
LOW_POWER_MODE_TRIGGER_LEVEL
};
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index 7cf1d715e947..8689dce3fef5 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -19,6 +19,7 @@ package android.security;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.OperationResult;
import android.security.KeystoreArguments;
@@ -74,4 +75,5 @@ interface IKeystoreService {
int addAuthToken(in byte[] authToken);
int onUserAdded(int userId, int parentId);
int onUserRemoved(int userId);
+ int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
}
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
new file mode 100644
index 000000000000..dc1876aaaebd
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable KeymasterCertificateChain;
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.java b/core/java/android/security/keymaster/KeymasterCertificateChain.java
new file mode 100644
index 000000000000..243b9fe5f7c6
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.java
@@ -0,0 +1,85 @@
+/*
+ * 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.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for the Java side of keystore-generated certificate chains.
+ *
+ * Serialization code for this must be kept in sync with system/security/keystore
+ * @hide
+ */
+public class KeymasterCertificateChain implements Parcelable {
+
+ private List<byte[]> mCertificates;
+
+ public static final Parcelable.Creator<KeymasterCertificateChain> CREATOR = new
+ Parcelable.Creator<KeymasterCertificateChain>() {
+ public KeymasterCertificateChain createFromParcel(Parcel in) {
+ return new KeymasterCertificateChain(in);
+ }
+ public KeymasterCertificateChain[] newArray(int size) {
+ return new KeymasterCertificateChain[size];
+ }
+ };
+
+ public KeymasterCertificateChain() {
+ mCertificates = null;
+ }
+
+ public KeymasterCertificateChain(List<byte[]> mCertificates) {
+ this.mCertificates = mCertificates;
+ }
+
+ private KeymasterCertificateChain(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public List<byte[]> getCertificates() {
+ return mCertificates;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (mCertificates == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(mCertificates.size());
+ for (byte[] arg : mCertificates) {
+ out.writeByteArray(arg);
+ }
+ }
+ }
+
+ public void readFromParcel(Parcel in) {
+ int length = in.readInt();
+ mCertificates = new ArrayList<byte[]>(length);
+ for (int i = 0; i < length; i++) {
+ mCertificates.add(in.createByteArray());
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 04d59522e40b..eb3d0312b2cf 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -58,6 +58,8 @@ public final class KeymasterDefs {
public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200;
+ public static final int KM_TAG_INCLUDE_UNIQUE_ID = KM_BOOL | 202;
+
public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
@@ -70,15 +72,17 @@ public final class KeymasterDefs {
public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
+ public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
- public static final int KM_TAG_APPLICATION_DATA = KM_BYTES | 700;
public static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
public static final int KM_TAG_ORIGIN = KM_ENUM | 702;
public static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
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_ASSOCIATED_DATA = KM_BYTES | 1000;
public static final int KM_TAG_NONCE = KM_BYTES | 1001;
diff --git a/core/java/android/security/net/config/ManifestConfigSource.java b/core/java/android/security/net/config/ManifestConfigSource.java
index 0e137cddc148..be0821c0c730 100644
--- a/core/java/android/security/net/config/ManifestConfigSource.java
+++ b/core/java/android/security/net/config/ManifestConfigSource.java
@@ -61,6 +61,7 @@ public class ManifestConfigSource implements ConfigSource {
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("Failed to look up ApplicationInfo", e);
}
+ int targetSdkVersion = info.targetSdkVersion;
int configResourceId = 0;
if (info != null && info.metaData != null) {
configResourceId = info.metaData.getInt(META_DATA_NETWORK_SECURITY_CONFIG);
@@ -74,14 +75,15 @@ public class ManifestConfigSource implements ConfigSource {
+ mContext.getResources().getResourceEntryName(configResourceId)
+ " debugBuild: " + debugBuild);
}
- source = new XmlConfigSource(mContext, configResourceId, debugBuild);
+ source = new XmlConfigSource(mContext, configResourceId, debugBuild,
+ targetSdkVersion);
} else {
if (DBG) {
Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
}
boolean usesCleartextTraffic =
(info.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0;
- source = new DefaultConfigSource(usesCleartextTraffic);
+ source = new DefaultConfigSource(usesCleartextTraffic, targetSdkVersion);
}
mConfigSource = source;
return mConfigSource;
@@ -92,11 +94,11 @@ public class ManifestConfigSource implements ConfigSource {
private final NetworkSecurityConfig mDefaultConfig;
- public DefaultConfigSource(boolean usesCleartextTraffic) {
- mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder()
+ public DefaultConfigSource(boolean usesCleartextTraffic, int targetSdkVersion) {
+ mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(targetSdkVersion)
.setCleartextTrafficPermitted(usesCleartextTraffic)
.build();
- }
+ }
@Override
public NetworkSecurityConfig getDefaultConfig() {
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index ebe14691464c..6d6a92a5b308 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -16,6 +16,7 @@
package android.security.net.config;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.security.cert.X509Certificate;
@@ -37,7 +38,6 @@ public final class NetworkSecurityConfig {
public static final boolean DEFAULT_CLEARTEXT_TRAFFIC_PERMITTED = true;
/** @hide */
public static final boolean DEFAULT_HSTS_ENFORCED = false;
- public static final NetworkSecurityConfig DEFAULT = getDefaultBuilder().build();
private final boolean mCleartextTrafficPermitted;
private final boolean mHstsEnforced;
@@ -163,21 +163,28 @@ public final class NetworkSecurityConfig {
* <li>Cleartext traffic is permitted.</li>
* <li>HSTS is not enforced.</li>
* <li>No certificate pinning is used.</li>
- * <li>The system and user added trusted certificate stores are trusted for connections.</li>
+ * <li>The system certificate store is trusted for connections.</li>
+ * <li>If the application targets API level 23 (Android M) or lower then the user certificate
+ * store is trusted by default as well.</li>
* </ol>
*
* @hide
*/
- public static final Builder getDefaultBuilder() {
- return new Builder()
+ public static final Builder getDefaultBuilder(int targetSdkVersion) {
+ Builder builder = new Builder()
.setCleartextTrafficPermitted(DEFAULT_CLEARTEXT_TRAFFIC_PERMITTED)
.setHstsEnforced(DEFAULT_HSTS_ENFORCED)
// System certificate store, does not bypass static pins.
.addCertificatesEntryRef(
- new CertificatesEntryRef(SystemCertificateSource.getInstance(), false))
- // User certificate store, does not bypass static pins.
- .addCertificatesEntryRef(
- new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
+ new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
+ // Applications targeting N and above must opt in into trusting the user added certificate
+ // store.
+ if (targetSdkVersion <= Build.VERSION_CODES.M) {
+ // User certificate store, does not bypass static pins.
+ builder.addCertificatesEntryRef(
+ new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
+ }
+ return builder;
}
/**
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index 982ed68f13da..81cad79bd05e 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -40,6 +40,9 @@ public class NetworkSecurityTrustManager implements X509TrustManager {
// TODO: Replace this with a general X509TrustManager and use duck-typing.
private final TrustManagerImpl mDelegate;
private final NetworkSecurityConfig mNetworkSecurityConfig;
+ private final Object mIssuersLock = new Object();
+
+ private X509Certificate[] mIssuers;
public NetworkSecurityTrustManager(NetworkSecurityConfig config) {
if (config == null) {
@@ -139,6 +142,19 @@ public class NetworkSecurityTrustManager implements X509TrustManager {
@Override
public X509Certificate[] getAcceptedIssuers() {
- return mDelegate.getAcceptedIssuers();
+ // TrustManagerImpl only looks at the provided KeyStore and not the TrustedCertificateStore
+ // for getAcceptedIssuers, so implement it here instead of delegating.
+ synchronized (mIssuersLock) {
+ if (mIssuers == null) {
+ Set<TrustAnchor> anchors = mNetworkSecurityConfig.getTrustAnchors();
+ X509Certificate[] issuers = new X509Certificate[anchors.size()];
+ int i = 0;
+ for (TrustAnchor anchor : anchors) {
+ issuers[i++] = anchor.certificate;
+ }
+ mIssuers = issuers;
+ }
+ return mIssuers.clone();
+ }
}
}
diff --git a/core/java/android/security/net/config/ResourceCertificateSource.java b/core/java/android/security/net/config/ResourceCertificateSource.java
index 8803c4b2559c..22fbee2feab3 100644
--- a/core/java/android/security/net/config/ResourceCertificateSource.java
+++ b/core/java/android/security/net/config/ResourceCertificateSource.java
@@ -44,7 +44,7 @@ public class ResourceCertificateSource implements CertificateSource {
public ResourceCertificateSource(int resourceId, Context context) {
mResourceId = resourceId;
- mContext = context.getApplicationContext();
+ mContext = context;
}
private void ensureInitialized() {
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index 1706e95513ff..2a8773cd3d86 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -3,9 +3,11 @@ package android.security.net.config;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.os.Build;
import android.util.ArraySet;
import android.util.Base64;
import android.util.Pair;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -34,20 +36,29 @@ public class XmlConfigSource implements ConfigSource {
private final Object mLock = new Object();
private final int mResourceId;
private final boolean mDebugBuild;
+ private final int mTargetSdkVersion;
private boolean mInitialized;
private NetworkSecurityConfig mDefaultConfig;
private Set<Pair<Domain, NetworkSecurityConfig>> mDomainMap;
private Context mContext;
+ @VisibleForTesting
public XmlConfigSource(Context context, int resourceId) {
this(context, resourceId, false);
}
+ @VisibleForTesting
public XmlConfigSource(Context context, int resourceId, boolean debugBuild) {
+ this(context, resourceId, debugBuild, Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
+ int targetSdkVersion) {
mResourceId = resourceId;
mContext = context;
mDebugBuild = debugBuild;
+ mTargetSdkVersion = targetSdkVersion;
}
public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
@@ -341,7 +352,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();
+ NetworkSecurityConfig.getDefaultBuilder(mTargetSdkVersion);
addDebugAnchorsIfNeeded(debugConfigBuilder, platformDefaultBuilder);
if (baseConfigBuilder != null) {
baseConfigBuilder.setParent(platformDefaultBuilder);
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index fb58f4e519c3..b5387f14e40c 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -97,14 +97,11 @@ public abstract class NotificationAssistantService extends NotificationListenerS
/** Notification was canceled because it was an invisible member of a group. */
public static final int REASON_GROUP_OPTIMIZATION = 13;
- /** Notification was canceled by the user banning the topic. */
- public static final int REASON_TOPIC_BANNED = 14;
-
/** Notification was canceled by the device administrator suspending the package. */
- public static final int REASON_PACKAGE_SUSPENDED = 15;
+ public static final int REASON_PACKAGE_SUSPENDED = 14;
/** Notification was canceled by the owning managed profile being turned off. */
- public static final int REASON_PROFILE_TURNED_OFF = 16;
+ public static final int REASON_PROFILE_TURNED_OFF = 15;
public class Adjustment {
int mImportance;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 7b461b17329c..b4332e181fc4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,8 +15,8 @@
*/
package android.service.notification;
-import android.service.notification.IStatusBarNotificationHolder;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.app.INotificationManager;
@@ -42,7 +42,10 @@ import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.widget.RemoteViews;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -752,9 +755,16 @@ public abstract class NotificationListenerService extends Service {
private void maybePopulateRemoteViews(Notification notification) {
if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
Builder builder = Builder.recoverBuilder(getContext(), notification);
- notification.contentView = builder.makeContentView();
- notification.bigContentView = builder.makeBigContentView();
- notification.headsUpContentView = builder.makeHeadsUpContentView();
+
+ // Some styles wrap Notification's contentView, bigContentView and headsUpContentView.
+ // First inflate them all, only then set them to avoid recursive wrapping.
+ RemoteViews content = builder.createContentView();
+ RemoteViews big = builder.createBigContentView();
+ RemoteViews headsUp = builder.createHeadsUpContentView();
+
+ notification.contentView = content;
+ notification.bigContentView = big;
+ notification.headsUpContentView = headsUp;
}
}
@@ -911,6 +921,14 @@ public abstract class NotificationListenerService extends Service {
* current {@link RankingMap}.
*/
public static class Ranking {
+
+ /** @hide */
+ @IntDef({VISIBILITY_NO_OVERRIDE, IMPORTANCE_UNSPECIFIED, IMPORTANCE_NONE,
+ IMPORTANCE_MIN, IMPORTANCE_LOW, IMPORTANCE_DEFAULT, IMPORTANCE_HIGH,
+ IMPORTANCE_MAX})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Importance {}
+
/** Value signifying that the user has not expressed a per-app visibility override value.
* @hide */
public static final int VISIBILITY_NO_OVERRIDE = -1000;
@@ -929,26 +947,31 @@ public abstract class NotificationListenerService extends Service {
public static final int IMPORTANCE_NONE = 0;
/**
- * Low notification importance: only shows in the shade, below the fold.
+ * Min notification importance: only shows in the shade, below the fold.
*/
- public static final int IMPORTANCE_LOW = 1;
+ public static final int IMPORTANCE_MIN = 1;
/**
- * Default notification importance: shows everywhere, but is not intrusive.
+ * Low notification importance: shows everywhere, but is not intrusive.
*/
- public static final int IMPORTANCE_DEFAULT = 2;
+ public static final int IMPORTANCE_LOW = 2;
/**
- * Higher notification importance: shows everywhere, makes noise,
+ * Default notification importance: shows everywhere, allowed to makes noise,
* but does not visually intrude.
*/
- public static final int IMPORTANCE_HIGH = 3;
+ public static final int IMPORTANCE_DEFAULT = 3;
+
+ /**
+ * Higher notification importance: shows everywhere, allowed to makes noise and peek.
+ */
+ public static final int IMPORTANCE_HIGH = 4;
/**
- * Highest notification importance: shows everywhere, makes noise,
- * and also visually intrudes.
+ * Highest notification importance: shows everywhere, allowed to makes noise, peek, and
+ * use full screen intents.
*/
- public static final int IMPORTANCE_MAX = 4;
+ public static final int IMPORTANCE_MAX = 5;
private String mKey;
private int mRank = -1;
@@ -956,7 +979,7 @@ public abstract class NotificationListenerService extends Service {
private boolean mMatchesInterruptionFilter;
private int mVisibilityOverride;
private int mSuppressedVisualEffects;
- private int mImportance;
+ private @Importance int mImportance;
private CharSequence mImportanceExplanation;
public Ranking() {}
@@ -1022,7 +1045,7 @@ public abstract class NotificationListenerService extends Service {
*
* @return the rank of the notification
*/
- public int getImportance() {
+ public @Importance int getImportance() {
return mImportance;
}
@@ -1041,7 +1064,7 @@ public abstract class NotificationListenerService extends Service {
CharSequence explanation) {
mKey = key;
mRank = rank;
- mIsAmbient = importance < IMPORTANCE_DEFAULT;
+ mIsAmbient = importance < IMPORTANCE_LOW;
mMatchesInterruptionFilter = matchesInterruptionFilter;
mVisibilityOverride = visibilityOverride;
mSuppressedVisualEffects = suppressedVisualEffects;
@@ -1058,6 +1081,8 @@ public abstract class NotificationListenerService extends Service {
return "UNSPECIFIED";
case IMPORTANCE_NONE:
return "NONE";
+ case IMPORTANCE_MIN:
+ return "MIN";
case IMPORTANCE_LOW:
return "LOW";
case IMPORTANCE_DEFAULT:
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 63853cb45676..97939a9ba3af 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -565,6 +565,10 @@ public class ZenModeConfig implements Parcelable {
private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
final String val = parser.getAttributeValue(null, att);
+ return safeBoolean(val, defValue);
+ }
+
+ private static boolean safeBoolean(String val, boolean defValue) {
if (TextUtils.isEmpty(val)) return defValue;
return Boolean.valueOf(val);
}
@@ -802,6 +806,7 @@ public class ZenModeConfig implements Parcelable {
.appendQueryParameter("days", toDayList(schedule.days))
.appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
.appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
+ .appendQueryParameter("exitAtAlarm", String.valueOf(schedule.exitAtAlarm))
.build();
}
@@ -825,6 +830,7 @@ public class ZenModeConfig implements Parcelable {
rt.startMinute = start[1];
rt.endHour = end[0];
rt.endMinute = end[1];
+ rt.exitAtAlarm = safeBoolean(conditionId.getQueryParameter("exitAtAlarm"), false);
return rt;
}
@@ -838,6 +844,8 @@ public class ZenModeConfig implements Parcelable {
public int startMinute;
public int endHour;
public int endMinute;
+ public boolean exitAtAlarm;
+ public long nextAlarm;
@Override
public int hashCode() {
@@ -852,7 +860,8 @@ public class ZenModeConfig implements Parcelable {
&& startHour == other.startHour
&& startMinute == other.startMinute
&& endHour == other.endHour
- && endMinute == other.endMinute;
+ && endMinute == other.endMinute
+ && exitAtAlarm == other.exitAtAlarm;
}
public ScheduleInfo copy() {
@@ -865,6 +874,8 @@ public class ZenModeConfig implements Parcelable {
rt.startMinute = startMinute;
rt.endHour = endHour;
rt.endMinute = endMinute;
+ rt.exitAtAlarm = exitAtAlarm;
+ rt.nextAlarm = nextAlarm;
return rt;
}
}
diff --git a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
index 52db22397b65..626b40827334 100644
--- a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
+++ b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
@@ -35,4 +35,6 @@ interface IPersistentDataBlockService {
void setOemUnlockEnabled(boolean enabled);
boolean getOemUnlockEnabled();
+ int getFlashLockState();
}
+
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 0ffdf68c4b30..cfeed51da86f 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -17,9 +17,13 @@
package android.service.persistentdata;
import android.annotation.SystemApi;
+import android.annotation.IntDef;
import android.os.RemoteException;
import android.util.Slog;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Interface for reading and writing data blocks to a persistent partition.
*
@@ -43,6 +47,27 @@ public class PersistentDataBlockManager {
private static final String TAG = PersistentDataBlockManager.class.getSimpleName();
private IPersistentDataBlockService sService;
+ /**
+ * Indicates that the device's bootloader lock state is UNKNOWN.
+ */
+ public static final int FLASH_LOCK_UNKNOWN = -1;
+ /**
+ * Indicates that the device's bootloader is UNLOCKED.
+ */
+ public static final int FLASH_LOCK_UNLOCKED = 0;
+ /**
+ * Indicates that the device's bootloader is LOCKED.
+ */
+ public static final int FLASH_LOCK_LOCKED = 1;
+
+ @IntDef({
+ FLASH_LOCK_UNKNOWN,
+ FLASH_LOCK_LOCKED,
+ FLASH_LOCK_UNLOCKED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FlashLockState {}
+
public PersistentDataBlockManager(IPersistentDataBlockService service) {
sService = service;
}
@@ -60,8 +85,7 @@ public class PersistentDataBlockManager {
try {
return sService.write(data);
} catch (RemoteException e) {
- onError("writing data");
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -72,8 +96,7 @@ public class PersistentDataBlockManager {
try {
return sService.read();
} catch (RemoteException e) {
- onError("reading data");
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -86,8 +109,7 @@ public class PersistentDataBlockManager {
try {
return sService.getDataBlockSize();
} catch (RemoteException e) {
- onError("getting data block size");
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -100,8 +122,7 @@ public class PersistentDataBlockManager {
try {
return sService.getMaximumDataBlockSize();
} catch (RemoteException e) {
- onError("getting maximum data block size");
- return -1;
+ throw e.rethrowFromSystemServer();
}
}
@@ -113,7 +134,7 @@ public class PersistentDataBlockManager {
try {
sService.wipe();
} catch (RemoteException e) {
- onError("wiping persistent partition");
+ throw e.rethrowFromSystemServer();
}
}
@@ -124,7 +145,7 @@ public class PersistentDataBlockManager {
try {
sService.setOemUnlockEnabled(enabled);
} catch (RemoteException e) {
- onError("setting OEM unlock enabled to " + enabled);
+ throw e.rethrowFromSystemServer();
}
}
@@ -135,12 +156,24 @@ public class PersistentDataBlockManager {
try {
return sService.getOemUnlockEnabled();
} catch (RemoteException e) {
- onError("getting OEM unlock enabled bit");
- return false;
+ throw e.rethrowFromSystemServer();
}
}
- private void onError(String msg) {
- Slog.v(TAG, "Remote exception while " + msg);
+ /**
+ * Retrieves available information about this device's flash lock state.
+ *
+ * @return FLASH_LOCK_STATE_LOCKED if device bootloader is locked,
+ * FLASH_LOCK_STATE_UNLOCKED if device bootloader is unlocked,
+ * or FLASH_LOCK_STATE unknown if this information cannot be ascertained
+ * on this device.
+ */
+ @FlashLockState
+ public int getFlashLockState() {
+ try {
+ return sService.getFlashLockState();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 0cf1175f8bc5..553d539eafee 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -16,6 +16,8 @@
package android.service.quicksettings;
import android.Manifest;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.app.Dialog;
import android.app.Service;
@@ -74,6 +76,14 @@ import android.view.WindowManager;
public class TileService extends Service {
/**
+ * An activity that provides a user interface for adjusting TileService preferences.
+ * Optional but recommended for apps that implement a TileService.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String ACTION_QS_TILE_PREFERENCES
+ = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+
+ /**
* Action that identifies a Service as being a TileService.
*/
public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 76a401d74559..9464a8754fa8 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -617,11 +617,7 @@ public class AlwaysOnHotwordDetector {
}
@Override
- public void onDetected(RecognitionEvent event) {
- if (! (event instanceof KeyphraseRecognitionEvent)) {
- Slog.e(TAG, "onDetected() called for a soundtrigger event.");
- return;
- }
+ public void onKeyphraseDetected(KeyphraseRecognitionEvent event) {
if (DBG) {
Slog.d(TAG, "onDetected(" + event + ")");
} else {
@@ -632,6 +628,10 @@ public class AlwaysOnHotwordDetector {
event.captureFormat, event.captureSession, event.data))
.sendToTarget();
}
+ @Override
+ public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
+ Slog.w(TAG, "Generic sound trigger event detected at AOHD: " + event);
+ }
@Override
public void onError(int status) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a98551752181..de8133b33aa6 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -271,7 +271,8 @@ public abstract class WallpaperService extends Service {
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect, boolean forceLayout) {
+ Configuration newConfig, Rect backDropRect, boolean forceLayout,
+ boolean alwaysConsumeNavBar) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0, outsets);
mCaller.sendMessage(msg);
@@ -790,7 +791,7 @@ public abstract class WallpaperService extends Service {
mFinalStableInsets.set(mDispatchedStableInsets);
WindowInsets insets = new WindowInsets(mFinalSystemInsets,
null, mFinalStableInsets,
- getResources().getConfiguration().isScreenRound());
+ getResources().getConfiguration().isScreenRound(), false);
if (DEBUG) {
Log.v(TAG, "dispatching insets=" + insets);
}
diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
index 675803c7b7bd..707c0fcb75ee 100644
--- a/core/java/android/text/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.Nullable;
import android.view.View;
import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
@@ -390,14 +391,17 @@ public final class BidiFormatter {
* @return Input string after applying the above processing. {@code null} if {@code str} is
* {@code null}.
*/
- public String unicodeWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+ public @Nullable String unicodeWrap(@Nullable String str, TextDirectionHeuristic heuristic,
+ boolean isolate) {
+ if (str == null) return null;
return unicodeWrap((CharSequence) str, heuristic, isolate).toString();
}
/**
* @hide
*/
- public CharSequence unicodeWrap(CharSequence str, TextDirectionHeuristic heuristic, boolean isolate) {
+ public @Nullable CharSequence unicodeWrap(@Nullable CharSequence str,
+ TextDirectionHeuristic heuristic, boolean isolate) {
if (str == null) return null;
final boolean isRtl = heuristic.isRtl(str, 0, str.length());
SpannableStringBuilder result = new SpannableStringBuilder();
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index fd9188b79599..bfe5c3ff255f 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -189,12 +189,6 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
mBottom = spacing;
- if (includepad) {
- mDesc = spacing + metrics.top;
- } else {
- mDesc = spacing + metrics.ascent;
- }
-
if (trustWidth) {
mMax = metrics.width;
} else {
@@ -214,6 +208,8 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
mTopPadding = metrics.top - metrics.ascent;
mBottomPadding = metrics.bottom - metrics.descent;
}
+
+ mDesc = spacing + mBottomPadding + (includepad ? metrics.top : metrics.ascent);
}
/**
@@ -427,9 +423,6 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
private float mMax;
private int mEllipsizedWidth, mEllipsizedStart, mEllipsizedCount;
- private static final TextPaint sTemp =
- new TextPaint();
-
public static class Metrics extends Paint.FontMetricsInt {
public int width;
diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java
new file mode 100644
index 000000000000..c0f0663084fe
--- /dev/null
+++ b/core/java/android/text/Emoji.java
@@ -0,0 +1,74 @@
+/*
+ * 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 java.util.Arrays;
+
+/**
+ * An utility class for Emoji.
+ * @hide
+ */
+public class Emoji {
+ // See http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
+ private static int[] EMOJI_MODIFIER_BASE = {
+ 0x261D, 0x26F9, 0x270A, 0x270B, 0x270C, 0x270D, 0x1F385, 0x1F3C3, 0x1F3C4, 0x1F3CA,
+ 0x1F3CB, 0x1F442, 0x1F443, 0x1F446, 0x1F447, 0x1F448, 0x1F449, 0x1F44A, 0x1F44B, 0x1F44C,
+ 0x1F44D, 0x1F44E, 0x1F44F, 0x1F450, 0x1F466, 0x1F467, 0x1F468, 0x1F469, 0x1F46E, 0x1F470,
+ 0x1F471, 0x1F472, 0x1F473, 0x1F474, 0x1F475, 0x1F476, 0x1F477, 0x1F478, 0x1F47C, 0x1F481,
+ 0x1F482, 0x1F483, 0x1F485, 0x1F486, 0x1F487, 0x1F4AA, 0x1F575, 0x1F57A, 0x1F590, 0x1F595,
+ 0x1F596, 0x1F645, 0x1F646, 0x1F647, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F6A3,
+ 0x1F6B4, 0x1F6B5, 0x1F6B6, 0x1F6C0, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D,
+ 0x1F91E, 0x1F926, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, 0x1F939,
+ 0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E
+ };
+
+ // See http://www.unicode.org/emoji/charts/emoji-zwj-sequences.html
+ private static int[] ZWJ_EMOJI = {
+ 0x2764, 0x1F441, 0x1F466, 0x1F467, 0x1F468, 0x1F469, 0x1F48B, 0x1F5E8
+ };
+
+ public static int COMBINING_ENCLOSING_KEYCAP = 0x20E3;
+
+ public static int ZERO_WIDTH_JOINER = 0x200D;
+
+ public static int VARIATION_SELECTOR_16 = 0xFE0F;
+
+ // Returns true if the given code point is regional indicator symbol.
+ public static boolean isRegionalIndicatorSymbol(int codepoint) {
+ return 0x1F1E6 <= codepoint && codepoint <= 0x1F1FF;
+ }
+
+ // Returns true if the given code point is emoji modifier.
+ public static boolean isEmojiModifier(int codepoint) {
+ return 0x1F3FB <= codepoint && codepoint <= 0x1F3FF;
+ }
+
+ // Returns true if the given code point is emoji modifier base.
+ public static boolean isEmojiModifierBase(int codePoint) {
+ return Arrays.binarySearch(EMOJI_MODIFIER_BASE, codePoint) >= 0;
+ }
+
+ // Returns true if the character appears before or after zwj in a zwj emoji sequence.
+ public static boolean isZwjEmoji(int codePoint) {
+ return Arrays.binarySearch(ZWJ_EMOJI, codePoint) >= 0;
+ }
+
+ // Returns true if the character can be a base character of COMBINING ENCLOSING KEYCAP.
+ public static boolean isKeycapBase(int codePoint) {
+ return ('0' <= codePoint && codePoint <= '9') || codePoint == '#' || codePoint == '*';
+ }
+}
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index ed91239cccdf..409994d7cd84 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -54,6 +54,11 @@ import android.text.style.UnderlineSpan;
import java.io.IOException;
import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* This class processes HTML strings into displayable styled text.
@@ -354,24 +359,48 @@ public class Html {
}
}
- private static String getTextStyles(Spanned text, int start, int end) {
- final StringBuilder style = new StringBuilder(" style=\"margin-top:0; margin-bottom:0;");
+ private static String getTextStyles(Spanned text, int start, int end,
+ boolean forceNoVerticalMargin, boolean includeTextAlign) {
+ String margin = null;
+ String textAlign = null;
- final AlignmentSpan[] alignmentSpans = text.getSpans(start, end, AlignmentSpan.class);
- final int len = alignmentSpans.length;
- if (len > 0) {
- final Layout.Alignment alignment = alignmentSpans[len - 1].getAlignment();
- if (alignment == Layout.Alignment.ALIGN_NORMAL) {
- style.append(" text-align:start;");
- } else if (alignment == Layout.Alignment.ALIGN_CENTER) {
- style.append(" text-align:center;");
- } else if (alignment == Layout.Alignment.ALIGN_OPPOSITE) {
- style.append(" text-align:end;");
+ if (forceNoVerticalMargin) {
+ margin = "margin-top:0; margin-bottom:0;";
+ }
+ if (includeTextAlign) {
+ final AlignmentSpan[] alignmentSpans = text.getSpans(start, end, AlignmentSpan.class);
+
+ // Only use the last AlignmentSpan with flag SPAN_PARAGRAPH
+ for (int i = alignmentSpans.length - 1; i >= 0; i--) {
+ AlignmentSpan s = alignmentSpans[i];
+ if ((text.getSpanFlags(s) & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH) {
+ final Layout.Alignment alignment = s.getAlignment();
+ if (alignment == Layout.Alignment.ALIGN_NORMAL) {
+ textAlign = "text-align:start;";
+ } else if (alignment == Layout.Alignment.ALIGN_CENTER) {
+ textAlign = "text-align:center;";
+ } else if (alignment == Layout.Alignment.ALIGN_OPPOSITE) {
+ textAlign = "text-align:end;";
+ }
+ break;
+ }
}
}
- style.append("\"");
- return style.toString();
+ if (margin == null && textAlign == null) {
+ return "";
+ }
+
+ final StringBuilder style = new StringBuilder(" style=\"");
+ if (margin != null && textAlign != null) {
+ style.append(margin).append(" ").append(textAlign);
+ } else if (margin != null) {
+ style.append(margin);
+ } else if (textAlign != null) {
+ style.append(textAlign);
+ }
+
+ return style.append("\"").toString();
}
private static void withinBlockquote(StringBuilder out, Spanned text, int start, int end,
@@ -393,46 +422,55 @@ public class Html {
next = end;
}
- boolean isListItem = false;
- ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
- for (ParagraphStyle paragraphStyle : paragraphStyles) {
- final int spanFlags = text.getSpanFlags(paragraphStyle);
- if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
- && paragraphStyle instanceof BulletSpan) {
- isListItem = true;
- break;
+ if (next == i) {
+ if (isInList) {
+ // Current paragraph is no longer a list item; close the previously opened list
+ isInList = false;
+ out.append("</ul>\n");
+ }
+ out.append("<br>\n");
+ } else {
+ boolean isListItem = false;
+ ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
+ for (ParagraphStyle paragraphStyle : paragraphStyles) {
+ final int spanFlags = text.getSpanFlags(paragraphStyle);
+ if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
+ && paragraphStyle instanceof BulletSpan) {
+ isListItem = true;
+ break;
+ }
}
- }
- if (isListItem && !isInList) {
- // Current paragraph is the first item in a list
- isInList = true;
- out.append("<ul>\n");
- }
+ if (isListItem && !isInList) {
+ // Current paragraph is the first item in a list
+ isInList = true;
+ out.append("<ul")
+ .append(getTextStyles(text, i, next, true, false))
+ .append(">\n");
+ }
- if (isInList && !isListItem) {
- // Current paragraph is no longer a list item; close the previously opened list
- isInList = false;
- out.append("</ul>\n");
- }
+ if (isInList && !isListItem) {
+ // Current paragraph is no longer a list item; close the previously opened list
+ isInList = false;
+ out.append("</ul>\n");
+ }
- String tagType = isListItem ? "li" : "p";
- out.append("<").append(tagType).append(getTextDirection(text, start, next))
- .append(getTextStyles(text, start, next)).append(">");
+ String tagType = isListItem ? "li" : "p";
+ out.append("<").append(tagType)
+ .append(getTextDirection(text, i, next))
+ .append(getTextStyles(text, i, next, !isListItem, true))
+ .append(">");
- if (next - i == 0) {
- out.append("<br>");
- } else {
withinParagraph(out, text, i, next);
- }
- out.append("</");
- out.append(tagType);
- out.append(">\n");
+ out.append("</");
+ out.append(tagType);
+ out.append(">\n");
- if (next == end && isInList) {
- isInList = false;
- out.append("</ul>\n");
+ if (next == end && isInList) {
+ isInList = false;
+ out.append("</ul>\n");
+ }
}
next++;
@@ -640,7 +678,7 @@ public class Html {
class HtmlToSpannedConverter implements ContentHandler {
- private static final float[] HEADER_SIZES = {
+ private static final float[] HEADING_SIZES = {
1.5f, 1.4f, 1.3f, 1.2f, 1.1f, 1f,
};
@@ -651,6 +689,58 @@ class HtmlToSpannedConverter implements ContentHandler {
private Html.TagHandler mTagHandler;
private int mFlags;
+ private static Pattern sTextAlignPattern;
+ private static Pattern sForegroundColorPattern;
+ private static Pattern sBackgroundColorPattern;
+ private static Pattern sTextDecorationPattern;
+
+ /**
+ * Name-value mapping of HTML/CSS colors which have different values in {@link Color}.
+ */
+ private static final Map<String, Integer> sColorMap;
+
+ static {
+ sColorMap = new HashMap<>();
+ sColorMap.put("darkgray", 0xFFA9A9A9);
+ sColorMap.put("gray", 0xFF808080);
+ sColorMap.put("lightgray", 0xFFD3D3D3);
+ sColorMap.put("darkgrey", 0xFFA9A9A9);
+ sColorMap.put("grey", 0xFF808080);
+ sColorMap.put("lightgrey", 0xFFD3D3D3);
+ sColorMap.put("green", 0xFF008000);
+ }
+
+ private static Pattern getTextAlignPattern() {
+ if (sTextAlignPattern == null) {
+ sTextAlignPattern = Pattern.compile("(?:\\s+|\\A)text-align\\s*:\\s*(\\S*)\\b");
+ }
+ return sTextAlignPattern;
+ }
+
+ private static Pattern getForegroundColorPattern() {
+ if (sForegroundColorPattern == null) {
+ sForegroundColorPattern = Pattern.compile(
+ "(?:\\s+|\\A)color\\s*:\\s*(\\S*)\\b");
+ }
+ return sForegroundColorPattern;
+ }
+
+ private static Pattern getBackgroundColorPattern() {
+ if (sBackgroundColorPattern == null) {
+ sBackgroundColorPattern = Pattern.compile(
+ "(?:\\s+|\\A)background(?:-color)?\\s*:\\s*(\\S*)\\b");
+ }
+ return sBackgroundColorPattern;
+ }
+
+ private static Pattern getTextDecorationPattern() {
+ if (sTextDecorationPattern == null) {
+ sTextDecorationPattern = Pattern.compile(
+ "(?:\\s+|\\A)text-decoration\\s*:\\s*(\\S*)\\b");
+ }
+ return sTextDecorationPattern;
+ }
+
public HtmlToSpannedConverter( String source, Html.ImageGetter imageGetter,
Html.TagHandler tagHandler, Parser parser, int flags) {
mSource = source;
@@ -701,11 +791,18 @@ class HtmlToSpannedConverter implements ContentHandler {
private void handleStartTag(String tag, Attributes attributes) {
if (tag.equalsIgnoreCase("br")) {
// We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
- // so we can safely emite the linebreaks when we handle the close tag.
+ // so we can safely emit the linebreaks when we handle the close tag.
} else if (tag.equalsIgnoreCase("p")) {
- handleP(mSpannableStringBuilder);
+ startBlockElement(mSpannableStringBuilder, attributes, getMarginParagraph());
+ startCssStyle(mSpannableStringBuilder, attributes);
+ } else if (tag.equalsIgnoreCase("ul")) {
+ startBlockElement(mSpannableStringBuilder, attributes, getMarginList());
+ } else if (tag.equalsIgnoreCase("li")) {
+ startLi(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("div")) {
- handleP(mSpannableStringBuilder);
+ startBlockElement(mSpannableStringBuilder, attributes, getMarginDiv());
+ } else if (tag.equalsIgnoreCase("span")) {
+ startCssStyle(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("strong")) {
start(mSpannableStringBuilder, new Bold());
} else if (tag.equalsIgnoreCase("b")) {
@@ -725,8 +822,7 @@ class HtmlToSpannedConverter implements ContentHandler {
} else if (tag.equalsIgnoreCase("font")) {
startFont(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("blockquote")) {
- handleP(mSpannableStringBuilder);
- start(mSpannableStringBuilder, new Blockquote());
+ startBlockquote(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("tt")) {
start(mSpannableStringBuilder, new Monospace());
} else if (tag.equalsIgnoreCase("a")) {
@@ -744,10 +840,9 @@ class HtmlToSpannedConverter implements ContentHandler {
} else if (tag.equalsIgnoreCase("sub")) {
start(mSpannableStringBuilder, new Sub());
} else if (tag.length() == 2 &&
- Character.toLowerCase(tag.charAt(0)) == 'h' &&
- tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
- handleP(mSpannableStringBuilder);
- start(mSpannableStringBuilder, new Header(tag.charAt(1) - '1'));
+ Character.toLowerCase(tag.charAt(0)) == 'h' &&
+ tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
+ startHeading(mSpannableStringBuilder, attributes, tag.charAt(1) - '1');
} else if (tag.equalsIgnoreCase("img")) {
startImg(mSpannableStringBuilder, attributes, mImageGetter);
} else if (mTagHandler != null) {
@@ -759,9 +854,16 @@ class HtmlToSpannedConverter implements ContentHandler {
if (tag.equalsIgnoreCase("br")) {
handleBr(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("p")) {
- handleP(mSpannableStringBuilder);
+ endCssStyle(mSpannableStringBuilder);
+ endBlockElement(mSpannableStringBuilder);
+ } else if (tag.equalsIgnoreCase("ul")) {
+ endBlockElement(mSpannableStringBuilder);
+ } else if (tag.equalsIgnoreCase("li")) {
+ endLi(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("div")) {
- handleP(mSpannableStringBuilder);
+ endBlockElement(mSpannableStringBuilder);
+ } else if (tag.equalsIgnoreCase("span")) {
+ endCssStyle(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("strong")) {
end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD));
} else if (tag.equalsIgnoreCase("b")) {
@@ -781,11 +883,9 @@ class HtmlToSpannedConverter implements ContentHandler {
} else if (tag.equalsIgnoreCase("font")) {
endFont(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("blockquote")) {
- handleP(mSpannableStringBuilder);
- end(mSpannableStringBuilder, Blockquote.class, new QuoteSpan());
+ endBlockquote(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("tt")) {
- end(mSpannableStringBuilder, Monospace.class,
- new TypefaceSpan("monospace"));
+ end(mSpannableStringBuilder, Monospace.class, new TypefaceSpan("monospace"));
} else if (tag.equalsIgnoreCase("a")) {
endA(mSpannableStringBuilder);
} else if (tag.equalsIgnoreCase("u")) {
@@ -803,40 +903,151 @@ class HtmlToSpannedConverter implements ContentHandler {
} else if (tag.length() == 2 &&
Character.toLowerCase(tag.charAt(0)) == 'h' &&
tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
- handleP(mSpannableStringBuilder);
- endHeader(mSpannableStringBuilder);
+ endHeading(mSpannableStringBuilder);
} else if (mTagHandler != null) {
mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader);
}
}
- private static void handleP(SpannableStringBuilder text) {
- int len = text.length();
+ private int getMarginParagraph() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH);
+ }
- if (len >= 1 && text.charAt(len - 1) == '\n') {
- if (len >= 2 && text.charAt(len - 2) == '\n') {
- return;
- }
+ private int getMarginHeading() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING);
+ }
- text.append("\n");
+ private int getMarginListItem() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM);
+ }
+
+ private int getMarginList() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_LIST);
+ }
+
+ private int getMarginDiv() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_DIV);
+ }
+
+ private int getMarginBlockquote() {
+ return getMargin(Html.FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE);
+ }
+
+ /**
+ * Returns the minimum number of newline characters needed before and after a given block-level
+ * element.
+ *
+ * @param flag the corresponding option flag defined in {@link Html} of a block-level element
+ */
+ private int getMargin(int flag) {
+ if ((flag & mFlags) != 0) {
+ return 1;
+ }
+ return 2;
+ }
+
+ private static void appendNewlines(Editable text, int minNewline) {
+ final int len = text.length();
+
+ if (len == 0) {
return;
}
- if (len != 0) {
- text.append("\n\n");
+ int existingNewlines = 0;
+ for (int i = len - 1; i >= 0 && text.charAt(i) == '\n'; i--) {
+ existingNewlines++;
}
+
+ for (int j = existingNewlines; j < minNewline; j++) {
+ text.append("\n");
+ }
+ }
+
+ private static void startBlockElement(Editable text, Attributes attributes, int margin) {
+ final int len = text.length();
+ if (margin > 0) {
+ appendNewlines(text, margin);
+ start(text, new Newline(margin));
+ }
+
+ String style = attributes.getValue("", "style");
+ if (style != null) {
+ Matcher m = getTextAlignPattern().matcher(style);
+ if (m.find()) {
+ String alignment = m.group(1);
+ if (alignment.equalsIgnoreCase("start")) {
+ start(text, new Alignment(Layout.Alignment.ALIGN_NORMAL));
+ } else if (alignment.equalsIgnoreCase("center")) {
+ start(text, new Alignment(Layout.Alignment.ALIGN_CENTER));
+ } else if (alignment.equalsIgnoreCase("end")) {
+ start(text, new Alignment(Layout.Alignment.ALIGN_OPPOSITE));
+ }
+ }
+ }
+ }
+
+ private static void endBlockElement(Editable text) {
+ Newline n = getLast(text, Newline.class);
+ if (n != null) {
+ appendNewlines(text, n.mNumNewlines);
+ text.removeSpan(n);
+ }
+
+ Alignment a = getLast(text, Alignment.class);
+ if (a != null) {
+ setSpanFromMark(text, a, new AlignmentSpan.Standard(a.mAlignment));
+ }
+ }
+
+ private static void handleBr(Editable text) {
+ text.append('\n');
+ }
+
+ private void startLi(Editable text, Attributes attributes) {
+ startBlockElement(text, attributes, getMarginListItem());
+ start(text, new Bullet());
+ startCssStyle(text, attributes);
+ }
+
+ private static void endLi(Editable text) {
+ endCssStyle(text);
+ endBlockElement(text);
+ end(text, Bullet.class, new BulletSpan());
+ }
+
+ private void startBlockquote(Editable text, Attributes attributes) {
+ startBlockElement(text, attributes, getMarginBlockquote());
+ start(text, new Blockquote());
+ }
+
+ private static void endBlockquote(Editable text) {
+ endBlockElement(text);
+ end(text, Blockquote.class, new QuoteSpan());
}
- private static void handleBr(SpannableStringBuilder text) {
- text.append("\n");
+ private void startHeading(Editable text, Attributes attributes, int level) {
+ startBlockElement(text, attributes, getMarginHeading());
+ start(text, new Heading(level));
}
- private static Object getLast(Spanned text, Class kind) {
+ private static void endHeading(Editable text) {
+ // RelativeSizeSpan and StyleSpan are CharacterStyles
+ // Their ranges should not include the newlines at the end
+ Heading h = getLast(text, Heading.class);
+ if (h != null) {
+ setSpanFromMark(text, h, new RelativeSizeSpan(HEADING_SIZES[h.mLevel]),
+ new StyleSpan(Typeface.BOLD));
+ }
+
+ endBlockElement(text);
+ }
+
+ private static <T> T getLast(Spanned text, Class<T> kind) {
/*
* This knows that the last returned object from getSpans()
* will be the most recently added.
*/
- Object[] objs = text.getSpans(0, text.length(), kind);
+ T[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
@@ -845,26 +1056,77 @@ class HtmlToSpannedConverter implements ContentHandler {
}
}
- private static void start(SpannableStringBuilder text, Object mark) {
+ private static void setSpanFromMark(Spannable text, Object mark, Object... spans) {
+ int where = text.getSpanStart(mark);
+ text.removeSpan(mark);
+ int len = text.length();
+ if (where != len) {
+ for (Object span : spans) {
+ text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ }
+
+ private static void start(Editable text, Object mark) {
int len = text.length();
- text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
+ text.setSpan(mark, len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
- private static void end(SpannableStringBuilder text, Class kind,
- Object repl) {
+ private static void end(Editable text, Class kind, Object repl) {
int len = text.length();
Object obj = getLast(text, kind);
- int where = text.getSpanStart(obj);
+ if (obj != null) {
+ setSpanFromMark(text, obj, repl);
+ }
+ }
- text.removeSpan(obj);
+ private void startCssStyle(Editable text, Attributes attributes) {
+ String style = attributes.getValue("", "style");
+ if (style != null) {
+ Matcher m = getForegroundColorPattern().matcher(style);
+ if (m.find()) {
+ int c = getHtmlColor(m.group(1));
+ if (c != -1) {
+ start(text, new Foreground(c | 0xFF000000));
+ }
+ }
- if (where != len) {
- text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ m = getBackgroundColorPattern().matcher(style);
+ if (m.find()) {
+ int c = getHtmlColor(m.group(1));
+ if (c != -1) {
+ start(text, new Background(c | 0xFF000000));
+ }
+ }
+
+ m = getTextDecorationPattern().matcher(style);
+ if (m.find()) {
+ String textDecoration = m.group(1);
+ if (textDecoration.equalsIgnoreCase("line-through")) {
+ start(text, new Strikethrough());
+ }
+ }
+ }
+ }
+
+ private static void endCssStyle(Editable text) {
+ Strikethrough s = getLast(text, Strikethrough.class);
+ if (s != null) {
+ setSpanFromMark(text, s, new StrikethroughSpan());
+ }
+
+ Background b = getLast(text, Background.class);
+ if (b != null) {
+ setSpanFromMark(text, b, new BackgroundColorSpan(b.mBackgroundColor));
+ }
+
+ Foreground f = getLast(text, Foreground.class);
+ if (f != null) {
+ setSpanFromMark(text, f, new ForegroundColorSpan(f.mForegroundColor));
}
}
- private static void startImg(SpannableStringBuilder text,
- Attributes attributes, Html.ImageGetter img) {
+ private static void startImg(Editable text, Attributes attributes, Html.ImageGetter img) {
String src = attributes.getValue("", "src");
Drawable d = null;
@@ -885,98 +1147,58 @@ class HtmlToSpannedConverter implements ContentHandler {
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- private static void startFont(SpannableStringBuilder text,
- Attributes attributes) {
+ private void startFont(Editable text, Attributes attributes) {
String color = attributes.getValue("", "color");
String face = attributes.getValue("", "face");
- int len = text.length();
- text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK);
- }
-
- private static void endFont(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Font.class);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- Font f = (Font) obj;
-
- if (!TextUtils.isEmpty(f.mColor)) {
- if (f.mColor.startsWith("@")) {
- Resources res = Resources.getSystem();
- String name = f.mColor.substring(1);
- int colorRes = res.getIdentifier(name, "color", "android");
- if (colorRes != 0) {
- ColorStateList colors = res.getColorStateList(colorRes, null);
- text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null),
- where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- } else {
- int c = Color.getHtmlColor(f.mColor);
- if (c != -1) {
- text.setSpan(new ForegroundColorSpan(c | 0xFF000000),
- where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
+ if (!TextUtils.isEmpty(color)) {
+ int c = getHtmlColor(color);
+ if (c != -1) {
+ start(text, new Foreground(c | 0xFF000000));
}
+ }
- if (f.mFace != null) {
- text.setSpan(new TypefaceSpan(f.mFace), where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
+ if (!TextUtils.isEmpty(face)) {
+ start(text, new Font(face));
}
}
- private static void startA(SpannableStringBuilder text, Attributes attributes) {
- String href = attributes.getValue("", "href");
+ private static void endFont(Editable text) {
+ Font font = getLast(text, Font.class);
+ if (font != null) {
+ setSpanFromMark(text, font, new TypefaceSpan(font.mFace));
+ }
- int len = text.length();
- text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK);
+ Foreground foreground = getLast(text, Foreground.class);
+ if (foreground != null) {
+ setSpanFromMark(text, foreground,
+ new ForegroundColorSpan(foreground.mForegroundColor));
+ }
}
- private static void endA(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Href.class);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- Href h = (Href) obj;
+ private static void startA(Editable text, Attributes attributes) {
+ String href = attributes.getValue("", "href");
+ start(text, new Href(href));
+ }
+ private static void endA(Editable text) {
+ Href h = getLast(text, Href.class);
+ if (h != null) {
if (h.mHref != null) {
- text.setSpan(new URLSpan(h.mHref), where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ setSpanFromMark(text, h, new URLSpan((h.mHref)));
}
}
}
- private static void endHeader(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Header.class);
-
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- // Back off not to change only the text, not the blank line.
- while (len > where && text.charAt(len - 1) == '\n') {
- len--;
- }
-
- if (where != len) {
- Header h = (Header) obj;
-
- text.setSpan(new RelativeSizeSpan(HEADER_SIZES[h.mLevel]),
- where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- text.setSpan(new StyleSpan(Typeface.BOLD),
- where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ private int getHtmlColor(String color) {
+ if ((mFlags & Html.FROM_HTML_OPTION_USE_CSS_COLORS)
+ == Html.FROM_HTML_OPTION_USE_CSS_COLORS) {
+ Integer i = sColorMap.get(color.toLowerCase(Locale.US));
+ if (i != null) {
+ return i;
+ }
}
+ return Color.getHtmlColor(color);
}
public void setDocumentLocator(Locator locator) {
@@ -1060,13 +1282,12 @@ class HtmlToSpannedConverter implements ContentHandler {
private static class Blockquote { }
private static class Super { }
private static class Sub { }
+ private static class Bullet { }
private static class Font {
- public String mColor;
public String mFace;
- public Font(String color, String face) {
- mColor = color;
+ public Font(String face) {
mFace = face;
}
}
@@ -1079,11 +1300,43 @@ class HtmlToSpannedConverter implements ContentHandler {
}
}
- private static class Header {
+ private static class Foreground {
+ private int mForegroundColor;
+
+ public Foreground(int foregroundColor) {
+ mForegroundColor = foregroundColor;
+ }
+ }
+
+ private static class Background {
+ private int mBackgroundColor;
+
+ public Background(int backgroundColor) {
+ mBackgroundColor = backgroundColor;
+ }
+ }
+
+ private static class Heading {
private int mLevel;
- public Header(int level) {
+ public Heading(int level) {
mLevel = level;
}
}
+
+ private static class Newline {
+ private int mNumNewlines;
+
+ public Newline(int numNewlines) {
+ mNumNewlines = numNewlines;
+ }
+ }
+
+ private static class Alignment {
+ private Layout.Alignment mAlignment;
+
+ public Alignment(Layout.Alignment alignment) {
+ mAlignment = alignment;
+ }
+ }
}
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index fe7571f62176..e79dfcacac29 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -16,13 +16,19 @@
package android.text.method;
+import android.icu.lang.UCharacter;
+import android.icu.lang.UProperty;
import android.view.KeyEvent;
import android.view.View;
import android.text.*;
import android.text.method.TextKeyListener.Capitalize;
+import android.text.style.ReplacementSpan;
import android.widget.TextView;
import java.text.BreakIterator;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
/**
* Abstract base class for key listeners.
@@ -63,6 +69,213 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
return backspaceOrForwardDelete(view, content, keyCode, event, true);
}
+ // Returns true if the given code point is a variation selector.
+ private static boolean isVariationSelector(int codepoint) {
+ return UCharacter.hasBinaryProperty(codepoint, UProperty.VARIATION_SELECTOR);
+ }
+
+ // Returns the offset of the replacement span edge if the offset is inside of the replacement
+ // span. Otherwise, does nothing and returns the input offset value.
+ private static int adjustReplacementSpan(CharSequence text, int offset, boolean moveToStart) {
+ if (!(text instanceof Spanned)) {
+ return offset;
+ }
+
+ ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, ReplacementSpan.class);
+ for (int i = 0; i < spans.length; i++) {
+ final int start = ((Spanned) text).getSpanStart(spans[i]);
+ final int end = ((Spanned) text).getSpanEnd(spans[i]);
+
+ if (start < offset && end > offset) {
+ offset = moveToStart ? start : end;
+ }
+ }
+ return offset;
+ }
+
+ // Returns the start offset to be deleted by a backspace key from the given offset.
+ private static int getOffsetForBackspaceKey(CharSequence text, int offset) {
+ if (offset <= 1) {
+ return 0;
+ }
+
+ // Initial state
+ final int STATE_START = 0;
+
+ // The offset is immediately before a KEYCAP.
+ final int STATE_BEFORE_KEYCAP = 1;
+ // The offset is immediately before a variation selector and a KEYCAP.
+ final int STATE_BEFORE_VS_AND_KEYCAP = 2;
+
+ // The offset is immediately before an emoji modifier.
+ final int STATE_BEFORE_EMOJI_MODIFIER = 3;
+ // The offset is immediately before a variation selector and an emoji modifier.
+ final int STATE_BEFORE_VS_AND_EMOJI_MODIFIER = 4;
+
+ // The offset is immediately before a variation selector.
+ final int STATE_BEFORE_VS = 5;
+
+ // The offset is immediately before a ZWJ emoji.
+ final int STATE_BEFORE_ZWJ_EMOJI = 6;
+ // The offset is immediately before a ZWJ that were seen before a ZWJ emoji.
+ final int STATE_BEFORE_ZWJ = 7;
+ // The offset is immediately before a variation selector and a ZWJ that were seen before a
+ // ZWJ emoji.
+ final int STATE_BEFORE_VS_AND_ZWJ = 8;
+
+ // The number of following RIS code points is odd.
+ final int STATE_ODD_NUMBERED_RIS = 9;
+ // The number of following RIS code points is even.
+ final int STATE_EVEN_NUMBERED_RIS = 10;
+
+ // The state machine has been stopped.
+ final int STATE_FINISHED = 11;
+
+ int deleteCharCount = 0; // Char count to be deleted by backspace.
+ int lastSeenVSCharCount = 0; // Char count of previous variation selector.
+
+ int state = STATE_START;
+
+ int tmpOffset = offset;
+ do {
+ final int codePoint = Character.codePointBefore(text, tmpOffset);
+ tmpOffset -= Character.charCount(codePoint);
+
+ switch (state) {
+ case STATE_START:
+ deleteCharCount = Character.charCount(codePoint);
+ if (isVariationSelector(codePoint)) {
+ state = STATE_BEFORE_VS;
+ } else if (Emoji.isZwjEmoji(codePoint)) {
+ state = STATE_BEFORE_ZWJ_EMOJI;
+ } else if (Emoji.isRegionalIndicatorSymbol(codePoint)) {
+ state = STATE_ODD_NUMBERED_RIS;
+ } else if (Emoji.isEmojiModifier(codePoint)) {
+ state = STATE_BEFORE_EMOJI_MODIFIER;
+ } else if (codePoint == Emoji.COMBINING_ENCLOSING_KEYCAP) {
+ state = STATE_BEFORE_KEYCAP;
+ } else {
+ state = STATE_FINISHED;
+ }
+ break;
+ case STATE_ODD_NUMBERED_RIS:
+ if (Emoji.isRegionalIndicatorSymbol(codePoint)) {
+ deleteCharCount += 2; /* Char count of RIS */
+ state = STATE_EVEN_NUMBERED_RIS;
+ } else {
+ state = STATE_FINISHED;
+ }
+ break;
+ case STATE_EVEN_NUMBERED_RIS:
+ if (Emoji.isRegionalIndicatorSymbol(codePoint)) {
+ deleteCharCount -= 2; /* Char count of RIS */
+ state = STATE_ODD_NUMBERED_RIS;
+ } else {
+ state = STATE_FINISHED;
+ }
+ break;
+ case STATE_BEFORE_KEYCAP:
+ if (isVariationSelector(codePoint)) {
+ lastSeenVSCharCount = Character.charCount(codePoint);
+ state = STATE_BEFORE_VS_AND_KEYCAP;
+ break;
+ }
+
+ if (Emoji.isKeycapBase(codePoint)) {
+ deleteCharCount += Character.charCount(codePoint);
+ }
+ state = STATE_FINISHED;
+ break;
+ case STATE_BEFORE_VS_AND_KEYCAP:
+ if (Emoji.isKeycapBase(codePoint)) {
+ deleteCharCount += lastSeenVSCharCount + Character.charCount(codePoint);
+ }
+ state = STATE_FINISHED;
+ break;
+ case STATE_BEFORE_EMOJI_MODIFIER:
+ if (isVariationSelector(codePoint)) {
+ lastSeenVSCharCount = Character.charCount(codePoint);
+ state = STATE_BEFORE_VS_AND_EMOJI_MODIFIER;
+ break;
+ } else if (Emoji.isEmojiModifierBase(codePoint)) {
+ deleteCharCount += Character.charCount(codePoint);
+ }
+ state = STATE_FINISHED;
+ break;
+ case STATE_BEFORE_VS_AND_EMOJI_MODIFIER:
+ if (Emoji.isEmojiModifierBase(codePoint)) {
+ deleteCharCount += lastSeenVSCharCount + Character.charCount(codePoint);
+ }
+ state = STATE_FINISHED;
+ break;
+ case STATE_BEFORE_VS:
+ if (Emoji.isZwjEmoji(codePoint)) {
+ deleteCharCount += Character.charCount(codePoint);
+ state = STATE_BEFORE_ZWJ_EMOJI;
+ break;
+ }
+
+ if (!isVariationSelector(codePoint) &&
+ UCharacter.getCombiningClass(codePoint) == 0) {
+ deleteCharCount += Character.charCount(codePoint);
+ }
+ state = STATE_FINISHED;
+ break;
+ case STATE_BEFORE_ZWJ_EMOJI:
+ if (codePoint == Emoji.ZERO_WIDTH_JOINER) {
+ state = STATE_BEFORE_ZWJ;
+ } else {
+ state = STATE_FINISHED;
+ }
+ break;
+ case STATE_BEFORE_ZWJ:
+ if (Emoji.isZwjEmoji(codePoint)) {
+ deleteCharCount += Character.charCount(codePoint) + 1; // +1 for ZWJ.
+ state = STATE_BEFORE_ZWJ_EMOJI;
+ } else if (isVariationSelector(codePoint)) {
+ lastSeenVSCharCount = Character.charCount(codePoint);
+ state = STATE_BEFORE_VS_AND_ZWJ;
+ } else {
+ state = STATE_FINISHED;
+ }
+ break;
+ case STATE_BEFORE_VS_AND_ZWJ:
+ if (Emoji.isZwjEmoji(codePoint)) {
+ // +1 for ZWJ.
+ deleteCharCount += lastSeenVSCharCount + 1 + Character.charCount(codePoint);
+ lastSeenVSCharCount = 0;
+ state = STATE_BEFORE_ZWJ_EMOJI;
+ } else {
+ state = STATE_FINISHED;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("state " + state + " is unknown");
+ }
+ } while (tmpOffset > 0 && state != STATE_FINISHED);
+
+ return adjustReplacementSpan(text, offset - deleteCharCount, true /* move to the start */);
+ }
+
+ // Returns the end offset to be deleted by a forward delete key from the given offset.
+ private static int getOffsetForForwardDeleteKey(CharSequence text, int offset) {
+ final int len = text.length();
+
+ if (offset >= len - 1) {
+ return len;
+ }
+
+ int codePoint = Character.codePointAt(text, offset);
+ offset += Character.charCount(codePoint);
+ if (offset == len) {
+ return len;
+ }
+
+ // TODO: Handle emoji, combining chars, etc.
+
+ return adjustReplacementSpan(text, offset, false /* move to the end */);
+ }
+
private boolean backspaceOrForwardDelete(View view, Editable content, int keyCode,
KeyEvent event, boolean isForwardDelete) {
// Ensure the key event does not have modifiers except ALT or SHIFT or CTRL.
@@ -98,9 +311,9 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
final int start = Selection.getSelectionEnd(content);
final int end;
if (isForwardDelete) {
- end = TextUtils.getOffsetAfter(content, start);
+ end = getOffsetForForwardDeleteKey(content, start);
} else {
- end = TextUtils.getOffsetBefore(content, start);
+ end = getOffsetForBackspaceKey(content, start);
}
if (start != end) {
content.delete(Math.min(start, end), Math.max(start, end));
@@ -224,6 +437,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
if (handled) {
adjustMetaAfterKeypress(content);
+ return true;
}
return super.onKeyDown(view, content, keyCode, event);
@@ -257,4 +471,3 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
return true;
}
}
-
diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java
index 26c725faed15..07190b2f1d6a 100644
--- a/core/java/android/text/style/ReplacementSpan.java
+++ b/core/java/android/text/style/ReplacementSpan.java
@@ -16,18 +16,49 @@
package android.text.style;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.text.TextPaint;
public abstract class ReplacementSpan extends MetricAffectingSpan {
- public abstract int getSize(Paint paint, CharSequence text,
- int start, int end,
- Paint.FontMetricsInt fm);
- public abstract void draw(Canvas canvas, CharSequence text,
- int start, int end, float x,
- int top, int y, int bottom, Paint paint);
+ /**
+ * Returns the width of the span. Extending classes can set the height of the span by updating
+ * attributes of {@link android.graphics.Paint.FontMetricsInt}. If the span covers the whole
+ * text, and the height is not set,
+ * {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} will not be
+ * called for the span.
+ *
+ * @param paint Paint instance.
+ * @param text Current text.
+ * @param start Start character index for span.
+ * @param end End character index for span.
+ * @param fm Font metrics, can be null.
+ * @return Width of the span.
+ */
+ public abstract int getSize(@NonNull Paint paint, CharSequence text,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @Nullable Paint.FontMetricsInt fm);
+
+ /**
+ * Draws the span into the canvas.
+ *
+ * @param canvas Canvas into which the span should be rendered.
+ * @param text Current text.
+ * @param start Start character index for span.
+ * @param end End character index for span.
+ * @param x Edge of the replacement closest to the leading margin.
+ * @param top Top of the line.
+ * @param y Baseline.
+ * @param bottom Bottom of the line.
+ * @param paint Paint instance.
+ */
+ public abstract void draw(@NonNull Canvas canvas, CharSequence text,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x,
+ int top, int y, int bottom, @NonNull Paint paint);
/**
* This method does nothing, since ReplacementSpans are measured
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index b2e8d3351028..627183f0cf24 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -16,8 +16,6 @@
package android.transition;
-import com.android.internal.R;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -28,6 +26,8 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
+
/**
* This transition tracks changes to the visibility of target views in the
* start and end scenes and fades views in or out when they become visible
@@ -144,12 +144,9 @@ public class Fade extends Visibility {
Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
startView + ", " + view);
}
- float startAlpha = 0;
- if (startValues != null) {
- startAlpha = (Float) startValues.values.get(PROPNAME_TRANSITION_ALPHA);
- if (startAlpha == 1) {
- startAlpha = 0;
- }
+ float startAlpha = getStartAlpha(startValues, 0);
+ if (startAlpha == 1) {
+ startAlpha = 0;
}
return createAnimation(view, startAlpha, 1);
}
@@ -157,11 +154,19 @@ public class Fade extends Visibility {
@Override
public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,
TransitionValues endValues) {
- float startAlpha = 1;
+ float startAlpha = getStartAlpha(startValues, 1);
+ return createAnimation(view, startAlpha, 0);
+ }
+
+ private static float getStartAlpha(TransitionValues startValues, float fallbackValue) {
+ float startAlpha = fallbackValue;
if (startValues != null) {
- startAlpha = (Float) startValues.values.get(PROPNAME_TRANSITION_ALPHA);
+ Float startAlphaFloat = (Float) startValues.values.get(PROPNAME_TRANSITION_ALPHA);
+ if (startAlphaFloat != null) {
+ startAlpha = startAlphaFloat;
+ }
}
- return createAnimation(view, startAlpha, 0);
+ return startAlpha;
}
private static class FadeAnimatorListener extends AnimatorListenerAdapter {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 48614c0c1014..4afa9fef9912 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -2191,9 +2191,6 @@ public abstract class Transition implements Cloneable {
return mNameOverrides;
}
- /** @hide */
- public void forceVisibility(int visibility, boolean isStartValue) {}
-
@Override
public String toString() {
return toString("");
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 09d2c69138be..583dc0f1ef2c 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -46,7 +46,7 @@ import java.util.ArrayList;
* transition on the affected view targets:</p>
* <pre>
* &lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
- * android:ordering="sequential"&gt;
+ * android:transitionOrdering="sequential"&gt;
* &lt;fade/&gt;
* &lt;changeBounds/&gt;
* &lt;/transitionSet&gt;
@@ -318,15 +318,6 @@ public class TransitionSet extends Transition {
}
}
- /** @hide */
- @Override
- public void forceVisibility(int visibility, boolean isStartValue) {
- int numTransitions = mTransitions.size();
- for (int i = 0; i < numTransitions; i++) {
- mTransitions.get(i).forceVisibility(visibility, isStartValue);
- }
- }
-
/**
* Removes the specified child transition from this set.
*
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index eb95a02dd75b..4eaab3748b1e 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -85,9 +85,6 @@ public abstract class Visibility extends Transition {
private int mMode = MODE_IN | MODE_OUT;
- private int mForcedStartVisibility = -1;
- private int mForcedEndVisibility = -1;
-
public Visibility() {}
public Visibility(Context context, AttributeSet attrs) {
@@ -132,13 +129,8 @@ public abstract class Visibility extends Transition {
return sTransitionProperties;
}
- private void captureValues(TransitionValues transitionValues, int forcedVisibility) {
- int visibility;
- if (forcedVisibility != -1) {
- visibility = forcedVisibility;
- } else {
- visibility = transitionValues.view.getVisibility();
- }
+ private void captureValues(TransitionValues transitionValues) {
+ int visibility = transitionValues.view.getVisibility();
transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
int[] loc = new int[2];
@@ -148,22 +140,12 @@ public abstract class Visibility extends Transition {
@Override
public void captureStartValues(TransitionValues transitionValues) {
- captureValues(transitionValues, mForcedStartVisibility);
+ captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
- captureValues(transitionValues, mForcedEndVisibility);
- }
-
- /** @hide */
- @Override
- public void forceVisibility(int visibility, boolean isStartValue) {
- if (isStartValue) {
- mForcedStartVisibility = visibility;
- } else {
- mForcedEndVisibility = visibility;
- }
+ captureValues(transitionValues);
}
/**
@@ -298,12 +280,6 @@ public abstract class Visibility extends Transition {
return null;
}
}
- final boolean isForcedVisibility = mForcedStartVisibility != -1 ||
- mForcedEndVisibility != -1;
- if (isForcedVisibility) {
- // Make sure that we reverse the effect of onDisappear's setTransitionAlpha(0)
- endValues.view.setTransitionAlpha(1);
- }
return onAppear(sceneRoot, endValues.view, startValues, endValues);
}
@@ -447,21 +423,16 @@ public abstract class Visibility extends Transition {
}
if (viewToKeep != null) {
- int originalVisibility = -1;
- final boolean isForcedVisibility = mForcedStartVisibility != -1 ||
- mForcedEndVisibility != -1;
- if (!isForcedVisibility) {
- originalVisibility = viewToKeep.getVisibility();
- viewToKeep.setTransitionVisibility(View.VISIBLE);
- }
+ int originalVisibility = viewToKeep.getVisibility();
+ viewToKeep.setTransitionVisibility(View.VISIBLE);
Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
if (animator != null) {
DisappearListener disappearListener = new DisappearListener(viewToKeep,
- finalVisibility, isForcedVisibility);
+ finalVisibility);
animator.addListener(disappearListener);
animator.addPauseListener(disappearListener);
addListener(disappearListener);
- } else if (!isForcedVisibility) {
+ } else {
viewToKeep.setTransitionVisibility(originalVisibility);
}
return animator;
@@ -509,18 +480,15 @@ public abstract class Visibility extends Transition {
private static class DisappearListener
extends TransitionListenerAdapter implements AnimatorListener, AnimatorPauseListener {
- private final boolean mIsForcedVisibility;
private final View mView;
private final int mFinalVisibility;
private final ViewGroup mParent;
private boolean mLayoutSuppressed;
- private boolean mFinalVisibilitySet = false;
boolean mCanceled = false;
- public DisappearListener(View view, int finalVisibility, boolean isForcedVisibility) {
+ public DisappearListener(View view, int finalVisibility) {
this.mView = view;
- this.mIsForcedVisibility = isForcedVisibility;
this.mFinalVisibility = finalVisibility;
this.mParent = (ViewGroup) view.getParent();
// Prevent a layout from including mView in its calculation.
@@ -529,14 +497,14 @@ public abstract class Visibility extends Transition {
@Override
public void onAnimationPause(Animator animation) {
- if (!mCanceled && !mIsForcedVisibility) {
+ if (!mCanceled) {
mView.setTransitionVisibility(mFinalVisibility);
}
}
@Override
public void onAnimationResume(Animator animation) {
- if (!mCanceled && !mIsForcedVisibility) {
+ if (!mCanceled) {
mView.setTransitionVisibility(View.VISIBLE);
}
}
@@ -576,15 +544,10 @@ public abstract class Visibility extends Transition {
private void hideViewWhenNotCanceled() {
if (!mCanceled) {
- if (mIsForcedVisibility) {
- mView.setTransitionAlpha(0);
- } else if (!mFinalVisibilitySet) {
- // Recreate the parent's display list in case it includes mView.
- mView.setTransitionVisibility(mFinalVisibility);
- if (mParent != null) {
- mParent.invalidate();
- }
- mFinalVisibilitySet = true;
+ // Recreate the parent's display list in case it includes mView.
+ mView.setTransitionVisibility(mFinalVisibility);
+ if (mParent != null) {
+ mParent.invalidate();
}
}
// Layout is allowed now that the View is in its final state
@@ -592,7 +555,7 @@ public abstract class Visibility extends Transition {
}
private void suppressLayout(boolean suppress) {
- if (mLayoutSuppressed != suppress && mParent != null && !mIsForcedVisibility) {
+ if (mLayoutSuppressed != suppress && mParent != null) {
mLayoutSuppressed = suppress;
mParent.suppressLayout(suppress);
}
diff --git a/core/java/android/util/BackupUtils.java b/core/java/android/util/BackupUtils.java
new file mode 100644
index 000000000000..474cedaa0552
--- /dev/null
+++ b/core/java/android/util/BackupUtils.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Utility methods for Backup/Restore
+ * @hide
+ */
+public class BackupUtils {
+
+ public static final int NULL = 0;
+ public static final int NOT_NULL = 1;
+
+ /**
+ * Thrown when there is a backup version mismatch
+ * between the data received and what the system can handle
+ */
+ public static class BadVersionException extends Exception {
+ public BadVersionException(String message) {
+ super(message);
+ }
+ }
+
+ public static String readString(DataInputStream in) throws IOException {
+ return (in.readByte() == NOT_NULL) ? in.readUTF() : null;
+ }
+
+ public static void writeString(DataOutputStream out, String val) throws IOException {
+ if (val != null) {
+ out.writeByte(NOT_NULL);
+ out.writeUTF(val);
+ } else {
+ out.writeByte(NULL);
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 544444dfd59f..5bc6c9480025 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -16,6 +16,8 @@
package android.util;
+import android.os.DeadSystemException;
+
import com.android.internal.os.RuntimeInit;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.LineBreakBufferedWriter;
@@ -377,8 +379,9 @@ public final class Log {
* Helper function for long messages. Uses the LineBreakBufferedWriter to break
* up long messages and stacktraces along newlines, but tries to write in large
* chunks. This is to avoid truncation.
+ * @hide
*/
- private static int printlns(int bufID, int priority, String tag, String msg,
+ public static int printlns(int bufID, int priority, String tag, String msg,
Throwable tr) {
ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
// Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
@@ -404,6 +407,11 @@ public final class Log {
if (t instanceof UnknownHostException) {
break;
}
+ if (t instanceof DeadSystemException) {
+ lbbw.println("DeadSystemException: The system died; "
+ + "earlier logs will point to the root cause");
+ break;
+ }
t = t.getCause();
}
if (t == null) {
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 81c8c458beab..728f72309439 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -72,8 +72,7 @@ public class ApkSignatureSchemeV2Verifier {
* <p>The attribute contains a comma-separated set of signature scheme IDs.
*/
public static final String SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME = "X-Android-APK-Signed";
- // TODO: Change the value when signing scheme finalized.
- public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 1234567890;
+ public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 2;
/**
* Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 664c02a70771..c7b1d03b120b 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -1053,6 +1053,7 @@ final class AccessibilityInteractionController {
private void prefetchPredecessorsOfVirtualNode(AccessibilityNodeInfo root,
View providerHost, AccessibilityNodeProvider provider,
List<AccessibilityNodeInfo> outInfos) {
+ final int initialResultSize = outInfos.size();
long parentNodeId = root.getParentNodeId();
int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
@@ -1071,6 +1072,12 @@ final class AccessibilityInteractionController {
AccessibilityNodeProvider.HOST_VIEW_ID);
}
if (parent == null) {
+ // Going up the parent relation we found a null predecessor,
+ // so remove these disconnected nodes form the result.
+ final int currentResultSize = outInfos.size();
+ for (int i = currentResultSize - 1; i >= initialResultSize; i--) {
+ outInfos.remove(i);
+ }
// Couldn't obtain the parent, which means we have a
// disconnected sub-tree. Abort prefetch immediately.
return;
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
new file mode 100644
index 000000000000..8e66f86f421e
--- /dev/null
+++ b/core/java/android/view/FrameMetrics.java
@@ -0,0 +1,281 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.view.Window;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class containing timing data for various milestones in a frame
+ * lifecycle reported by the rendering subsystem.
+ * <p>
+ * Supported metrics can be queried via their corresponding identifier.
+ * </p>
+ */
+public final class FrameMetrics {
+
+ /**
+ * Metric identifier for unknown delay.
+ * <p>
+ * Represents the number of nanoseconds elapsed waiting for the
+ * UI thread to become responsive and process the frame. This
+ * should be 0 most of the time.
+ * </p>
+ */
+ public static final int UNKNOWN_DELAY_DURATION = 0;
+
+ /**
+ * Metric identifier for input handling duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed issuing
+ * input handling callbacks.
+ * </p>
+ */
+ public static final int INPUT_HANDLING_DURATION = 1;
+
+ /**
+ * Metric identifier for animation callback duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed issuing
+ * animation callbacks.
+ * </p>
+ */
+ public static final int ANIMATION_DURATION = 2;
+
+ /**
+ * Metric identifier for layout/measure duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed measuring
+ * and laying out the invalidated pieces of the view hierarchy.
+ * </p>
+ */
+ public static final int LAYOUT_MEASURE_DURATION = 3;
+ /**
+ * Metric identifier for draw duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed computing
+ * DisplayLists for transformations applied to the view
+ * hierarchy.
+ * </p>
+ */
+ public static final int DRAW_DURATION = 4;
+
+ /**
+ * Metric identifier for sync duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed
+ * synchronizing the computed display lists with the render
+ * thread.
+ * </p>
+ */
+ public static final int SYNC_DURATION = 5;
+
+ /**
+ * Metric identifier for command issue duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed
+ * issuing draw commands to the GPU.
+ * </p>
+ */
+ public static final int COMMAND_ISSUE_DURATION = 6;
+
+ /**
+ * Metric identifier for swap buffers duration.
+ * <p>
+ * Represents the number of nanoseconds elapsed issuing
+ * the frame buffer for this frame to the display
+ * subsystem.
+ * </p>
+ */
+ public static final int SWAP_BUFFERS_DURATION = 7;
+
+ /**
+ * Metric identifier for total frame duration.
+ * <p>
+ * Represents the total time in nanoseconds this frame took to render
+ * and be issued to the display subsystem.
+ * </p>
+ * <p>
+ * Equal to the sum of the values of all other time-valued metric
+ * identifiers.
+ * </p>
+ */
+ public static final int TOTAL_DURATION = 8;
+
+ /**
+ * Metric identifier for a boolean value determining whether this frame was
+ * the first to draw in a new Window layout.
+ * <p>
+ * {@link #getMetric(int)} will return 0 for false, 1 for true.
+ * </p>
+ * <p>
+ * First draw frames are expected to be slow and should usually be exempt
+ * from display jank calculations as they do not cause skips in animations
+ * and are usually hidden by window animations or other tricks.
+ * </p>
+ */
+ public static final int FIRST_DRAW_FRAME = 9;
+
+ private static final int FRAME_INFO_FLAG_FIRST_DRAW = 1 << 0;
+
+ /**
+ * Identifiers for metrics available for each frame.
+ *
+ * {@see {@link #getMetric(int)}}
+ * @hide
+ */
+ @IntDef({
+ UNKNOWN_DELAY_DURATION,
+ INPUT_HANDLING_DURATION,
+ ANIMATION_DURATION,
+ LAYOUT_MEASURE_DURATION,
+ DRAW_DURATION,
+ SYNC_DURATION,
+ COMMAND_ISSUE_DURATION,
+ SWAP_BUFFERS_DURATION,
+ TOTAL_DURATION,
+ FIRST_DRAW_FRAME,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Metric {}
+
+ /**
+ * Timestamp indices for frame milestones.
+ *
+ * May change from release to release.
+ *
+ * Must be kept in sync with frameworks/base/libs/hwui/FrameInfo.h.
+ *
+ * @hide
+ */
+ @IntDef ({
+ Index.FLAGS,
+ Index.INTENDED_VSYNC,
+ Index.VSYNC,
+ Index.OLDEST_INPUT_EVENT,
+ Index.NEWEST_INPUT_EVENT,
+ Index.HANDLE_INPUT_START,
+ Index.ANIMATION_START,
+ Index.PERFORM_TRAVERSALS_START,
+ Index.DRAW_START,
+ Index.SYNC_QUEUED,
+ Index.SYNC_START,
+ Index.ISSUE_DRAW_COMMANDS_START,
+ Index.SWAP_BUFFERS,
+ Index.FRAME_COMPLETED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface Index {
+ int FLAGS = 0;
+ int INTENDED_VSYNC = 1;
+ int VSYNC = 2;
+ int OLDEST_INPUT_EVENT = 3;
+ int NEWEST_INPUT_EVENT = 4;
+ int HANDLE_INPUT_START = 5;
+ int ANIMATION_START = 6;
+ int PERFORM_TRAVERSALS_START = 7;
+ int DRAW_START = 8;
+ int SYNC_QUEUED = 9;
+ int SYNC_START = 10;
+ int ISSUE_DRAW_COMMANDS_START = 11;
+ int SWAP_BUFFERS = 12;
+ int FRAME_COMPLETED = 13;
+
+ int FRAME_STATS_COUNT = 14; // must always be last
+ }
+
+ /*
+ * Bucket endpoints for each Metric defined above.
+ *
+ * Each defined metric *must* have a corresponding entry
+ * in this list.
+ */
+ private static final int[] DURATIONS = new int[] {
+ // UNKNOWN_DELAY
+ Index.INTENDED_VSYNC, Index.HANDLE_INPUT_START,
+ // INPUT_HANDLING
+ Index.HANDLE_INPUT_START, Index.ANIMATION_START,
+ // ANIMATION
+ Index.ANIMATION_START, Index.PERFORM_TRAVERSALS_START,
+ // LAYOUT_MEASURE
+ Index.PERFORM_TRAVERSALS_START, Index.DRAW_START,
+ // DRAW
+ Index.DRAW_START, Index.SYNC_QUEUED,
+ // SYNC
+ Index.SYNC_START, Index.ISSUE_DRAW_COMMANDS_START,
+ // COMMAND_ISSUE
+ Index.ISSUE_DRAW_COMMANDS_START, Index.SWAP_BUFFERS,
+ // SWAP_BUFFERS
+ Index.SWAP_BUFFERS, Index.FRAME_COMPLETED,
+ // TOTAL_DURATION
+ Index.INTENDED_VSYNC, Index.FRAME_COMPLETED,
+ };
+
+ /* package */ final long[] mTimingData;
+
+ /**
+ * Constructs a FrameMetrics object as a copy.
+ * <p>
+ * Use this method to copy out metrics reported by
+ * {@link Window.FrameMetricsListener#onMetricsAvailable(Window, FrameMetrics, int)}
+ * </p>
+ * @param other the FrameMetrics object to copy.
+ */
+ public FrameMetrics(FrameMetrics other) {
+ mTimingData = new long[Index.FRAME_STATS_COUNT];
+ System.arraycopy(other.mTimingData, 0, mTimingData, 0, mTimingData.length);
+ }
+
+ /**
+ * @hide
+ */
+ FrameMetrics() {
+ mTimingData = new long[Index.FRAME_STATS_COUNT];
+ }
+
+ /**
+ * Retrieves the value associated with Metric identifier {@code id}
+ * for this frame.
+ * <p>
+ * Boolean metrics are represented in [0,1], with 0 corresponding to
+ * false, and 1 corresponding to true.
+ * </p>
+ * @param id the metric to retrieve
+ * @return the value of the metric or -1 if it is not available.
+ */
+ public long getMetric(@Metric int id) {
+ if (id < UNKNOWN_DELAY_DURATION || id > FIRST_DRAW_FRAME) {
+ return -1;
+ }
+
+ if (mTimingData == null) {
+ return -1;
+ }
+
+ if (id == FIRST_DRAW_FRAME) {
+ return (mTimingData[Index.FLAGS] & FRAME_INFO_FLAG_FIRST_DRAW) != 0 ? 1 : 0;
+ }
+
+ int durationsIdx = 2 * id;
+ return mTimingData[DURATIONS[durationsIdx + 1]]
+ - mTimingData[DURATIONS[durationsIdx]];
+ }
+}
+
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java
new file mode 100644
index 000000000000..f38f8b76a191
--- /dev/null
+++ b/core/java/android/view/FrameMetricsObserver.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.util.Log;
+import android.os.Looper;
+import android.os.MessageQueue;
+
+import com.android.internal.util.VirtualRefBasePtr;
+
+import java.lang.NullPointerException;
+import java.lang.ref.WeakReference;
+import java.lang.SuppressWarnings;
+
+/**
+ * Provides streaming access to frame stats information from the rendering
+ * subsystem to apps.
+ *
+ * @hide
+ */
+public class FrameMetricsObserver {
+ private MessageQueue mMessageQueue;
+
+ private WeakReference<Window> mWindow;
+
+ private FrameMetrics mFrameMetrics;
+
+ /* package */ Window.FrameMetricsListener mListener;
+ /* package */ VirtualRefBasePtr mNative;
+
+ /**
+ * Creates a FrameMetricsObserver
+ *
+ * @param looper the looper to use when invoking callbacks
+ */
+ FrameMetricsObserver(@NonNull Window window, @NonNull Looper looper,
+ @NonNull Window.FrameMetricsListener listener) {
+ if (looper == null) {
+ throw new NullPointerException("looper cannot be null");
+ }
+
+ mMessageQueue = looper.getQueue();
+ if (mMessageQueue == null) {
+ throw new IllegalStateException("invalid looper, null message queue\n");
+ }
+
+ mFrameMetrics = new FrameMetrics();
+ mWindow = new WeakReference<>(window);
+ mListener = listener;
+ }
+
+ // Called by native on the provided Handler
+ @SuppressWarnings("unused")
+ private void notifyDataAvailable(int dropCount) {
+ final Window window = mWindow.get();
+ if (window != null) {
+ mListener.onMetricsAvailable(window, mFrameMetrics, dropCount);
+ }
+ }
+}
diff --git a/core/java/android/view/FrameStatsObserver.java b/core/java/android/view/FrameStatsObserver.java
deleted file mode 100644
index 0add6072e827..000000000000
--- a/core/java/android/view/FrameStatsObserver.java
+++ /dev/null
@@ -1,122 +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;
-
-import android.annotation.NonNull;
-import android.util.Log;
-import android.os.Looper;
-import android.os.MessageQueue;
-
-import com.android.internal.util.VirtualRefBasePtr;
-
-import java.lang.NullPointerException;
-import java.lang.ref.WeakReference;
-import java.lang.SuppressWarnings;
-
-/**
- * Provides streaming access to frame stats information from the rendering
- * subsystem to apps.
- *
- * @hide
- */
-public abstract class FrameStatsObserver {
- private static final String TAG = "FrameStatsObserver";
-
- private MessageQueue mMessageQueue;
- private long[] mBuffer;
-
- private FrameStats mFrameStats;
-
- /* package */ ThreadedRenderer mRenderer;
- /* package */ VirtualRefBasePtr mNative;
-
- /**
- * Containing class for frame statistics reported
- * by the rendering subsystem.
- */
- public static class FrameStats {
- /**
- * Precise timing data for various milestones in a frame
- * lifecycle.
- *
- * This data is exactly the same as what is returned by
- * `adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats`
- *
- * The fields reported may change from release to release.
- *
- * @see {@link http://developer.android.com/training/testing/performance.html}
- * for a description of the fields present.
- */
- public long[] mTimingData;
- }
-
- /**
- * Creates a FrameStatsObserver
- *
- * @param looper the looper to use when invoking callbacks
- */
- public FrameStatsObserver(@NonNull Looper looper) {
- if (looper == null) {
- throw new NullPointerException("looper cannot be null");
- }
-
- mMessageQueue = looper.getQueue();
- if (mMessageQueue == null) {
- throw new IllegalStateException("invalid looper, null message queue\n");
- }
-
- mFrameStats = new FrameStats();
- }
-
- /**
- * Called on provided looper when frame stats data is available
- * for the previous frame.
- *
- * Clients of this class must do as little work as possible within
- * this callback, as the buffer is shared between the producer and consumer.
- *
- * If the consumer is still executing within this method when there is new
- * data available that data will be dropped. The producer cannot
- * wait on the consumer.
- *
- * @param data the newly available data
- */
- public abstract void onDataAvailable(FrameStats data);
-
- /**
- * Returns the number of reports dropped as a result of a slow
- * consumer.
- */
- public long getDroppedReportCount() {
- if (mRenderer == null) {
- return 0;
- }
-
- return mRenderer.getDroppedFrameReportCount();
- }
-
- public boolean isRegistered() {
- return mRenderer != null && mNative != null;
- }
-
- // === called by native === //
- @SuppressWarnings("unused")
- private void notifyDataAvailable() {
- mFrameStats.mTimingData = mBuffer;
- onDataAvailable(mFrameStats);
- }
-}
diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl
index 77fa7e25f9df..cbc8dbdd1726 100644
--- a/core/java/android/view/IDockedStackListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -33,4 +33,13 @@ oneway interface IDockedStackListener {
* Called when the docked stack gets created or removed.
*/
void onDockedStackExistsChanged(boolean exists);
+
+ /**
+ * Called when window manager decides to minimize the docked stack. The divider should make
+ * itself not interactable and shrink a bit in this state.
+ *
+ * @param minimized Whether the docked stack is currently minimized.
+ * @param animDuration The duration of the animation for changing the minimized state.
+ */
+ void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3688d50d9fe3..70d0513bfbc5 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -49,7 +49,8 @@ oneway interface IWindow {
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
- in Configuration newConfig, in Rect backDropFrame, boolean forceLayout);
+ in Configuration newConfig, in Rect backDropFrame, boolean forceLayout,
+ boolean alwaysConsumeNavBar);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5b9930bb34a7..9543acfba51b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -20,6 +20,7 @@ import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
+import com.android.internal.policy.IShortcutService;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -387,4 +388,11 @@ interface IWindowManager
* Retrieves the current stable insets from the primary display.
*/
void getStableInsets(out Rect outInsets);
+
+ /**
+ * Register shortcut key. Shortcut code is packed as:
+ * (MetaState << Integer.SIZE) | KeyCode
+ * @hide
+ */
+ void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1703ed1810e2..6a2cc802e1f1 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -260,4 +260,6 @@ interface IWindowSession {
* Returns true if the move started successfully; false otherwise.
*/
boolean startMovingTask(IWindow window, float startX, float startY);
+
+ void updatePointerIcon(IWindow window);
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 51e1f4baae97..e0c6770ecb38 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1780,6 +1780,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_SPACE:
+ case KeyEvent.KEYCODE_NUMPAD_ENTER:
return true;
default:
return false;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 7017ff5a3fa0..a45c18d058cb 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -775,7 +775,11 @@ public class RenderNode {
mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
}
- public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimator animatorSet) {
+ public boolean isAttached() {
+ return mOwningView != null && mOwningView.mAttachInfo != null;
+ }
+
+ public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
if (mOwningView == null || mOwningView.mAttachInfo == null) {
throw new IllegalStateException("Cannot start this animator on a detached view!");
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a2960515da08..2c9d691214b0 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -224,7 +224,7 @@ public class SurfaceView extends View {
mParent.requestTransparentRegion(this);
mSession = getWindowSession();
mLayout.token = getWindowToken();
- mLayout.setTitle("SurfaceView");
+ mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
mViewVisibility = getVisibility() == VISIBLE;
if (!mGlobalListenersAdded) {
@@ -743,7 +743,8 @@ public class SurfaceView extends View {
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect, boolean forceLayout) {
+ Configuration newConfig, Rect backDropRect, boolean forceLayout,
+ boolean alwaysConsumeNavBar) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
if (DEBUG) Log.v(
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 8b06ecf3bc8b..c97247656540 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -354,8 +354,6 @@ public final class ThreadedRenderer {
private boolean mEnabled;
private boolean mRequested = true;
- private HashSet<FrameStatsObserver> mFrameStatsObservers;
-
ThreadedRenderer(Context context, boolean translucent) {
final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
@@ -382,7 +380,7 @@ public final class ThreadedRenderer {
void destroy() {
mInitialized = false;
updateEnabledState(null);
- nDestroy(mNativeProxy);
+ nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
}
/**
@@ -964,29 +962,14 @@ public final class ThreadedRenderer {
}
}
- void addFrameStatsObserver(FrameStatsObserver fso) {
- if (mFrameStatsObservers == null) {
- mFrameStatsObservers = new HashSet<>();
- }
-
- long nativeFso = nAddFrameStatsObserver(mNativeProxy, fso);
- fso.mRenderer = this;
- fso.mNative = new VirtualRefBasePtr(nativeFso);
- mFrameStatsObservers.add(fso);
- }
-
- void removeFrameStatsObserver(FrameStatsObserver fso) {
- if (!mFrameStatsObservers.remove(fso)) {
- throw new IllegalArgumentException("attempt to remove FrameStatsObserver that was never added");
- }
-
- nRemoveFrameStatsObserver(mNativeProxy, fso.mNative.get());
- fso.mRenderer = null;
- fso.mNative = null;
+ void addFrameMetricsObserver(FrameMetricsObserver observer) {
+ long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
+ observer.mNative = new VirtualRefBasePtr(nativeObserver);
}
- long getDroppedFrameReportCount() {
- return nGetDroppedFrameReportCount(mNativeProxy);
+ void removeFrameMetricsObserver(FrameMetricsObserver observer) {
+ nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
+ observer.mNative = null;
}
static native void setupShadersDiskCache(String cacheFile);
@@ -1011,7 +994,7 @@ public final class ThreadedRenderer {
float lightX, float lightY, float lightZ);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
- private static native void nDestroy(long nativeProxy);
+ private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
@@ -1044,7 +1027,6 @@ public final class ThreadedRenderer {
private static native void nSetContentDrawBounds(long nativeProxy, int left,
int top, int right, int bottom);
- private static native long nAddFrameStatsObserver(long nativeProxy, FrameStatsObserver fso);
- private static native void nRemoveFrameStatsObserver(long nativeProxy, long nativeFso);
- private static native long nGetDroppedFrameReportCount(long nativeProxy);
+ private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
+ private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f52b29077f27..e7be7af48a7b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3703,9 +3703,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private ViewPropertyAnimator mAnimator = null;
/**
- * List of FrameStatsObservers pending registration when mAttachInfo is null.
+ * List of registered FrameMetricsObservers.
*/
- private ArrayList<FrameStatsObserver> mPendingFrameStatsObservers;
+ private ArrayList<FrameMetricsObserver> mFrameMetricsObservers;
/**
* Flag indicating that a drag can cross window boundaries. When
@@ -5479,19 +5479,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide
*/
- public void addFrameStatsObserver(FrameStatsObserver fso) {
+ public void addFrameMetricsListener(Window window, Window.FrameMetricsListener listener,
+ Handler handler) {
if (mAttachInfo != null) {
if (mAttachInfo.mHardwareRenderer != null) {
- mAttachInfo.mHardwareRenderer.addFrameStatsObserver(fso);
+ if (mFrameMetricsObservers == null) {
+ mFrameMetricsObservers = new ArrayList<>();
+ }
+
+ FrameMetricsObserver fmo = new FrameMetricsObserver(window,
+ handler.getLooper(), listener);
+ mFrameMetricsObservers.add(fmo);
+ mAttachInfo.mHardwareRenderer.addFrameMetricsObserver(fmo);
} else {
Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
}
} else {
- if (mPendingFrameStatsObservers == null) {
- mPendingFrameStatsObservers = new ArrayList<>();
+ if (mFrameMetricsObservers == null) {
+ mFrameMetricsObservers = new ArrayList<>();
}
- mPendingFrameStatsObservers.add(fso);
+ FrameMetricsObserver fmo = new FrameMetricsObserver(window,
+ handler.getLooper(), listener);
+ mFrameMetricsObservers.add(fmo);
}
}
@@ -5500,32 +5510,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide
*/
- public void removeFrameStatsObserver(FrameStatsObserver fso) {
+ public void removeFrameMetricsListener(Window.FrameMetricsListener listener) {
ThreadedRenderer renderer = getHardwareRenderer();
-
- if (mPendingFrameStatsObservers != null) {
- mPendingFrameStatsObservers.remove(fso);
+ FrameMetricsObserver fmo = findFrameMetricsObserver(listener);
+ if (fmo == null) {
+ throw new IllegalArgumentException("attempt to remove FrameMetricsListener that was never added");
}
- if (renderer != null) {
- renderer.removeFrameStatsObserver(fso);
+ if (mFrameMetricsObservers != null) {
+ mFrameMetricsObservers.remove(fmo);
+ if (renderer != null) {
+ renderer.removeFrameMetricsObserver(fmo);
+ }
}
}
- private void registerPendingFrameStatsObservers() {
- if (mPendingFrameStatsObservers != null) {
+ private void registerPendingFrameMetricsObservers() {
+ if (mFrameMetricsObservers != null) {
ThreadedRenderer renderer = getHardwareRenderer();
if (renderer != null) {
- for (FrameStatsObserver fso : mPendingFrameStatsObservers) {
- renderer.addFrameStatsObserver(fso);
+ for (FrameMetricsObserver fmo : mFrameMetricsObservers) {
+ renderer.addFrameMetricsObserver(fmo);
}
} else {
Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
}
- mPendingFrameStatsObservers = null;
}
}
+ private FrameMetricsObserver findFrameMetricsObserver(Window.FrameMetricsListener listener) {
+ for (int i = 0; i < mFrameMetricsObservers.size(); i++) {
+ FrameMetricsObserver observer = mFrameMetricsObservers.get(i);
+ if (observer.mListener == listener) {
+ return observer;
+ }
+ }
+
+ return null;
+ }
+
/**
* Call this view's OnClickListener, if it is defined. Performs all normal
* actions associated with clicking: reporting accessibility event, playing
@@ -6851,6 +6874,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param info The info whose drawing order should be populated
*/
private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) {
+ /*
+ * If the view's bounds haven't been set yet, layout has not completed. In that situation,
+ * drawing order may not be well-defined, and some Views with custom drawing order may
+ * not be initialized sufficiently to respond properly getChildDrawingOrder.
+ */
+ if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) {
+ info.setDrawingOrder(0);
+ return;
+ }
int drawingOrderInParent = 1;
// Iterate up the hierarchy if parents are not important for a11y
View viewAtDrawingLevel = this;
@@ -10871,6 +10903,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return true;
}
case MotionEvent.ACTION_DOWN:
+ if (mScrollCache.state == ScrollabilityCache.OFF) {
+ return false;
+ }
if (isOnVerticalScrollbarThumb(x, y)) {
mScrollCache.mScrollBarDraggingState =
ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR;
@@ -15160,7 +15195,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mFloatingTreeObserver = null;
}
- registerPendingFrameStatsObservers();
+ registerPendingFrameMetricsObservers();
if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) {
mAttachInfo.mScrollContainers.add(this);
@@ -18881,7 +18916,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
transformFromViewToWindowSpace(outLocation);
}
- void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) {
+ /** @hide */
+ public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) {
if (inOutLocation == null || inOutLocation.length < 2) {
throw new IllegalArgumentException("inOutLocation must be an array of two integers");
}
@@ -21549,6 +21585,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setPointerIcon(PointerIcon pointerIcon) {
mPointerIcon = pointerIcon;
+ if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) {
+ return;
+ }
+ try {
+ mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow);
+ } catch (RemoteException e) {
+ }
}
/**
@@ -22475,6 +22518,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final Rect mOutsets = new Rect();
/**
+ * In multi-window we force show the navigation bar. Because we don't want that the surface
+ * size changes in this mode, we instead have a flag whether the navigation bar size should
+ * always be consumed, so the app is treated like there is no virtual navigation bar at all.
+ */
+ boolean mAlwaysConsumeNavBar;
+
+ /**
* The internal insets given by this window. This value is
* supplied by the client (through
* {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
@@ -22595,6 +22645,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mHighContrastText;
/**
+ * Set to true if a pointer event is currently being handled.
+ */
+ boolean mHandlingPointerEvent;
+
+ /**
* Global to the view hierarchy used as a temporary for dealing with
* x/y points in the transparent region computations.
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 96853e0fa775..afe2f1061f3a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -313,6 +313,7 @@ public final class ViewRootImpl implements ViewParent,
final Rect mPendingContentInsets = new Rect();
final Rect mPendingOutsets = new Rect();
final Rect mPendingBackDropFrame = new Rect();
+ boolean mPendingAlwaysConsumeNavBar;
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
@@ -623,6 +624,9 @@ public final class ViewRootImpl implements ViewParent,
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
+ mAttachInfo.mAlwaysConsumeNavBar =
+ (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
+ mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
@@ -1072,6 +1076,13 @@ public final class ViewRootImpl implements ViewParent,
mStopped = stopped;
if (!mStopped) {
scheduleTraversals();
+ } else {
+ if (mAttachInfo.mHardwareRenderer != null) {
+ // TODO: Temporary to help track down b/27286867
+ Log.d(mTag, "WindowStopped on " + getTitle());
+ mAttachInfo.mHardwareRenderer.updateSurface(null);
+ mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
+ }
}
}
}
@@ -1343,7 +1354,8 @@ public final class ViewRootImpl implements ViewParent,
}
mLastWindowInsets = new WindowInsets(contentInsets,
null /* windowDecorInsets */, stableInsets,
- mContext.getResources().getConfiguration().isScreenRound());
+ mContext.getResources().getConfiguration().isScreenRound(),
+ mAttachInfo.mAlwaysConsumeNavBar);
}
return mLastWindowInsets;
}
@@ -1510,6 +1522,9 @@ public final class ViewRootImpl implements ViewParent,
if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
insetsChanged = true;
}
+ if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
+ insetsChanged = true;
+ }
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
windowSizeMayChange = true;
@@ -1606,10 +1621,6 @@ public final class ViewRootImpl implements ViewParent,
frame.height() < desiredWindowHeight && frame.height() != mHeight));
windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
- // If the backdrop frame doesn't equal to a frame, we are starting a resize operation, so
- // force it to be resized.
- windowShouldResize |= !mPendingBackDropFrame.equals(mWinFrame);
-
// If the activity was just relaunched, it might have unfrozen the task bounds (while
// relaunching), so we need to force a call into window manager to pick up the latest
// bounds.
@@ -1698,6 +1709,8 @@ public final class ViewRootImpl implements ViewParent,
final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
final boolean surfaceSizeChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
+ final boolean alwaysConsumeNavBarChanged =
+ mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar;
if (contentInsetsChanged) {
mAttachInfo.mContentInsets.set(mPendingContentInsets);
if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
@@ -1717,6 +1730,10 @@ public final class ViewRootImpl implements ViewParent,
// Need to relayout with content insets.
contentInsetsChanged = true;
}
+ if (alwaysConsumeNavBarChanged) {
+ mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar;
+ contentInsetsChanged = true;
+ }
if (contentInsetsChanged || mLastSystemUiVisibility !=
mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
|| mLastOverscanRequested != mAttachInfo.mOverscanRequested
@@ -1970,7 +1987,7 @@ public final class ViewRootImpl implements ViewParent,
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
- performLayout(lp, desiredWindowWidth, desiredWindowHeight);
+ performLayout(lp, mWidth, mHeight);
// By this point all views have been sized and positioned
// We can compute the transparent area
@@ -3393,6 +3410,7 @@ public final class ViewRootImpl implements ViewParent,
mPendingOutsets.set((Rect) args.arg7);
mPendingBackDropFrame.set((Rect) args.arg8);
mForceNextWindowRelayout = args.argi1 != 0;
+ mPendingAlwaysConsumeNavBar = args.argi2 != 0;
args.recycle();
@@ -3801,7 +3819,8 @@ public final class ViewRootImpl implements ViewParent,
return true;
} else if ((!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
- || mIsAmbientMode || (mPausedForTransition && !isBack(q.mEvent))) {
+ || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
+ || (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
// has stopped. This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
@@ -4315,6 +4334,24 @@ public final class ViewRootImpl implements ViewParent,
private int processPointerEvent(QueuedInputEvent q) {
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);
+ maybeUpdatePointerIcon(event);
+ mAttachInfo.mHandlingPointerEvent = false;
+ if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
+ mUnbufferedInputDispatch = true;
+ if (mConsumeBatchedInputScheduled) {
+ scheduleConsumeBatchedInputImmediately();
+ }
+ }
+ return handled ? FINISH_HANDLED : FORWARD;
+ }
+
+ private void maybeUpdatePointerIcon(MotionEvent event) {
if (event.getPointerCount() == 1
&& event.isFromSource(InputDevice.SOURCE_MOUSE)) {
if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
@@ -4331,19 +4368,6 @@ public final class ViewRootImpl implements ViewParent,
}
}
}
-
- mAttachInfo.mUnbufferedDispatchRequested = false;
- final View eventTarget =
- (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
- mCapturingView : mView;
- boolean handled = eventTarget.dispatchPointerEvent(event);
- if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
- mUnbufferedInputDispatch = true;
- if (mConsumeBatchedInputScheduled) {
- scheduleConsumeBatchedInputImmediately();
- }
- }
- return handled ? FINISH_HANDLED : FORWARD;
}
private int processTrackballEvent(QueuedInputEvent q) {
@@ -4374,8 +4398,14 @@ public final class ViewRootImpl implements ViewParent,
private boolean updatePointerIcon(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
+ if (mView == null) {
+ // E.g. click outside a popup to dismiss it
+ Slog.d(mTag, "updatePointerIcon called after view was removed");
+ return false;
+ }
if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
- Slog.e(mTag, "updatePointerIcon called with position out of bounds");
+ // E.g. when moving window divider with mouse
+ Slog.d(mTag, "updatePointerIcon called with position out of bounds");
return false;
}
final PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
@@ -5566,6 +5596,10 @@ public final class ViewRootImpl implements ViewParent,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
mSurface);
+
+ mPendingAlwaysConsumeNavBar =
+ (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
+
//Log.d(mTag, "<<<<<< BACK FROM relayout");
if (restore) {
params.restore();
@@ -5837,7 +5871,8 @@ public final class ViewRootImpl implements ViewParent,
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
+ Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+ boolean alwaysConsumeNavBar) {
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -5874,6 +5909,7 @@ public final class ViewRootImpl implements ViewParent,
args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
args.argi1 = forceLayout ? 1 : 0;
+ args.argi2 = alwaysConsumeNavBar ? 1 : 0;
msg.obj = args;
mHandler.sendMessage(msg);
}
@@ -6875,12 +6911,13 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
+ Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+ boolean alwaysConsumeNavBar) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
- forceLayout);
+ forceLayout, alwaysConsumeNavBar);
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index c68a740b29a5..9f05990fd781 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -34,6 +34,7 @@ import android.graphics.drawable.Drawable;
import android.media.session.MediaController;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -604,6 +605,34 @@ public abstract class Window {
void onRestrictedCaptionAreaChanged(Rect rect);
}
+ /**
+ * Callback for clients that want frame timing information for each
+ * frame rendered by the Window.
+ */
+ public interface FrameMetricsListener {
+ /**
+ * Called when information is available for the previously rendered frame.
+ *
+ * Reports can be dropped if this callback takes too
+ * long to execute, as the report producer cannot wait for the consumer to
+ * complete.
+ *
+ * It is highly recommended that clients copy the passed in FrameMetrics
+ * via {@link FrameMetrics#FrameMetrics(FrameMetrics)} within this method and defer
+ * additional computation or storage to another thread to avoid unnecessarily
+ * dropping reports.
+ *
+ * @param window The {@link Window} on which the frame was displayed.
+ * @param frameMetrics the available metrics. This object is reused on every call
+ * and thus <strong>this reference is not valid outside the scope of this method</strong>.
+ * @param dropCountSinceLastInvocation the number of reports dropped since the last time
+ * this callback was invoked.
+ */
+ void onMetricsAvailable(Window window, FrameMetrics frameMetrics,
+ int dropCountSinceLastInvocation);
+ }
+
+
public Window(Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
@@ -798,33 +827,28 @@ public abstract class Window {
* Set an observer to collect frame stats for each frame rendererd in this window.
*
* Must be in hardware rendering mode.
- * @hide
*/
- public final void addFrameStatsObserver(@NonNull FrameStatsObserver fso) {
+ public final void addFrameMetricsListener(@NonNull FrameMetricsListener listener,
+ Handler handler) {
final View decorView = getDecorView();
if (decorView == null) {
throw new IllegalStateException("can't observe a Window without an attached view");
}
- if (fso == null) {
- throw new NullPointerException("FrameStatsObserver cannot be null");
+ if (listener == null) {
+ throw new NullPointerException("listener cannot be null");
}
- if (fso.isRegistered()) {
- throw new IllegalStateException("FrameStatsObserver already registered on a Window.");
- }
-
- decorView.addFrameStatsObserver(fso);
+ decorView.addFrameMetricsListener(this, listener, handler);
}
/**
* Remove observer and stop listening to frame stats for this window.
- * @hide
*/
- public final void removeFrameStatsObserver(FrameStatsObserver fso) {
+ public final void removeFrameMetricsListener(FrameMetricsListener listener) {
final View decorView = getDecorView();
if (decorView != null) {
- getDecorView().removeFrameStatsObserver(fso);
+ getDecorView().removeFrameMetricsListener(listener);
}
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 997e7e8a16f0..929fdac82c28 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -37,6 +37,13 @@ public final class WindowInsets {
private Rect mTempRect;
private boolean mIsRound;
+ /**
+ * In multi-window we force show the navigation bar. Because we don't want that the surface size
+ * changes in this mode, we instead have a flag whether the navigation bar size should always
+ * be consumed, so the app is treated like there is no virtual navigation bar at all.
+ */
+ private boolean mAlwaysConsumeNavBar;
+
private boolean mSystemWindowInsetsConsumed = false;
private boolean mWindowDecorInsetsConsumed = false;
private boolean mStableInsetsConsumed = false;
@@ -52,12 +59,12 @@ public final class WindowInsets {
public static final WindowInsets CONSUMED;
static {
- CONSUMED = new WindowInsets(null, null, null, false);
+ CONSUMED = new WindowInsets(null, null, null, false, false);
}
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
- boolean isRound) {
+ boolean isRound, boolean alwaysConsumeNavBar) {
mSystemWindowInsetsConsumed = systemWindowInsets == null;
mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
@@ -68,6 +75,7 @@ public final class WindowInsets {
mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : stableInsets;
mIsRound = isRound;
+ mAlwaysConsumeNavBar = alwaysConsumeNavBar;
}
/**
@@ -87,7 +95,7 @@ public final class WindowInsets {
/** @hide */
public WindowInsets(Rect systemWindowInsets) {
- this(systemWindowInsets, null, null, false);
+ this(systemWindowInsets, null, null, false, false);
}
/**
@@ -475,6 +483,13 @@ public final class WindowInsets {
return result;
}
+ /**
+ * @hide
+ */
+ public boolean shouldAlwaysConsumeNavBar() {
+ return mAlwaysConsumeNavBar;
+ }
+
@Override
public String toString() {
return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0c5a5fc4bd45..6e025161f4ce 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -30,7 +30,7 @@ import android.text.TextUtils;
import android.util.Log;
import java.util.List;
-
+import java.util.Objects;
/**
* The interface that apps use to talk to the window manager.
@@ -1724,7 +1724,7 @@ public interface WindowManager extends ViewManager {
}
public final CharSequence getTitle() {
- return mTitle;
+ return mTitle != null ? mTitle : "";
}
/** @hide */
@@ -1950,7 +1950,8 @@ public interface WindowManager extends ViewManager {
// already have one.
packageName = o.packageName;
}
- if (!mTitle.equals(o.mTitle)) {
+ if (!Objects.equals(mTitle, o.mTitle) && o.mTitle != null) {
+ // NOTE: mTitle only copied if the originator set one.
mTitle = o.mTitle;
changes |= TITLE_CHANGED;
}
@@ -2194,7 +2195,7 @@ public interface WindowManager extends ViewManager {
}
}
- private CharSequence mTitle = "";
+ private CharSequence mTitle = null;
/** @hide */
@Override
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 1530b474c534..a1cbc1d07575 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -90,6 +90,13 @@ public final class WindowManagerGlobal {
public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
/**
+ * In multi-window we force show the navigation bar. Because we don't want that the surface size
+ * changes in this mode, we instead have a flag whether the navigation bar size should always be
+ * consumed, so the app is treated like there is no virtual navigation bar at all.
+ */
+ public static final int RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR = 0x40;
+
+ /**
* Flag for relayout: the client will be later giving
* internal insets; as a result, the window will not impact other window
* layouts until the insets are given.
@@ -107,6 +114,11 @@ public final class WindowManagerGlobal {
public static final int ADD_FLAG_APP_VISIBLE = 0x2;
public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
+ /**
+ * Like {@link #RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR}, but as a "hint" when adding the window.
+ */
+ public static final int ADD_FLAG_ALWAYS_CONSUME_NAV_BAR = 0x4;
+
public static final int ADD_OKAY = 0;
public static final int ADD_BAD_APP_TOKEN = -1;
public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 947906bf4403..b011414bc556 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.SystemApi;
+import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
@@ -28,7 +29,9 @@ import android.graphics.RectF;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.view.animation.Animation;
+import com.android.internal.policy.IShortcutService;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -120,6 +123,14 @@ public interface WindowManagerPolicy {
public final static int ACTION_PASS_TO_USER = 0x00000001;
/**
+ * Register shortcuts for window manager to dispatch.
+ * Shortcut code is packed as (metaState << Integer.SIZE) | keyCode
+ * @hide
+ */
+ void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
+ throws RemoteException;
+
+ /**
* Interface to the Window Manager state associated with a particular
* window. You can hold on to an instance of this interface from the call
* to prepareAddWindow() until removeWindow().
@@ -388,6 +399,12 @@ public interface WindowManagerPolicy {
* Check whether the window is currently dimming.
*/
public boolean isDimming();
+
+ /**
+ * @return the stack id this windows belongs to, or {@link StackId#INVALID_STACK_ID} if
+ * not attached to any stack.
+ */
+ int getStackId();
}
/**
@@ -465,6 +482,11 @@ public interface WindowManagerPolicy {
* @return The content insets of the docked divider window.
*/
int getDockedDividerInsetsLw();
+
+ /**
+ * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
+ */
+ void getStackBounds(int stackId, Rect outBounds);
}
public interface PointerEventListener {
@@ -619,7 +641,7 @@ public interface WindowManagerPolicy {
/**
* Return the display width available after excluding any screen
- * decorations that can never be removed. That is, system bar or
+ * decorations that could never be removed in Honeycomb. That is, system bar or
* button bar.
*/
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
@@ -627,7 +649,7 @@ public interface WindowManagerPolicy {
/**
* Return the display height available after excluding any screen
- * decorations that can never be removed. That is, system bar or
+ * decorations that could never be removed in Honeycomb. That is, system bar or
* button bar.
*/
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
@@ -908,9 +930,10 @@ public interface WindowManagerPolicy {
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
* @param outOutsets The areas that are not real display, but we would like to treat as such.
- *
+ * @return Whether to always consume the navigation bar.
+ * See {@link #isNavBarForcedShownLw(WindowState)}.
*/
- public void getInsetHintLw(WindowManager.LayoutParams attrs, int rotation,
+ public boolean getInsetHintLw(WindowManager.LayoutParams attrs, int rotation,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets);
/**
@@ -1338,4 +1361,29 @@ public interface WindowManagerPolicy {
*/
public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
Rect outInsets);
+
+
+ /**
+ * @return true if the navigation bar is forced to stay visible
+ */
+ public boolean isNavBarForcedShownLw(WindowState win);
+
+ /**
+ * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
+ * bar or button bar. See {@link #getNonDecorDisplayWidth}.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param outInsets the insets to return
+ */
+ public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+ Rect outInsets);
+
+ /**
+ * @return True if a specified {@param dockSide} is allowed on the current device, or false
+ * otherwise. It is guaranteed that at least one dock side for a particular orientation
+ * is allowed, so for example, if DOCKED_RIGHT is not allowed, DOCKED_LEFT is allowed.
+ */
+ public boolean isDockSideAllowed(int dockSide);
}
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index a75e8a73c145..ad78b686b8de 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -64,6 +64,12 @@ public final class AccessibilityWindowInfo implements Parcelable {
*/
public static final int TYPE_ACCESSIBILITY_OVERLAY = 4;
+ /**
+ * Window type: A system window used to divide the screen in split-screen mode.
+ * This type of window is present only in split-screen mode.
+ */
+ public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5;
+
private static final int UNDEFINED = -1;
private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0;
@@ -551,6 +557,9 @@ public final class AccessibilityWindowInfo implements Parcelable {
case TYPE_ACCESSIBILITY_OVERLAY: {
return "TYPE_ACCESSIBILITY_OVERLAY";
}
+ case TYPE_SPLIT_SCREEN_DIVIDER: {
+ return "TYPE_SPLIT_SCREEN_DIVIDER";
+ }
default:
return "<UNKNOWN>";
}
diff --git a/core/java/android/view/animation/ClipRectTBAnimation.java b/core/java/android/view/animation/ClipRectTBAnimation.java
deleted file mode 100644
index 06f86ceda82f..000000000000
--- a/core/java/android/view/animation/ClipRectTBAnimation.java
+++ /dev/null
@@ -1,49 +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 android.view.animation;
-
-import android.graphics.Rect;
-
-/**
- * Special case of ClipRectAnimation that animates only the top/bottom
- * dimensions of the clip, picking up the other dimensions from whatever is
- * set on the transform already.
- *
- * @hide
- */
-public class ClipRectTBAnimation extends ClipRectAnimation {
-
- /**
- * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation
- */
- public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB) {
- super(0, fromT, 0, fromB, 0, toT, 0, toB);
- }
-
- /**
- * Calculates and sets clip rect on given transformation. It uses existing values
- * on the Transformation for Left/Right clip parameters.
- */
- @Override
- protected void applyTransformation(float it, Transformation tr) {
- Rect oldClipRect = tr.getClipRect();
- tr.setClipRect(oldClipRect.left, mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it),
- oldClipRect.right,
- mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it));
- }
-
-}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a10f792b006b..6a830f87de1f 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -19,6 +19,7 @@ package android.view.inputmethod;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
+import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
import android.text.NoCopySpan;
@@ -602,6 +603,10 @@ public class BaseInputConnection implements InputConnection {
return false;
}
+ public Handler getHandler() {
+ return null;
+ }
+
/**
* The default implementation places the given text into the editable,
* replacing any existing composing text. The new text is marked as
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index eb773e23fa62..2a9706dc87d5 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.os.Bundle;
+import android.os.Handler;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -786,4 +787,15 @@ public interface InputConnection {
* {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}.
*/
public boolean requestCursorUpdates(int cursorUpdateMode);
+
+ /**
+ * Called by the {@link InputMethodManager} to enable application developers to specify a
+ * dedicated {@link Handler} on which incoming IPC method calls from input methods will be
+ * dispatched.
+ *
+ * <p>Note: This does nothing when called from input methods.</p>
+ *
+ * @return {@code null} to use the default {@link Handler}.
+ */
+ public Handler getHandler();
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index e5ae42299dba..65c7654c671b 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.os.Bundle;
+import android.os.Handler;
import android.view.KeyEvent;
/**
@@ -133,4 +134,8 @@ public class InputConnectionWrapper implements InputConnection {
public boolean requestCursorUpdates(int cursorUpdateMode) {
return mTarget.requestCursorUpdates(cursorUpdateMode);
}
+
+ public Handler getHandler() {
+ return mTarget.getHandler();
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 43306d094bda..281babeb367a 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -38,7 +38,6 @@ import android.util.Printer;
import android.util.Slog;
import android.util.Xml;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
-import android.view.inputmethod.InputMethodSubtypeArray;
import java.io.IOException;
import java.util.ArrayList;
@@ -122,7 +121,7 @@ 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 additionalSubtypes additional subtypes being added to this InputMethodInfo
+ * @param additionalSubtypesMap additional subtypes being added to this InputMethodInfo
* @hide
*/
public InputMethodInfo(Context context, ResolveInfo service,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0ed22994585b..4c015ba9e2d3 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1215,7 +1215,7 @@ public final class InputMethodManager {
if (mCurrentTextBoxAttribute == null) {
controlFlags |= CONTROL_START_INITIAL;
}
-
+
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
@@ -1230,7 +1230,9 @@ public final class InputMethodManager {
mCursorCandEnd = -1;
mCursorRect.setEmpty();
mCursorAnchorInfo = null;
- servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this);
+ final Handler icHandler = ic.getHandler();
+ servedContext = new ControlledInputConnectionWrapper(
+ icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
} else {
servedContext = null;
}
@@ -1238,20 +1240,14 @@ public final class InputMethodManager {
mServedInputConnectionWrapper.deactivate();
}
mServedInputConnectionWrapper = servedContext;
-
+
try {
if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
+ ic + " tba=" + tba + " controlFlags=#"
+ Integer.toHexString(controlFlags));
- InputBindResult res;
- if (windowGainingFocus != null) {
- res = mService.windowGainedFocus(startInputReason, mClient, windowGainingFocus,
- controlFlags, softInputMode, windowFlags,
- tba, servedContext);
- } else {
- res = mService.startInput(startInputReason, mClient,
- servedContext, tba, controlFlags);
- }
+ final InputBindResult res = mService.startInputOrWindowGainedFocus(
+ startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
+ windowFlags, tba, servedContext);
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
if (res != null) {
if (res.id != null) {
@@ -1469,13 +1465,13 @@ public final class InputMethodManager {
return;
}
}
-
+
// For some reason we didn't do a startInput + windowFocusGain, so
// we'll just do a window focus gain and call it a day.
synchronized (mH) {
try {
if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
- mService.windowGainedFocus(
+ mService.startInputOrWindowGainedFocus(
InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
null);
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index 89d5d69de392..5697dfc0188c 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -38,10 +38,14 @@ interface IWebViewUpdateService {
WebViewProviderResponse waitForAndGetProvider();
/**
- * DevelopmentSettings uses this to notify WebViewUpdateService that a
- * new provider has been selected by the user.
+ * DevelopmentSettings uses this to notify WebViewUpdateService that a new provider has been
+ * selected by the user. Returns the provider we end up switching to, this could be different to
+ * the one passed as argument to this method since the Dev Setting calling this method could be
+ * stale. I.e. the Dev setting could be letting the user choose uninstalled/disabled packages,
+ * it would then try to update the provider to such a package while in reality the update
+ * service would switch to another one.
*/
- void changeProviderAndSetting(String newProvider);
+ String changeProviderAndSetting(String newProvider);
/**
* DevelopmentSettings uses this to get the current available WebView
@@ -53,4 +57,15 @@ interface IWebViewUpdateService {
* Used by DevelopmentSetting to get the name of the WebView provider currently in use.
*/
String getCurrentWebViewPackageName();
+
+ /**
+ * Used by Settings to determine whether a certain package can be enabled/disabled by the user -
+ * the package should not be modifiable in this way if it is a fallback package.
+ */
+ boolean isFallbackPackage(String packageName);
+
+ /**
+ * Enable or disable the WebView package fallback mechanism.
+ */
+ void enableFallbackLogic(boolean enable);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 0f58ba3c002c..2eb258fb6683 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -39,6 +39,7 @@ import android.print.PrintDocumentAdapter;
import android.security.KeyChain;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -287,11 +288,11 @@ import java.util.Map;
* helps Google improve WebView. Data is collected on a per-app basis for each app which has
* instantiated a WebView. An individual app can opt out of this feature by putting the following
* tag in its manifest:
- * </p>
* <pre>
- * <meta-data android:name="android.webkit.WebView.MetricsOptOut"
- * android:value="true" />
+ * &lt;meta-data android:name="android.webkit.WebView.MetricsOptOut"
+ * android:value="true" /&gt;
* </pre>
+ * </p>
* <p>
* Data will only be uploaded for a given app if the user has consented AND the app has not opted
* out.
@@ -2528,6 +2529,11 @@ public class WebView extends AbsoluteLayout
}
@Override
+ public boolean onDragEvent(DragEvent event) {
+ return mProvider.getViewDelegate().onDragEvent(event);
+ }
+
+ @Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
// This method may be called in the constructor chain, before the WebView provider is
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 0e5034de7f4f..8318656342d7 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -332,7 +332,9 @@ public class WebViewClient {
* in memory (for the life of the application) if proceed() or cancel() is
* called and does not call onReceivedClientCertRequest() again for the
* same host and port pair. Webview does not store the response if ignore()
- * is called.
+ * is called. Note that, multiple layers in chromium network stack might be
+ * caching the responses, so the behavior for ignore is only a best case
+ * effort.
*
* This method is called on the UI thread. During the callback, the
* connection is suspended.
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 23af384e9165..94dc03cad23b 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -156,7 +156,7 @@ public final class WebViewDelegate {
* Adds the WebView asset path to {@link android.content.res.AssetManager}.
*/
public void addWebViewAssetPath(Context context) {
- context.getAssets().addAssetPath(
+ context.getAssets().addAssetPathAsSharedLibrary(
WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir);
}
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index b04b4c0e3b11..ad50ff60780e 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -21,6 +21,7 @@ import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -134,6 +135,7 @@ public final class WebViewFactory {
// Whether or not the provider must be explicitly chosen by the user to be used.
private static String TAG_AVAILABILITY = "availableByDefault";
private static String TAG_SIGNATURE = "signature";
+ private static String TAG_FALLBACK = "isFallback";
/**
* Reads all signatures at the current depth (within the current provider) from the XML parser.
@@ -159,6 +161,7 @@ public final class WebViewFactory {
* @hide
* */
public static WebViewProviderInfo[] getWebViewPackages() {
+ int numFallbackPackages = 0;
XmlResourceParser parser = null;
List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
try {
@@ -182,13 +185,21 @@ public final class WebViewFactory {
throw new MissingWebViewPackageException(
"WebView provider in framework resources missing description");
}
- String availableByDefault = parser.getAttributeValue(null, TAG_AVAILABILITY);
- if (availableByDefault == null) {
- availableByDefault = "false";
- }
- webViewProviders.add(
+ boolean availableByDefault = "true".equals(
+ parser.getAttributeValue(null, TAG_AVAILABILITY));
+ boolean isFallback = "true".equals(
+ parser.getAttributeValue(null, TAG_FALLBACK));
+ WebViewProviderInfo currentProvider =
new WebViewProviderInfo(packageName, description, availableByDefault,
- readSignatures(parser)));
+ isFallback, readSignatures(parser));
+ if (currentProvider.isFallbackPackage()) {
+ numFallbackPackages++;
+ if (numFallbackPackages > 1) {
+ throw new AndroidRuntimeException(
+ "There can be at most one webview fallback package.");
+ }
+ }
+ webViewProviders.add(currentProvider);
}
else {
Log.e(LOGTAG, "Found an element that is not a webview provider");
@@ -641,6 +652,18 @@ public final class WebViewFactory {
return result;
}
+ /**
+ * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
+ * than just one of its components).
+ * @hide
+ */
+ public static boolean entirePackageChanged(Intent intent) {
+ String[] componentList =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ return Arrays.asList(componentList).contains(
+ intent.getDataString().substring("package:".length()));
+ }
+
private static IWebViewUpdateService getUpdateService() {
return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
}
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 3ce034cf24cb..94d231c45b98 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -30,6 +30,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.print.PrintDocumentAdapter;
+import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -334,6 +335,8 @@ public interface WebViewProvider {
public InputConnection onCreateInputConnection(EditorInfo outAttrs);
+ public boolean onDragEvent(DragEvent event);
+
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event);
public boolean onKeyDown(int keyCode, KeyEvent event);
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 3f50fe2e376c..64c2caa58fd5 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -40,11 +40,12 @@ public class WebViewProviderInfo implements Parcelable {
public WebViewPackageNotFoundException(Exception e) { super(e); }
}
- public WebViewProviderInfo(String packageName, String description, String availableByDefault,
- String[] signatures) {
+ public WebViewProviderInfo(String packageName, String description, boolean availableByDefault,
+ boolean isFallback, String[] signatures) {
this.packageName = packageName;
this.description = description;
- this.availableByDefault = availableByDefault.equals("true");
+ this.availableByDefault = availableByDefault;
+ this.isFallback = isFallback;
this.signatures = signatures;
}
@@ -97,22 +98,12 @@ public class WebViewProviderInfo implements Parcelable {
*/
public boolean isEnabled() {
try {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- int enabled_state = pm.getApplicationEnabledSetting(packageName);
- switch (enabled_state) {
- case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
- return true;
- case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
- ApplicationInfo applicationInfo = getPackageInfo().applicationInfo;
- return applicationInfo.enabled;
- default:
- return false;
- }
+ // Explicitly fetch up-to-date package info here since the enabled-state of the package
+ // might have changed since we last fetched its package info.
+ updatePackageInfo();
+ return getPackageInfo().applicationInfo.enabled;
} catch (WebViewPackageNotFoundException e) {
return false;
- } catch (IllegalArgumentException e) {
- // Thrown by PackageManager.getApplicationEnabledSetting if the package does not exist
- return false;
}
}
@@ -124,14 +115,22 @@ public class WebViewProviderInfo implements Parcelable {
return availableByDefault;
}
+ public boolean isFallbackPackage() {
+ return isFallback;
+ }
+
+ private void updatePackageInfo() {
+ try {
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new WebViewPackageNotFoundException(e);
+ }
+ }
+
public PackageInfo getPackageInfo() {
if (packageInfo == null) {
- try {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
- } catch (PackageManager.NameNotFoundException e) {
- throw new WebViewPackageNotFoundException(e);
- }
+ updatePackageInfo();
}
return packageInfo;
}
@@ -171,6 +170,7 @@ public class WebViewProviderInfo implements Parcelable {
public String packageName;
public String description;
private boolean availableByDefault;
+ private boolean isFallback;
private String[] signatures;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b689564cfe58..496f7eee27f7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -28,6 +28,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.os.Debug;
+import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -5930,6 +5931,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public boolean requestCursorUpdates(int cursorUpdateMode) {
return getTarget().requestCursorUpdates(cursorUpdateMode);
}
+
+ @Override
+ public Handler getHandler() {
+ return getTarget().getHandler();
+ }
}
/**
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 9a6859387bdf..34f3a47393ba 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -694,7 +694,7 @@ public abstract class AbsSeekBar extends ProgressBar {
final int halfH = h >= 0 ? h / 2 : 1;
mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
- final int spacing = (getWidth() - mPaddingLeft - mPaddingRight) / count;
+ final float spacing = (getWidth() - mPaddingLeft - mPaddingRight) / (float) count;
final int saveCount = canvas.save();
canvas.translate(mPaddingLeft, getHeight() / 2);
for (int i = 0; i <= count; i++) {
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 4d707e369992..3421790894ed 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -19,15 +19,14 @@ package android.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.os.Handler;
-import android.os.Message;
import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.util.Formatter;
import java.util.IllegalFormatException;
import java.util.Locale;
@@ -37,11 +36,17 @@ import java.util.Locale;
* <p>
* You can give it a start time in the {@link SystemClock#elapsedRealtime} timebase,
* and it counts up from that, or if you don't give it a base time, it will use the
- * time at which you call {@link #start}. By default it will display the current
+ * time at which you call {@link #start}.
+ *
+ * <p>The timer can also count downward towards the base time by
+ * setting {@link #setCountDown(boolean)} to true.
+ *
+ * <p>By default it will display the current
* timer value in the form "MM:SS" or "H:MM:SS", or you can use {@link #setFormat}
* to format the timer value into an arbitrary string.
*
* @attr ref android.R.styleable#Chronometer_format
+ * @attr ref android.R.styleable#Chronometer_countDown
*/
@RemoteView
public class Chronometer extends TextView {
@@ -72,6 +77,7 @@ public class Chronometer extends TextView {
private StringBuilder mFormatBuilder;
private OnChronometerTickListener mOnChronometerTickListener;
private StringBuilder mRecycle = new StringBuilder(8);
+ private boolean mCountDown;
/**
* Initialize this Chronometer object.
@@ -102,7 +108,8 @@ public class Chronometer extends TextView {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Chronometer, defStyleAttr, defStyleRes);
- setFormat(a.getString(com.android.internal.R.styleable.Chronometer_format));
+ setFormat(a.getString(R.styleable.Chronometer_format));
+ setCountDown(a.getBoolean(R.styleable.Chronometer_countDown, false));
a.recycle();
init();
@@ -114,6 +121,27 @@ public class Chronometer extends TextView {
}
/**
+ * Set this view to count down to the base instead of counting up from it.
+ *
+ * @param countDown whether this view should count down
+ *
+ * @see #setBase(long)
+ */
+ @android.view.RemotableViewMethod
+ public void setCountDown(boolean countDown) {
+ mCountDown = countDown;
+ }
+
+ /**
+ * @return whether this view counts down
+ *
+ * @see #setCountDown(boolean)
+ */
+ public boolean isCountDown() {
+ return mCountDown;
+ }
+
+ /**
* Set the time that the count-up timer is in reference to.
*
* @param base Use the {@link SystemClock#elapsedRealtime} time base.
@@ -226,9 +254,17 @@ public class Chronometer extends TextView {
private synchronized void updateText(long now) {
mNow = now;
- long seconds = now - mBase;
+ long seconds = mCountDown ? mBase - now : now - mBase;
seconds /= 1000;
+ boolean negative = false;
+ if (seconds < 0) {
+ seconds = -seconds;
+ negative = true;
+ }
String text = DateUtils.formatElapsedTime(mRecycle, seconds);
+ if (negative) {
+ text = getResources().getString(R.string.negative_duration, text);
+ }
if (mFormat != null) {
Locale loc = Locale.getDefault();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 1826dd82abed..881e5cd62794 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -965,20 +965,21 @@ public class Editor {
private int getNextCursorOffset(int offset, boolean findAfterGivenOffset) {
final Layout layout = mTextView.getLayout();
if (layout == null) return offset;
- final CharSequence text = mTextView.getText();
- final int nextOffset = layout.getPaint().getTextRunCursor(text, 0, text.length(),
- layout.isRtlCharAt(offset) ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR,
- offset, findAfterGivenOffset ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE);
- return nextOffset == -1 ? offset : nextOffset;
+ return findAfterGivenOffset == layout.isRtlCharAt(offset) ?
+ layout.getOffsetToLeftOf(offset) : layout.getOffsetToRightOf(offset);
}
private long getCharClusterRange(int offset) {
final int textLength = mTextView.getText().length();
if (offset < textLength) {
- return TextUtils.packRangeInLong(offset, getNextCursorOffset(offset, true));
+ final int clusterEndOffset = getNextCursorOffset(offset, true);
+ return TextUtils.packRangeInLong(
+ getNextCursorOffset(clusterEndOffset, false), clusterEndOffset);
}
if (offset - 1 >= 0) {
- return TextUtils.packRangeInLong(getNextCursorOffset(offset, false), offset);
+ final int clusterStartOffset = getNextCursorOffset(offset, false);
+ return TextUtils.packRangeInLong(clusterStartOffset,
+ getNextCursorOffset(clusterStartOffset, true));
}
return TextUtils.packRangeInLong(offset, offset);
}
@@ -1089,7 +1090,7 @@ public class Editor {
CharSequence selectedText = mTextView.getTransformedText(start, end);
ClipData data = ClipData.newPlainText(null, selectedText);
DragLocalState localState = new DragLocalState(mTextView, start, end);
- mTextView.startDragAndDrop(data, getTextThumbnailBuilder(selectedText), localState,
+ mTextView.startDragAndDrop(data, getTextThumbnailBuilder(start, end), localState,
View.DRAG_FLAG_GLOBAL);
stopTextActionMode();
if (hasSelectionController()) {
@@ -2296,7 +2297,7 @@ public class Editor {
}
}
- private DragShadowBuilder getTextThumbnailBuilder(CharSequence text) {
+ private DragShadowBuilder getTextThumbnailBuilder(int start, int end) {
TextView shadowView = (TextView) View.inflate(mTextView.getContext(),
com.android.internal.R.layout.text_drag_thumbnail, null);
@@ -2304,9 +2305,11 @@ public class Editor {
throw new IllegalArgumentException("Unable to inflate text drag thumbnail");
}
- if (text.length() > DRAG_SHADOW_MAX_TEXT_LENGTH) {
- text = text.subSequence(0, DRAG_SHADOW_MAX_TEXT_LENGTH);
+ if (end - start > DRAG_SHADOW_MAX_TEXT_LENGTH) {
+ final long range = getCharClusterRange(start + DRAG_SHADOW_MAX_TEXT_LENGTH);
+ end = TextUtils.unpackRangeEndFromLong(range);
}
+ final CharSequence text = mTextView.getTransformedText(start, end);
shadowView.setText(text);
shadowView.setTextColor(mTextView.getTextColors());
@@ -4128,13 +4131,15 @@ public class Editor {
}
if (isVisible()) {
- final int positionX = parentPositionX + mPositionX;
- final int positionY = parentPositionY + mPositionY;
+ // Transform to the window coordinates to follow the view tranformation.
+ final int[] pts = { mPositionX + mHotspotX + getHorizontalOffset(), mPositionY};
+ mTextView.transformFromViewToWindowSpace(pts);
+ pts[0] -= mHotspotX + getHorizontalOffset();
+
if (isShowing()) {
- mContainer.update(positionX, positionY, -1, -1);
+ mContainer.update(pts[0], pts[1], -1, -1);
} else {
- mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
- positionX, positionY);
+ mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY, pts[0], pts[1]);
}
} else {
if (isShowing()) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8fa71a21cd4a..54b3932dfeb2 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1653,7 +1653,7 @@ public class PopupWindow {
// can expect the OnAttachStateChangeListener to have been called prior
// to executing this method, so we can rely on that instead.
final Transition exitTransition = mExitTransition;
- if (!mIsAnchorRootAttached && exitTransition != null && decorView.isLaidOut()) {
+ if (mIsAnchorRootAttached && exitTransition != null && decorView.isLaidOut()) {
// The decor view is non-interactive during exit transitions.
final LayoutParams p = (LayoutParams) decorView.getLayoutParams();
p.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dee25d35364c..063288e2adfc 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -454,12 +454,19 @@ public class RemoteViews implements Parcelable, Filter {
public void onClick(View v) {
// Insure that this view is a child of an AdapterView
View parent = (View) v.getParent();
+ // Break the for loop on the first encounter of:
+ // 1) an AdapterView,
+ // 2) an AppWidgetHostView that is not a RemoteViewsFrameLayout, or
+ // 3) a null parent.
+ // 2) and 3) are unexpected and catch the case where a child is not
+ // correctly parented in an AdapterView.
while (parent != null && !(parent instanceof AdapterView<?>)
- && !(parent instanceof AppWidgetHostView)) {
+ && !((parent instanceof AppWidgetHostView) &&
+ !(parent instanceof RemoteViewsAdapter.RemoteViewsFrameLayout))) {
parent = (View) parent.getParent();
}
- if (parent instanceof AppWidgetHostView || parent == null) {
+ if (!(parent instanceof AdapterView<?>)) {
// Somehow they've managed to get this far without having
// and AdapterView as a parent.
Log.e(LOG_TAG, "Collection item doesn't have AdapterView parent");
@@ -1823,23 +1830,37 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
- * Helper action to set layout margin on a View.
+ * Helper action to set layout params on a View.
*/
- private class ViewMarginEndAction extends Action {
- public ViewMarginEndAction(int viewId, int end) {
+ private class LayoutParamAction extends Action {
+
+ /** Set marginEnd */
+ public static final int LAYOUT_MARGIN_END = 1;
+ /** Set width */
+ public static final int LAYOUT_WIDTH = 2;
+
+ /**
+ * @param viewId ID of the view alter
+ * @param property which layout parameter to alter
+ * @param value new value of the layout parameter
+ */
+ public LayoutParamAction(int viewId, int property, int value) {
this.viewId = viewId;
- this.end = end;
+ this.property = property;
+ this.value = value;
}
- public ViewMarginEndAction(Parcel parcel) {
+ public LayoutParamAction(Parcel parcel) {
viewId = parcel.readInt();
- end = parcel.readInt();
+ property = parcel.readInt();
+ value = parcel.readInt();
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(TAG);
dest.writeInt(viewId);
- dest.writeInt(end);
+ dest.writeInt(property);
+ dest.writeInt(value);
}
@Override
@@ -1849,17 +1870,31 @@ public class RemoteViews implements Parcelable, Filter {
return;
}
ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
- if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(end);
- target.setLayoutParams(layoutParams);
+ if (layoutParams == null) {
+ return;
+ }
+ switch (property) {
+ case LAYOUT_MARGIN_END:
+ if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
+ ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
+ target.setLayoutParams(layoutParams);
+ }
+ break;
+ case LAYOUT_WIDTH:
+ layoutParams.width = value;
+ target.setLayoutParams(layoutParams);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown property " + property);
}
}
public String getActionName() {
- return "ViewMarginEndAction";
+ return "LayoutParamAction" + property + ".";
}
- int end;
+ int property;
+ int value;
public final static int TAG = 19;
}
@@ -1945,13 +1980,13 @@ public class RemoteViews implements Parcelable, Filter {
public SetRemoteInputsAction(Parcel parcel) {
viewId = parcel.readInt();
- remoteInputs = parcel.readParcelableArray(RemoteInput.class.getClassLoader());
+ remoteInputs = parcel.createTypedArray(RemoteInput.CREATOR);
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(TAG);
dest.writeInt(viewId);
- dest.writeParcelableArray(remoteInputs, flags);
+ dest.writeTypedArray(remoteInputs, flags);
}
@Override
@@ -2169,8 +2204,8 @@ public class RemoteViews implements Parcelable, Filter {
case SetRemoteInputsAction.TAG:
mActions.add(new SetRemoteInputsAction(parcel));
break;
- case ViewMarginEndAction.TAG:
- mActions.add(new ViewMarginEndAction(parcel));
+ case LayoutParamAction.TAG:
+ mActions.add(new LayoutParamAction(parcel));
break;
default:
throw new ActionException("Tag " + tag + " not found");
@@ -2528,6 +2563,8 @@ public class RemoteViews implements Parcelable, Filter {
* @param format The Chronometer format string, or null to
* simply display the timer value.
* @param started True if you want the clock to be started, false if not.
+ *
+ * @see #setChronometerCountsDown(int, boolean)
*/
public void setChronometer(int viewId, long base, String format, boolean started) {
setLong(viewId, "setBase", base);
@@ -2536,6 +2573,18 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Equivalent to calling {@link Chronometer#setCountDown(boolean) Chronometer.setCountDown} on
+ * the chronometer with the given viewId.
+ *
+ * @param viewId The id of the {@link Chronometer} to change
+ * @param isCountDown True if you want the chronometer to count down to base instead of
+ * counting up.
+ */
+ public void setChronometerCountsDown(int viewId, boolean isCountDown) {
+ setBoolean(viewId, "setCountDown", isCountDown);
+ }
+
+ /**
* Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
* {@link ProgressBar#setProgress ProgressBar.setProgress}, and
* {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
@@ -2788,7 +2837,15 @@ public class RemoteViews implements Parcelable, Filter {
* @param endMargin the left padding in pixels
*/
public void setViewLayoutMarginEnd(int viewId, int endMargin) {
- addAction(new ViewMarginEndAction(viewId, endMargin));
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END, endMargin));
+ }
+
+ /**
+ * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
+ * @hide
+ */
+ public void setViewLayoutWidth(int viewId, int layoutWidth) {
+ mActions.add(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, layoutWidth));
}
/**
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 5953a989c928..10abbab6aacd 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -18,11 +18,13 @@ package android.widget;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import android.Manifest;
+import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +36,9 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
@@ -74,7 +79,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
private RemoteViewsAdapterServiceConnection mServiceConnection;
private WeakReference<RemoteAdapterConnectionCallback> mCallback;
private OnClickHandler mRemoteViewsOnClickHandler;
- private FixedSizeRemoteViewsCache mCache;
+ private final FixedSizeRemoteViewsCache mCache;
private int mVisibleWindowLowerBound;
private int mVisibleWindowUpperBound;
@@ -92,13 +97,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
// structures;
- private static final HashMap<RemoteViewsCacheKey,
- FixedSizeRemoteViewsCache> sCachedRemoteViewsCaches
- = new HashMap<RemoteViewsCacheKey,
- FixedSizeRemoteViewsCache>();
+ private static final HashMap<RemoteViewsCacheKey, FixedSizeRemoteViewsCache>
+ sCachedRemoteViewsCaches = new HashMap<>();
private static final HashMap<RemoteViewsCacheKey, Runnable>
- sRemoteViewsCacheRemoveRunnables
- = new HashMap<RemoteViewsCacheKey, Runnable>();
+ sRemoteViewsCacheRemoveRunnables = new HashMap<>();
private static HandlerThread sCacheRemovalThread;
private static Handler sCacheRemovalQueue;
@@ -286,9 +288,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
* A FrameLayout which contains a loading view, and manages the re/applying of RemoteViews when
* they are loaded.
*/
- private static class RemoteViewsFrameLayout extends FrameLayout {
- public RemoteViewsFrameLayout(Context context) {
+ static class RemoteViewsFrameLayout extends AppWidgetHostView {
+ private final FixedSizeRemoteViewsCache mCache;
+
+ public RemoteViewsFrameLayout(Context context, FixedSizeRemoteViewsCache cache) {
super(context);
+ mCache = cache;
}
/**
@@ -297,13 +302,24 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
* successfully.
*/
public void onRemoteViewsLoaded(RemoteViews view, OnClickHandler handler) {
- try {
- // Remove all the children of this layout first
- removeAllViews();
- addView(view.apply(getContext(), this, handler));
- } catch (Exception e) {
- Log.e(TAG, "Failed to apply RemoteViews.");
- }
+ setOnClickHandler(handler);
+ applyRemoteViews(view);
+ }
+
+ @Override
+ protected View getDefaultView() {
+ return mCache.getMetaData().createDefaultLoadingView(this);
+ }
+
+ @Override
+ protected Context getRemoteContext() {
+ return null;
+ }
+
+ @Override
+ protected View getErrorView() {
+ // Use the default loading view as the error view.
+ return getDefaultView();
}
}
@@ -312,29 +328,21 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
* adapter that have not yet had their RemoteViews loaded.
*/
private class RemoteViewsFrameLayoutRefSet {
- private HashMap<Integer, LinkedList<RemoteViewsFrameLayout>> mReferences;
- private HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
- mViewToLinkedList;
-
- public RemoteViewsFrameLayoutRefSet() {
- mReferences = new HashMap<Integer, LinkedList<RemoteViewsFrameLayout>>();
- mViewToLinkedList =
- new HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>();
- }
+ private final SparseArray<LinkedList<RemoteViewsFrameLayout>> mReferences =
+ new SparseArray<>();
+ private final HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
+ mViewToLinkedList = new HashMap<>();
/**
* Adds a new reference to a RemoteViewsFrameLayout returned by the adapter.
*/
public void add(int position, RemoteViewsFrameLayout layout) {
- final Integer pos = position;
- LinkedList<RemoteViewsFrameLayout> refs;
+ LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
// Create the list if necessary
- if (mReferences.containsKey(pos)) {
- refs = mReferences.get(pos);
- } else {
+ if (refs == null) {
refs = new LinkedList<RemoteViewsFrameLayout>();
- mReferences.put(pos, refs);
+ mReferences.put(position, refs);
}
mViewToLinkedList.put(layout, refs);
@@ -349,10 +357,9 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
public void notifyOnRemoteViewsLoaded(int position, RemoteViews view) {
if (view == null) return;
- final Integer pos = position;
- if (mReferences.containsKey(pos)) {
+ final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
+ if (refs != null) {
// Notify all the references for that position of the newly loaded RemoteViews
- final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(pos);
for (final RemoteViewsFrameLayout ref : refs) {
ref.onRemoteViewsLoaded(view, mRemoteViewsOnClickHandler);
if (mViewToLinkedList.containsKey(ref)) {
@@ -361,7 +368,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
refs.clear();
// Remove this set from the original mapping
- mReferences.remove(pos);
+ mReferences.remove(position);
}
}
@@ -402,7 +409,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
int mFirstViewHeight;
// A mapping from type id to a set of unique type ids
- private final HashMap<Integer, Integer> mTypeIdIndexMap = new HashMap<Integer, Integer>();
+ private final SparseIntArray mTypeIdIndexMap = new SparseIntArray();
public RemoteViewsMetaData() {
reset();
@@ -438,82 +445,47 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
public int getMappedViewType(int typeId) {
- if (mTypeIdIndexMap.containsKey(typeId)) {
- return mTypeIdIndexMap.get(typeId);
- } else {
+ int mappedTypeId = mTypeIdIndexMap.get(typeId, -1);
+ if (mappedTypeId == -1) {
// We +1 because the loading view always has view type id of 0
- int incrementalTypeId = mTypeIdIndexMap.size() + 1;
- mTypeIdIndexMap.put(typeId, incrementalTypeId);
- return incrementalTypeId;
+ mappedTypeId = mTypeIdIndexMap.size() + 1;
+ mTypeIdIndexMap.put(typeId, mappedTypeId);
}
+ return mappedTypeId;
}
public boolean isViewTypeInRange(int typeId) {
int mappedType = getMappedViewType(typeId);
- if (mappedType >= viewTypeCount) {
- return false;
- } else {
- return true;
- }
+ return (mappedType < viewTypeCount);
}
- private RemoteViewsFrameLayout createLoadingView(int position, View convertView,
- ViewGroup parent, Object lock, LayoutInflater layoutInflater, OnClickHandler
- handler) {
- // Create and return a new FrameLayout, and setup the references for this position
+ /**
+ * Creates a default loading view. Uses the size of the first row as a guide for the
+ * size of the loading view.
+ */
+ private synchronized View createDefaultLoadingView(ViewGroup parent) {
final Context context = parent.getContext();
- RemoteViewsFrameLayout layout = new RemoteViewsFrameLayout(context);
-
- // Create a new loading view
- synchronized (lock) {
- boolean customLoadingViewAvailable = false;
-
- if (mUserLoadingView != null) {
- // Try to inflate user-specified loading view
- try {
- View loadingView = mUserLoadingView.apply(parent.getContext(), parent,
- handler);
- loadingView.setTagInternal(com.android.internal.R.id.rowTypeId,
- new Integer(0));
- layout.addView(loadingView);
- customLoadingViewAvailable = true;
- } catch (Exception e) {
- Log.w(TAG, "Error inflating custom loading view, using default loading" +
- "view instead", e);
- }
- }
- if (!customLoadingViewAvailable) {
- // A default loading view
- // Use the size of the first row as a guide for the size of the loading view
- if (mFirstViewHeight < 0) {
- try {
- View firstView = mFirstView.apply(parent.getContext(), parent, handler);
- firstView.measure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mFirstViewHeight = firstView.getMeasuredHeight();
- mFirstView = null;
- } catch (Exception e) {
- float density = context.getResources().getDisplayMetrics().density;
- mFirstViewHeight = (int)
- Math.round(sDefaultLoadingViewHeight * density);
- mFirstView = null;
- Log.w(TAG, "Error inflating first RemoteViews" + e);
- }
- }
-
- // Compose the loading view text
- TextView loadingTextView = (TextView) layoutInflater.inflate(
- com.android.internal.R.layout.remote_views_adapter_default_loading_view,
- layout, false);
- loadingTextView.setHeight(mFirstViewHeight);
- loadingTextView.setTag(new Integer(0));
-
- layout.addView(loadingTextView);
+ if (mFirstViewHeight < 0) {
+ try {
+ View firstView = mFirstView.apply(parent.getContext(), parent);
+ firstView.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mFirstViewHeight = firstView.getMeasuredHeight();
+ } catch (Exception e) {
+ float density = context.getResources().getDisplayMetrics().density;
+ mFirstViewHeight = Math.round(sDefaultLoadingViewHeight * density);
+ Log.w(TAG, "Error inflating first RemoteViews" + e);
}
+ mFirstView = null;
}
- return layout;
+ // Compose the loading view text
+ TextView loadingTextView = (TextView) LayoutInflater.from(context).inflate(
+ com.android.internal.R.layout.remote_views_adapter_default_loading_view,
+ parent, false);
+ loadingTextView.setHeight(mFirstViewHeight);
+ return loadingTextView;
}
}
@@ -548,8 +520,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// The meta data objects are made final so that they can be locked on independently
// of the FixedSizeRemoteViewsCache. If we ever lock on both meta data objects, it is in
// the order mTemporaryMetaData followed by mMetaData.
- private final RemoteViewsMetaData mMetaData;
- private final RemoteViewsMetaData mTemporaryMetaData;
+ private final RemoteViewsMetaData mMetaData = new RemoteViewsMetaData();
+ private final RemoteViewsMetaData mTemporaryMetaData = new RemoteViewsMetaData();
// The cache/mapping of position to RemoteViewsMetaData. This set is guaranteed to be
// greater than or equal to the set of RemoteViews.
@@ -558,22 +530,20 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// the heavy RemoteViews around. The RemoteViews cache is trimmed to fixed constraints wrt.
// memory and size, but this metadata cache will retain information until the data at the
// position is guaranteed as not being necessary any more (usually on notifyDataSetChanged).
- private HashMap<Integer, RemoteViewsIndexMetaData> mIndexMetaData;
+ private final SparseArray<RemoteViewsIndexMetaData> mIndexMetaData = new SparseArray<>();
// The cache of actual RemoteViews, which may be pruned if the cache gets too large, or uses
// too much memory.
- private HashMap<Integer, RemoteViews> mIndexRemoteViews;
+ private final SparseArray<RemoteViews> mIndexRemoteViews = new SparseArray<>();
- // The set of indices that have been explicitly requested by the collection view
- private HashSet<Integer> mRequestedIndices;
+ // An array of indices to load, Indices which are explicitely requested are set to true,
+ // and those determined by the preloading algorithm to prefetch are set to false.
+ private final SparseBooleanArray mIndicesToLoad = new SparseBooleanArray();
// We keep a reference of the last requested index to determine which item to prune the
// farthest items from when we hit the memory limit
private int mLastRequestedIndex;
- // The set of indices to load, including those explicitly requested, as well as those
- // determined by the preloading algorithm to be prefetched
- private HashSet<Integer> mLoadIndices;
// The lower and upper bounds of the preloaded range
private int mPreloadLowerBound;
@@ -584,8 +554,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// The maxCountSlack is used to determine if a new position in the cache to be loaded is
// sufficiently ouside the old set, prompting a shifting of the "window" of items to be
// preloaded.
- private int mMaxCount;
- private int mMaxCountSlack;
+ private final int mMaxCount;
+ private final int mMaxCountSlack;
private static final float sMaxCountSlackPercent = 0.75f;
private static final int sMaxMemoryLimitInBytes = 2 * 1024 * 1024;
@@ -594,17 +564,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
mMaxCountSlack = Math.round(sMaxCountSlackPercent * (mMaxCount / 2));
mPreloadLowerBound = 0;
mPreloadUpperBound = -1;
- mMetaData = new RemoteViewsMetaData();
- mTemporaryMetaData = new RemoteViewsMetaData();
- mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>();
- mIndexRemoteViews = new HashMap<Integer, RemoteViews>();
- mRequestedIndices = new HashSet<Integer>();
mLastRequestedIndex = -1;
- mLoadIndices = new HashSet<Integer>();
}
- public void insert(int position, RemoteViews v, long itemId,
- ArrayList<Integer> visibleWindow) {
+ public void insert(int position, RemoteViews v, long itemId, int[] visibleWindow) {
// Trim the cache if we go beyond the count
if (mIndexRemoteViews.size() >= mMaxCount) {
mIndexRemoteViews.remove(getFarthestPositionFrom(position, visibleWindow));
@@ -630,8 +593,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
// Update the metadata cache
- if (mIndexMetaData.containsKey(position)) {
- final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
+ final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
+ if (metaData != null) {
metaData.set(v, itemId);
} else {
mIndexMetaData.put(position, new RemoteViewsIndexMetaData(v, itemId));
@@ -646,16 +609,10 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
return mTemporaryMetaData;
}
public RemoteViews getRemoteViewsAt(int position) {
- if (mIndexRemoteViews.containsKey(position)) {
- return mIndexRemoteViews.get(position);
- }
- return null;
+ return mIndexRemoteViews.get(position);
}
public RemoteViewsIndexMetaData getMetaDataAt(int position) {
- if (mIndexMetaData.containsKey(position)) {
- return mIndexMetaData.get(position);
- }
- return null;
+ return mIndexMetaData.get(position);
}
public void commitTemporaryMetaData() {
@@ -669,8 +626,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
private int getRemoteViewsBitmapMemoryUsage() {
// Calculate the memory usage of all the RemoteViews bitmaps being cached
int mem = 0;
- for (Integer i : mIndexRemoteViews.keySet()) {
- final RemoteViews v = mIndexRemoteViews.get(i);
+ for (int i = mIndexRemoteViews.size() - 1; i >= 0; i--) {
+ final RemoteViews v = mIndexRemoteViews.valueAt(i);
if (v != null) {
mem += v.estimateMemoryUsage();
}
@@ -678,24 +635,25 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
return mem;
}
- private int getFarthestPositionFrom(int pos, ArrayList<Integer> visibleWindow) {
+ private int getFarthestPositionFrom(int pos, int[] visibleWindow) {
// Find the index farthest away and remove that
int maxDist = 0;
int maxDistIndex = -1;
int maxDistNotVisible = 0;
int maxDistIndexNotVisible = -1;
- for (int i : mIndexRemoteViews.keySet()) {
- int dist = Math.abs(i-pos);
- if (dist > maxDistNotVisible && !visibleWindow.contains(i)) {
+ for (int i = mIndexRemoteViews.size() - 1; i >= 0; i--) {
+ int index = mIndexRemoteViews.keyAt(i);
+ int dist = Math.abs(index-pos);
+ if (dist > maxDistNotVisible && Arrays.binarySearch(visibleWindow, index) < 0) {
// maxDistNotVisible/maxDistIndexNotVisible will store the index of the
// farthest non-visible position
- maxDistIndexNotVisible = i;
+ maxDistIndexNotVisible = index;
maxDistNotVisible = dist;
}
if (dist >= maxDist) {
// maxDist/maxDistIndex will store the index of the farthest position
// regardless of whether it is visible or not
- maxDistIndex = i;
+ maxDistIndex = index;
maxDist = dist;
}
}
@@ -707,9 +665,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
public void queueRequestedPositionToLoad(int position) {
mLastRequestedIndex = position;
- synchronized (mLoadIndices) {
- mRequestedIndices.add(position);
- mLoadIndices.add(position);
+ synchronized (mIndicesToLoad) {
+ mIndicesToLoad.put(position, true);
}
}
public boolean queuePositionsToBePreloadedFromRequestedPosition(int position) {
@@ -725,11 +682,13 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
synchronized (mMetaData) {
count = mMetaData.count;
}
- synchronized (mLoadIndices) {
- mLoadIndices.clear();
-
- // Add all the requested indices
- mLoadIndices.addAll(mRequestedIndices);
+ synchronized (mIndicesToLoad) {
+ // Remove all indices which have not been previously requested.
+ for (int i = mIndicesToLoad.size() - 1; i >= 0; i--) {
+ if (!mIndicesToLoad.valueAt(i)) {
+ mIndicesToLoad.removeAt(i);
+ }
+ }
// Add all the preload indices
int halfMaxCount = mMaxCount / 2;
@@ -738,43 +697,40 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
int effectiveLowerBound = Math.max(0, mPreloadLowerBound);
int effectiveUpperBound = Math.min(mPreloadUpperBound, count - 1);
for (int i = effectiveLowerBound; i <= effectiveUpperBound; ++i) {
- mLoadIndices.add(i);
+ if (mIndexRemoteViews.indexOfKey(i) < 0 && !mIndicesToLoad.get(i)) {
+ // If the index has not been requested, and has not been loaded.
+ mIndicesToLoad.put(i, false);
+ }
}
-
- // But remove all the indices that have already been loaded and are cached
- mLoadIndices.removeAll(mIndexRemoteViews.keySet());
}
return true;
}
- /** Returns the next index to load, and whether that index was directly requested or not */
- public int[] getNextIndexToLoad() {
+ /** Returns the next index to load */
+ public int getNextIndexToLoad() {
// We try and prioritize items that have been requested directly, instead
// of items that are loaded as a result of the caching mechanism
- synchronized (mLoadIndices) {
+ synchronized (mIndicesToLoad) {
// Prioritize requested indices to be loaded first
- if (!mRequestedIndices.isEmpty()) {
- Integer i = mRequestedIndices.iterator().next();
- mRequestedIndices.remove(i);
- mLoadIndices.remove(i);
- return new int[]{i.intValue(), 1};
+ int index = mIndicesToLoad.indexOfValue(true);
+ if (index < 0) {
+ // Otherwise, preload other indices as necessary
+ index = mIndicesToLoad.indexOfValue(false);
}
-
- // Otherwise, preload other indices as necessary
- if (!mLoadIndices.isEmpty()) {
- Integer i = mLoadIndices.iterator().next();
- mLoadIndices.remove(i);
- return new int[]{i.intValue(), 0};
+ if (index < 0) {
+ return -1;
+ } else {
+ int key = mIndicesToLoad.keyAt(index);
+ mIndicesToLoad.removeAt(index);
+ return key;
}
-
- return new int[]{-1, 0};
}
}
public boolean containsRemoteViewAt(int position) {
- return mIndexRemoteViews.containsKey(position);
+ return mIndexRemoteViews.indexOfKey(position) >= 0;
}
public boolean containsMetaDataAt(int position) {
- return mIndexMetaData.containsKey(position);
+ return mIndexMetaData.indexOfKey(position) >= 0;
}
public void reset() {
@@ -787,9 +743,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
mLastRequestedIndex = -1;
mIndexRemoteViews.clear();
mIndexMetaData.clear();
- synchronized (mLoadIndices) {
- mRequestedIndices.clear();
- mLoadIndices.clear();
+ synchronized (mIndicesToLoad) {
+ mIndicesToLoad.clear();
}
}
}
@@ -942,8 +897,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// Get the next index to load
int position = -1;
synchronized (mCache) {
- int[] res = mCache.getNextIndexToLoad();
- position = res[0];
+ position = mCache.getNextIndexToLoad();
}
if (position > -1) {
// Load the item, and notify any existing RemoteViewsFrameLayouts
@@ -1048,7 +1002,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
synchronized (mCache) {
if (viewTypeInRange) {
- ArrayList<Integer> visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
+ int[] visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
mVisibleWindowUpperBound, cacheCount);
// Cache the RemoteViews we loaded
mCache.insert(position, remoteViews, itemId, visibleWindow);
@@ -1117,21 +1071,6 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
/**
- * Returns the item type id for the specified convert view. Returns -1 if the convert view
- * is invalid.
- */
- private int getConvertViewTypeId(View convertView) {
- int typeId = -1;
- if (convertView != null) {
- Object tag = convertView.getTag(com.android.internal.R.id.rowTypeId);
- if (tag != null) {
- typeId = (Integer) tag;
- }
- }
- return typeId;
- }
-
- /**
* This method allows an AdapterView using this Adapter to provide information about which
* views are currently being displayed. This allows for certain optimizations and preloading
* which wouldn't otherwise be possible.
@@ -1145,7 +1084,8 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// "Request" an index so that we can queue it for loading, initiate subsequent
// preloading, etc.
synchronized (mCache) {
- boolean isInCache = mCache.containsRemoteViewAt(position);
+ RemoteViews rv = mCache.getRemoteViewsAt(position);
+ boolean isInCache = (rv != null);
boolean isConnected = mServiceConnection.isConnected();
boolean hasNewItems = false;
@@ -1162,75 +1102,23 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
hasNewItems = mCache.queuePositionsToBePreloadedFromRequestedPosition(position);
}
+ final RemoteViewsFrameLayout layout =
+ (convertView instanceof RemoteViewsFrameLayout)
+ ? (RemoteViewsFrameLayout) convertView
+ : new RemoteViewsFrameLayout(parent.getContext(), mCache);
if (isInCache) {
- View convertViewChild = null;
- int convertViewTypeId = 0;
- RemoteViewsFrameLayout layout = null;
-
- if (convertView instanceof RemoteViewsFrameLayout) {
- layout = (RemoteViewsFrameLayout) convertView;
- convertViewChild = layout.getChildAt(0);
- convertViewTypeId = getConvertViewTypeId(convertViewChild);
- }
-
- // Second, we try and retrieve the RemoteViews from the cache, returning a loading
- // view and queueing it to be loaded if it has not already been loaded.
- Context context = parent.getContext();
- RemoteViews rv = mCache.getRemoteViewsAt(position);
- RemoteViewsIndexMetaData indexMetaData = mCache.getMetaDataAt(position);
- int typeId = indexMetaData.typeId;
-
- try {
- // Reuse the convert view where possible
- if (layout != null) {
- if (convertViewTypeId == typeId) {
- rv.reapply(context, convertViewChild, mRemoteViewsOnClickHandler);
- return layout;
- }
- layout.removeAllViews();
- } else {
- layout = new RemoteViewsFrameLayout(context);
- }
-
- // Otherwise, create a new view to be returned
- View newView = rv.apply(context, parent, mRemoteViewsOnClickHandler);
- newView.setTagInternal(com.android.internal.R.id.rowTypeId,
- new Integer(typeId));
- layout.addView(newView);
- return layout;
-
- } catch (Exception e){
- // We have to make sure that we successfully inflated the RemoteViews, if not
- // we return the loading view instead.
- Log.w(TAG, "Error inflating RemoteViews at position: " + position + ", using" +
- "loading view instead" + e);
-
- RemoteViewsFrameLayout loadingView = null;
- final RemoteViewsMetaData metaData = mCache.getMetaData();
- synchronized (metaData) {
- loadingView = metaData.createLoadingView(position, convertView, parent,
- mCache, mLayoutInflater, mRemoteViewsOnClickHandler);
- }
- return loadingView;
- } finally {
- if (hasNewItems) loadNextIndexInBackground();
- }
+ layout.onRemoteViewsLoaded(rv, mRemoteViewsOnClickHandler);
+ if (hasNewItems) loadNextIndexInBackground();
} else {
- // If the cache does not have the RemoteViews at this position, then create a
- // loading view and queue the actual position to be loaded in the background
- RemoteViewsFrameLayout loadingView = null;
- final RemoteViewsMetaData metaData = mCache.getMetaData();
- synchronized (metaData) {
- loadingView = metaData.createLoadingView(position, convertView, parent,
- mCache, mLayoutInflater, mRemoteViewsOnClickHandler);
- }
-
- mRequestedViews.add(position, loadingView);
+ // If the views is not loaded, apply the loading view. If the loading view doesn't
+ // exist, the layout will create a default view based on the firstView height.
+ layout.onRemoteViewsLoaded(mCache.getMetaData().mUserLoadingView,
+ mRemoteViewsOnClickHandler);
+ mRequestedViews.add(position, layout);
mCache.queueRequestedPositionToLoad(position);
loadNextIndexInBackground();
-
- return loadingView;
}
+ return layout;
}
}
@@ -1276,7 +1164,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
// Re-request the new metadata (only after the notification to the factory)
updateTemporaryMetaData();
int newCount;
- ArrayList<Integer> visibleWindow;
+ int[] visibleWindow;
synchronized(mCache.getTemporaryMetaData()) {
newCount = mCache.getTemporaryMetaData().count;
visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
@@ -1311,26 +1199,33 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
mNotifyDataSetChangedAfterOnServiceConnected = false;
}
- private ArrayList<Integer> getVisibleWindow(int lower, int upper, int count) {
- ArrayList<Integer> window = new ArrayList<Integer>();
-
+ /**
+ * Returns a sorted array of all integers between lower and upper.
+ */
+ private int[] getVisibleWindow(int lower, int upper, int count) {
// In the case that the window is invalid or uninitialized, return an empty window.
if ((lower == 0 && upper == 0) || lower < 0 || upper < 0) {
- return window;
+ return new int[0];
}
+ int[] window;
if (lower <= upper) {
- for (int i = lower; i <= upper; i++){
- window.add(i);
+ window = new int[upper + 1 - lower];
+ for (int i = lower, j = 0; i <= upper; i++, j++){
+ window[j] = i;
}
} else {
// If the upper bound is less than the lower bound it means that the visible window
// wraps around.
- for (int i = lower; i < count; i++) {
- window.add(i);
+ count = Math.max(count, lower);
+ window = new int[count - lower + upper + 1];
+ int j = 0;
+ // Add the entries in sorted order
+ for (int i = 0; i <= upper; i++, j++) {
+ window[j] = i;
}
- for (int i = 0; i <= upper; i++) {
- window.add(i);
+ for (int i = lower; i < count; i++, j++) {
+ window[j] = i;
}
}
return window;
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 45fc6c3d4c7a..9a4d69fd4e9a 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -36,6 +36,8 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.speech.RecognizerIntent;
import android.text.Editable;
import android.text.InputType;
@@ -1332,6 +1334,59 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
setIconified(false);
}
+ static class SavedState extends BaseSavedState {
+ boolean isIconified;
+
+ SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public SavedState(Parcel source) {
+ super(source);
+ isIconified = (Boolean) source.readValue(null);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeValue(isIconified);
+ }
+
+ @Override
+ public String toString() {
+ return "SearchView.SavedState{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " isIconified=" + isIconified + "}";
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState ss = new SavedState(superState);
+ ss.isIconified = isIconified();
+ return ss;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ updateViewsVisibility(ss.isIconified);
+ requestLayout();
+ }
+
@Override
public CharSequence getAccessibilityClassName() {
return SearchView.class.getName();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a5c1da936f99..95fcdc179643 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6853,11 +6853,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
.setBreakStrategy(mBreakStrategy)
- .setHyphenationFrequency(mHyphenationFrequency);
+ .setHyphenationFrequency(mHyphenationFrequency)
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
if (shouldEllipsize) {
builder.setEllipsize(mEllipsize)
- .setEllipsizedWidth(ellipsisWidth)
- .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ .setEllipsizedWidth(ellipsisWidth);
}
mHintLayout = builder.build();
}
@@ -6944,11 +6944,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
.setBreakStrategy(mBreakStrategy)
- .setHyphenationFrequency(mHyphenationFrequency);
+ .setHyphenationFrequency(mHyphenationFrequency)
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
- .setEllipsizedWidth(ellipsisWidth)
- .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ .setEllipsizedWidth(ellipsisWidth);
+
}
// TODO: explore always setting maxLines
result = builder.build();
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1d6e52c7cc1e..05fd4c8ab69f 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -69,10 +69,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
private static final int[] ATTRS_TEXT_COLOR = new int[] {R.attr.textColor};
private static final int[] ATTRS_DISABLED_ALPHA = new int[] {R.attr.disabledAlpha};
- // LayoutLib relies on these constants. Change TimePickerClockDelegate_Delegate if
- // modifying these.
- static final int AM = 0;
- static final int PM = 1;
+ private static final int AM = 0;
+ private static final int PM = 1;
private static final int HOURS_IN_HALF_DAY = 12;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b0fb93b89052..6085164b74d2 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -45,6 +45,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.provider.DocumentsContract;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
@@ -128,6 +129,7 @@ public class ChooserActivity extends ResolverActivity {
if (mServiceConnections.isEmpty()) {
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
sendVoiceChoicesIfNeeded();
+ mChooserListAdapter.setShowServiceTargets(true);
}
break;
@@ -137,6 +139,7 @@ public class ChooserActivity extends ResolverActivity {
}
unbindRemainingServices();
sendVoiceChoicesIfNeeded();
+ mChooserListAdapter.setShowServiceTargets(true);
break;
default:
@@ -232,7 +235,7 @@ public class ChooserActivity extends ResolverActivity {
// the case where we don't have access to credential encrypted storage we just won't
// have our pinned target info.
final File prefsFile = new File(new File(
- Environment.getDataUserCredentialEncryptedPackageDirectory(null,
+ Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
context.getUserId(), context.getPackageName()),
"shared_prefs"),
PINNED_SHARED_PREFS_NAME + ".xml");
@@ -308,24 +311,6 @@ public class ChooserActivity extends ResolverActivity {
}
@Override
- public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
- final Intent intent = target.getResolvedIntent();
- final ResolveInfo resolve = target.getResolveInfo();
-
- // When GET_CONTENT is handled by the DocumentsUI system component,
- // we're okay automatically launching it, since it offers it's own
- // intent disambiguation UI.
- if (intent != null && Intent.ACTION_GET_CONTENT.equals(intent.getAction())
- && resolve != null && resolve.priority > 0
- && resolve.activityInfo != null && DocumentsContract.PACKAGE_DOCUMENTS_UI
- .equals(resolve.activityInfo.packageName)) {
- return true;
- }
-
- return false;
- }
-
- @Override
public void showTargetDetails(ResolveInfo ri) {
ComponentName name = ri.activityInfo.getComponentName();
boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
@@ -765,6 +750,7 @@ public class ChooserActivity extends ResolverActivity {
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
private final List<TargetInfo> mCallerTargets = new ArrayList<>();
+ private boolean mShowServiceTargets;
private float mLateFee = 1.f;
@@ -865,6 +851,9 @@ public class ChooserActivity extends ResolverActivity {
}
public int getServiceTargetCount() {
+ if (!mShowServiceTargets) {
+ return 0;
+ }
return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
}
@@ -954,6 +943,14 @@ public class ChooserActivity extends ResolverActivity {
notifyDataSetChanged();
}
+ /**
+ * Set to true to reveal all service targets at once.
+ */
+ public void setShowServiceTargets(boolean show) {
+ mShowServiceTargets = show;
+ notifyDataSetChanged();
+ }
+
private void insertServiceTarget(ChooserTargetInfo chooserTargetInfo) {
final float newScore = chooserTargetInfo.getModifiedScore();
for (int i = 0, N = mServiceTargets.size(); i < N; i++) {
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 9fa2c23dc953..b13be97dfb98 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -44,6 +44,7 @@ interface IAppOpsService {
int checkAudioOperation(int code, int usage, int uid, String packageName);
void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
- void setUserRestrictions(in Bundle restrictions, int userHandle);
+ void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
+ void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle);
void removeUser(int userHandle);
}
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index 9de4a6c62a49..f4c18c300513 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -33,10 +33,11 @@ interface ISoundTriggerService {
void deleteSoundModel(in ParcelUuid soundModelId);
- void startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+ int startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback,
+ in SoundTrigger.RecognitionConfig config);
/**
* Stops recognition.
*/
- void stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+ int stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
}
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index c7459d7b274c..aca93abddf85 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -16,8 +16,8 @@
package com.android.internal.app;
-import android.icu.util.ULocale;
import android.icu.text.ListFormatter;
+import android.icu.util.ULocale;
import android.util.LocaleList;
import java.text.Collator;
@@ -99,7 +99,7 @@ public class LocaleHelper {
* @return the localized name of the locale.
*/
public static String getDisplayName(Locale locale, Locale displayLocale, boolean sentenceCase) {
- String result = ULocale.getDisplayName(locale.toLanguageTag(),
+ String result = ULocale.getDisplayNameWithDialect(locale.toLanguageTag(),
ULocale.forLocale(displayLocale));
return sentenceCase ? toSentenceCase(result, displayLocale) : result;
}
@@ -112,7 +112,8 @@ public class LocaleHelper {
* @return the localized name of the locale.
*/
public static String getDisplayName(Locale locale, boolean sentenceCase) {
- String result = ULocale.getDisplayName(locale.toLanguageTag(), ULocale.getDefault());
+ String result = ULocale.getDisplayNameWithDialect(locale.toLanguageTag(),
+ ULocale.getDefault());
return sentenceCase ? toSentenceCase(result, Locale.getDefault()) : result;
}
@@ -155,7 +156,7 @@ public class LocaleHelper {
}
ListFormatter lfn = ListFormatter.getInstance(dispLocale);
- return lfn.format(localeNames);
+ return lfn.format((Object[]) localeNames);
}
/**
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 6a365e0a6927..b1b019cce869 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -275,7 +275,7 @@ public class LocalePicker extends ListFragment {
config.setLocales(locales);
config.userSetLocale = true;
- am.updateConfiguration(config);
+ am.updatePersistentConfiguration(config);
// Trigger the dirty bit for the Settings Provider.
BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 210adce4d0af..465c4d833aa1 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -104,6 +104,9 @@ public class LocaleStore {
}
private boolean isSuggestionOfType(int suggestionMask) {
+ if (!mIsTranslated) { // Never suggest an untranslated locale
+ return false;
+ }
return (mSuggestionFlags & suggestionMask) == suggestionMask;
}
@@ -207,6 +210,27 @@ public class LocaleStore {
}
}
+ /*
+ * Show all the languages supported for a country in the suggested list.
+ * This is also handy for devices without SIM (tablets).
+ */
+ private static void addSuggestedLocalesForRegion(Locale locale) {
+ if (locale == null) {
+ return;
+ }
+ final String country = locale.getCountry();
+ if (country.isEmpty()) {
+ return;
+ }
+
+ for (LocaleInfo li : sLocaleCache.values()) {
+ if (country.equals(li.getLocale().getCountry())) {
+ // We don't need to differentiate between manual and SIM suggestions
+ li.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SIM;
+ }
+ }
+ }
+
public static void fillCache(Context context) {
if (sFullyInitialized) {
return;
@@ -256,6 +280,8 @@ public class LocaleStore {
li.setTranslated(localizedLocales.contains(li.getLangScriptKey()));
}
+ addSuggestedLocalesForRegion(Locale.getDefault());
+
sFullyInitialized = true;
}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 0964dcf81722..59445688aa7e 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -73,62 +73,28 @@ public class PlatLogoActivity extends Activity {
final int size = (int)
(Math.min(Math.min(dm.widthPixels, dm.heightPixels), 600*dp) - 100*dp);
- final View im = new View(this);
+ final ImageView im = new ImageView(this);
+ final int pad = (int)(40*dp);
+ im.setPadding(pad, pad, pad, pad);
im.setTranslationZ(20);
im.setScaleX(0.5f);
im.setScaleY(0.5f);
im.setAlpha(0f);
- im.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- final int pad = (int) (8 * dp);
- outline.setOval(pad, pad, view.getWidth() - pad, view.getHeight() - pad);
- }
- });
- final float hue = (float) Math.random();
- final Paint bgPaint = new Paint();
- bgPaint.setColor(HSBtoColor(hue, 0.4f, 1f));
- final Paint fgPaint = new Paint();
- fgPaint.setColor(HSBtoColor(hue, 0.5f, 1f));
- final Drawable M = getDrawable(com.android.internal.R.drawable.platlogo_m);
- final Drawable platlogo = new Drawable() {
- @Override
- public void setAlpha(int alpha) { }
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) { }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void draw(Canvas c) {
- final float r = c.getWidth() / 2f;
- c.drawCircle(r, r, r, bgPaint);
- c.drawArc(0, 0, 2 * r, 2 * r, 135, 180, false, fgPaint);
- M.setBounds(0, 0, c.getWidth(), c.getHeight());
- M.draw(c);
- }
- };
im.setBackground(new RippleDrawable(
ColorStateList.valueOf(0xFFFFFFFF),
- platlogo,
+ getDrawable(com.android.internal.R.drawable.platlogo),
null));
- im.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setOval(0, 0, view.getWidth(), view.getHeight());
- }
- });
+// im.setOutlineProvider(new ViewOutlineProvider() {
+// @Override
+// public void getOutline(View view, Outline outline) {
+// outline.setOval(0, 0, view.getWidth(), view.getHeight());
+// }
+// });
im.setClickable(true);
im.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (mTapCount == 0) {
- showMarshmallow(im);
- }
im.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
@@ -175,9 +141,6 @@ public class PlatLogoActivity extends Activity {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode != KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
- if (mKeyCount == 0) {
- showMarshmallow(im);
- }
++mKeyCount;
if (mKeyCount > 2) {
if (mTapCount > 5) {
@@ -201,81 +164,4 @@ public class PlatLogoActivity extends Activity {
.setStartDelay(800)
.start();
}
-
- public void showMarshmallow(View im) {
- final Drawable fg = getDrawable(com.android.internal.R.drawable.platlogo);
- fg.setBounds(0, 0, im.getWidth(), im.getHeight());
- fg.setAlpha(0);
- im.getOverlay().add(fg);
-
- final Animator fadeIn = ObjectAnimator.ofInt(fg, "alpha", 255);
- fadeIn.setInterpolator(mInterpolator);
- fadeIn.setDuration(300);
- fadeIn.start();
- }
-
- /**
- * Convert HSB components to an ARGB color. Alpha set to 0xFF.
- * hsv[0] is Hue [0 .. 1)
- * hsv[1] is Saturation [0...1]
- * hsv[2] is Value [0...1]
- * If hsv values are out of range, they are pinned.
- * @param h Hue component
- * @param s Saturation component
- * @param b Brightness component
- * @return the resulting argb color
- */
- private static int HSBtoColor(float h, float s, float b) {
- h = MathUtils.constrain(h, 0.0f, 1.0f);
- s = MathUtils.constrain(s, 0.0f, 1.0f);
- b = MathUtils.constrain(b, 0.0f, 1.0f);
-
- float red = 0.0f;
- float green = 0.0f;
- float blue = 0.0f;
-
- final float hf = (h - (int) h) * 6.0f;
- final int ihf = (int) hf;
- final float f = hf - ihf;
- final float pv = b * (1.0f - s);
- final float qv = b * (1.0f - s * f);
- final float tv = b * (1.0f - s * (1.0f - f));
-
- switch (ihf) {
- case 0: // Red is the dominant color
- red = b;
- green = tv;
- blue = pv;
- break;
- case 1: // Green is the dominant color
- red = qv;
- green = b;
- blue = pv;
- break;
- case 2:
- red = pv;
- green = b;
- blue = tv;
- break;
- case 3: // Blue is the dominant color
- red = pv;
- green = qv;
- blue = b;
- break;
- case 4:
- red = tv;
- green = pv;
- blue = b;
- break;
- case 5: // Red is the dominant color
- red = b;
- green = pv;
- blue = qv;
- break;
- }
-
- return 0xFF000000 | (((int) (red * 255.0f)) << 16) |
- (((int) (green * 255.0f)) << 8) | ((int) (blue * 255.0f));
- }
-
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3fb768f68ee6..9897b125dea3 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -174,10 +174,6 @@ public class ResolverActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- // We're dispatching intents that might be coming from legacy apps, so
- // don't kill ourselves.
- StrictMode.disableDeathOnFileUriExposure();
-
// Use a specialized prompt when we're handling the 'Home' app startActivity()
final Intent intent = makeMyIntent();
final Set<String> categories = intent.getCategories();
@@ -768,6 +764,17 @@ public class ResolverActivity extends Activity {
}
public void safelyStartActivity(TargetInfo cti) {
+ // We're dispatching intents that might be coming from legacy apps, so
+ // don't kill ourselves.
+ StrictMode.disableDeathOnFileUriExposure();
+ try {
+ safelyStartActivityInternal(cti);
+ } finally {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+ }
+
+ private void safelyStartActivityInternal(TargetInfo cti) {
// If needed, show that intent is forwarded
// from managed profile to owner or other way around.
if (mProfileSwitchMessageId != -1) {
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 478a56d774a5..0d4a5aac2c0a 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -23,7 +23,6 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
-import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
@@ -156,16 +155,9 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
}
TextView text = (TextView) convertView.findViewById(R.id.locale);
- ImageView localized = (ImageView) convertView.findViewById(R.id.l10nWarn);
LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
text.setText(item.getLabel());
- if (item.isTranslated() || mCountryMode) {
- localized.setVisibility(View.GONE);
- text.setTextLocale(item.getLocale());
- } else {
- localized.setVisibility(View.VISIBLE);
- text.setTextLocale(Locale.getDefault());
- }
+ text.setTextLocale(item.getLocale());
if (mCountryMode) {
int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
//noinspection ResourceType
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index f0c10945f746..4e48e45d018e 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -18,6 +18,7 @@ package com.android.internal.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -27,12 +28,13 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.RemoteException;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LocaleList;
import android.util.Pair;
+import android.util.Printer;
import android.util.Slog;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -485,18 +487,29 @@ public class InputMethodUtils {
return NOT_A_SUBTYPE_ID;
}
+ private static final LocaleUtils.LocaleExtractor<InputMethodSubtype> sSubtypeToLocale =
+ new LocaleUtils.LocaleExtractor<InputMethodSubtype>() {
+ @Override
+ public Locale get(InputMethodSubtype source) {
+ return source != null ? source.getLocaleObject() : null;
+ }
+ };
+
@VisibleForTesting
public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
Resources res, InputMethodInfo imi) {
final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
- final String systemLocale = res.getConfiguration().locale.toString();
+ final LocaleList systemLocales = res.getConfiguration().getLocales();
+ final String systemLocale = systemLocales.get(0).toString();
if (TextUtils.isEmpty(systemLocale)) return new ArrayList<>();
- final String systemLanguage = res.getConfiguration().locale.getLanguage();
+ final int numSubtypes = subtypes.size();
+
+ // Handle overridesImplicitlyEnabledSubtype mechanism.
+ final String systemLanguage = systemLocales.get(0).getLanguage();
final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>();
- final int N = subtypes.size();
- for (int i = 0; i < N; ++i) {
+ for (int i = 0; i < numSubtypes; ++i) {
// scan overriding implicitly enabled subtypes.
- InputMethodSubtype subtype = subtypes.get(i);
+ final InputMethodSubtype subtype = subtypes.get(i);
if (subtype.overridesImplicitlyEnabledSubtype()) {
final String mode = subtype.getMode();
if (!applicableModeAndSubtypesMap.containsKey(mode)) {
@@ -507,42 +520,46 @@ public class InputMethodUtils {
if (applicableModeAndSubtypesMap.size() > 0) {
return new ArrayList<>(applicableModeAndSubtypesMap.values());
}
- for (int i = 0; i < N; ++i) {
+
+ final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>();
+ for (int i = 0; i < numSubtypes; ++i) {
final InputMethodSubtype subtype = subtypes.get(i);
- final String locale = subtype.getLocale();
- final String mode = subtype.getMode();
- final String language = getLanguageFromLocaleString(locale);
- // When system locale starts with subtype's locale, that subtype will be applicable
- // for system locale. We need to make sure the languages are the same, to prevent
- // locales like "fil" (Filipino) being matched by "fi" (Finnish).
- //
- // For instance, it's clearly applicable for cases like system locale = en_US and
- // subtype = en, but it is not necessarily considered applicable for cases like system
- // locale = en and subtype = en_US.
- //
- // We just call systemLocale.startsWith(locale) in this function because there is no
- // need to find applicable subtypes aggressively unlike
- // findLastResortApplicableSubtypeLocked.
- //
- // TODO: This check is broken. It won't take scripts into account and doesn't
- // account for the mandatory conversions performed by Locale#toString.
- if (language.equals(systemLanguage) && systemLocale.startsWith(locale)) {
- final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
- // If more applicable subtypes are contained, skip.
- if (applicableSubtype != null) {
- if (systemLocale.equals(applicableSubtype.getLocale())) continue;
- if (!systemLocale.equals(locale)) continue;
+ if (TextUtils.equals(SUBTYPE_MODE_KEYBOARD, subtype.getMode())) {
+ keyboardSubtypes.add(subtype);
+ } else {
+ final Locale locale = subtype.getLocaleObject();
+ final String mode = subtype.getMode();
+ // TODO: Take secondary system locales into consideration.
+ if (locale != null && locale.equals(systemLanguage)) {
+ final InputMethodSubtype applicableSubtype =
+ applicableModeAndSubtypesMap.get(mode);
+ // If more applicable subtypes are contained, skip.
+ if (applicableSubtype != null) {
+ if (systemLocale.equals(applicableSubtype.getLocaleObject())) continue;
+ if (!systemLocale.equals(locale)) continue;
+ }
+ applicableModeAndSubtypesMap.put(mode, subtype);
}
- applicableModeAndSubtypesMap.put(mode, subtype);
}
}
- final InputMethodSubtype keyboardSubtype
- = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD);
- final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>(
- applicableModeAndSubtypesMap.values());
- if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
- for (int i = 0; i < N; ++i) {
- final InputMethodSubtype subtype = subtypes.get(i);
+
+ final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>();
+ LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
+ applicableSubtypes);
+
+ boolean hasAsciiCapableKeyboard = false;
+ final int numApplicationSubtypes = applicableSubtypes.size();
+ for (int i = 0; i < numApplicationSubtypes; ++i) {
+ final InputMethodSubtype subtype = applicableSubtypes.get(i);
+ if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
+ hasAsciiCapableKeyboard = true;
+ break;
+ }
+ }
+ if (!hasAsciiCapableKeyboard) {
+ final int numKeyboardSubtypes = keyboardSubtypes.size();
+ for (int i = 0; i < numKeyboardSubtypes; ++i) {
+ final InputMethodSubtype subtype = keyboardSubtypes.get(i);
final String mode = subtype.getMode();
if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
@@ -550,13 +567,16 @@ public class InputMethodUtils {
}
}
}
- if (keyboardSubtype == null) {
+
+ if (applicableSubtypes.isEmpty()) {
InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
if (lastResortKeyboardSubtype != null) {
applicableSubtypes.add(lastResortKeyboardSubtype);
}
}
+
+ applicableSubtypes.addAll(applicableModeAndSubtypesMap.values());
return applicableSubtypes;
}
@@ -769,7 +789,7 @@ public class InputMethodUtils {
public static ArrayMap<String, ArraySet<String>> parseInputMethodsAndSubtypesString(
@Nullable final String inputMethodsAndSubtypesString) {
- final ArrayMap<String, ArraySet<String>> imeMap = new ArrayMap<String, ArraySet<String>>();
+ final ArrayMap<String, ArraySet<String>> imeMap = new ArrayMap<>();
if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) {
return imeMap;
}
@@ -784,7 +804,7 @@ public class InputMethodUtils {
typeSplitter,
subtypeSplitter);
for (Pair<String, ArrayList<String>> ime : allImeSettings) {
- ArraySet<String> subtypes = new ArraySet<String>();
+ ArraySet<String> subtypes = new ArraySet<>();
if (ime.second != null) {
subtypes.addAll(ime.second);
}
@@ -827,7 +847,14 @@ public class InputMethodUtils {
private final HashMap<String, InputMethodInfo> mMethodMap;
private final ArrayList<InputMethodInfo> mMethodList;
+ /**
+ * On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
+ */
+ private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>();
+
+ private boolean mCopyOnWrite = false;
private String mEnabledInputMethodsStrCache;
+ @UserIdInt
private int mCurrentUserId;
private int[] mCurrentProfileIds = new int[0];
@@ -880,23 +907,85 @@ public class InputMethodUtils {
return imsList;
}
+ @Deprecated
public InputMethodSettings(
Resources res, ContentResolver resolver,
HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
- int userId) {
- setCurrentUserId(userId);
+ @UserIdInt int userId) {
+ this(res, resolver, methodMap, methodList, userId, false /* copyOnWrite */);
+ }
+
+ public InputMethodSettings(
+ Resources res, ContentResolver resolver,
+ HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
+ @UserIdInt int userId, boolean copyOnWrite) {
mRes = res;
mResolver = resolver;
mMethodMap = methodMap;
mMethodList = methodList;
+ switchCurrentUser(userId, copyOnWrite);
}
- public void setCurrentUserId(int userId) {
+ /**
+ * Must be called when the current user is changed.
+ *
+ * @param userId The user ID.
+ * @param copyOnWrite If {@code true}, for each settings key
+ * (e.g. {@link Settings.Secure#ACTION_INPUT_METHOD_SUBTYPE_SETTINGS}) we use the actual
+ * settings on the {@link Settings.Secure} until we do the first write operation.
+ */
+ public void switchCurrentUser(@UserIdInt int userId, boolean copyOnWrite) {
if (DEBUG) {
- Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to " + userId);
+ Slog.d(TAG, "--- Switch the current user from " + mCurrentUserId + " to " + userId);
+ }
+ if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) {
+ mCopyOnWriteDataStore.clear();
+ mEnabledInputMethodsStrCache = "";
+ // TODO: mCurrentProfileIds should be cleared here.
}
- // IMMS settings are kept per user, so keep track of current user
mCurrentUserId = userId;
+ mCopyOnWrite = copyOnWrite;
+ // TODO: mCurrentProfileIds should be updated here.
+ }
+
+ private void putString(final String key, final String str) {
+ if (mCopyOnWrite) {
+ mCopyOnWriteDataStore.put(key, str);
+ } else {
+ Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+ }
+ }
+
+ private String getString(final String key) {
+ if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
+ final String result = mCopyOnWriteDataStore.get(key);
+ return result != null ? result : "";
+ }
+ return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
+ }
+
+ private void putInt(final String key, final int value) {
+ if (mCopyOnWrite) {
+ mCopyOnWriteDataStore.put(key, String.valueOf(value));
+ } else {
+ Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+ }
+ }
+
+ private int getInt(final String key, final int defaultValue) {
+ if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
+ final String result = mCopyOnWriteDataStore.get(key);
+ return result != null ? Integer.valueOf(result) : 0;
+ }
+ return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
+ }
+
+ private void putBoolean(final String key, final boolean value) {
+ putInt(key, value ? 1 : 0);
+ }
+
+ private boolean getBoolean(final String key, final boolean defaultValue) {
+ return getInt(key, defaultValue ? 1 : 0) == 1;
}
public void setCurrentProfileIds(int[] currentProfileIds) {
@@ -915,7 +1004,7 @@ public class InputMethodUtils {
}
}
- public List<InputMethodInfo> getEnabledInputMethodListLocked() {
+ public ArrayList<InputMethodInfo> getEnabledInputMethodListLocked() {
return createEnabledInputMethodListLocked(
getEnabledInputMethodsAndSubtypeListLocked());
}
@@ -1022,7 +1111,7 @@ public class InputMethodUtils {
return isRemoved;
}
- private List<InputMethodInfo> createEnabledInputMethodListLocked(
+ private ArrayList<InputMethodInfo> createEnabledInputMethodListLocked(
List<Pair<String, ArrayList<String>>> imsList) {
final ArrayList<InputMethodInfo> res = new ArrayList<>();
for (Pair<String, ArrayList<String>> ims: imsList) {
@@ -1035,17 +1124,15 @@ public class InputMethodUtils {
}
private void putEnabledInputMethodsStr(String str) {
- Settings.Secure.putStringForUser(
- mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str, mCurrentUserId);
- mEnabledInputMethodsStrCache = str;
if (DEBUG) {
Slog.d(TAG, "putEnabledInputMethodStr: " + str);
}
+ putString(Settings.Secure.ENABLED_INPUT_METHODS, str);
+ mEnabledInputMethodsStrCache = str;
}
public String getEnabledInputMethodsStr() {
- mEnabledInputMethodsStrCache = Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.ENABLED_INPUT_METHODS, mCurrentUserId);
+ mEnabledInputMethodsStrCache = getString(Settings.Secure.ENABLED_INPUT_METHODS);
if (DEBUG) {
Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache
+ ", " + mCurrentUserId);
@@ -1103,8 +1190,7 @@ public class InputMethodUtils {
if (DEBUG) {
Slog.d(TAG, "putSubtypeHistoryStr: " + str);
}
- Settings.Secure.putStringForUser(
- mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str, mCurrentUserId);
+ putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
}
public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
@@ -1222,12 +1308,11 @@ public class InputMethodUtils {
}
private String getSubtypeHistoryStr() {
+ final String history = getString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY);
if (DEBUG) {
- Slog.d(TAG, "getSubtypeHistoryStr: " + Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, mCurrentUserId));
+ Slog.d(TAG, "getSubtypeHistoryStr: " + history);
}
- return Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, mCurrentUserId);
+ return history;
}
public void putSelectedInputMethod(String imeId) {
@@ -1235,8 +1320,7 @@ public class InputMethodUtils {
Slog.d(TAG, "putSelectedInputMethodStr: " + imeId + ", "
+ mCurrentUserId);
}
- Settings.Secure.putStringForUser(
- mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, imeId, mCurrentUserId);
+ putString(Settings.Secure.DEFAULT_INPUT_METHOD, imeId);
}
public void putSelectedSubtype(int subtypeId) {
@@ -1244,18 +1328,15 @@ public class InputMethodUtils {
Slog.d(TAG, "putSelectedInputMethodSubtypeStr: " + subtypeId + ", "
+ mCurrentUserId);
}
- Settings.Secure.putIntForUser(mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
- subtypeId, mCurrentUserId);
+ putInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, subtypeId);
}
public String getSelectedInputMethod() {
+ final String imi = getString(Settings.Secure.DEFAULT_INPUT_METHOD);
if (DEBUG) {
- Slog.d(TAG, "getSelectedInputMethodStr: " + Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, mCurrentUserId)
- + ", " + mCurrentUserId);
+ Slog.d(TAG, "getSelectedInputMethodStr: " + imi);
}
- return Settings.Secure.getStringForUser(
- mResolver, Settings.Secure.DEFAULT_INPUT_METHOD, mCurrentUserId);
+ return imi;
}
public boolean isSubtypeSelected() {
@@ -1263,24 +1344,18 @@ public class InputMethodUtils {
}
private int getSelectedInputMethodSubtypeHashCode() {
- try {
- return Settings.Secure.getIntForUser(
- mResolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, mCurrentUserId);
- } catch (SettingNotFoundException e) {
- return NOT_A_SUBTYPE_ID;
- }
+ return getInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID);
}
public boolean isShowImeWithHardKeyboardEnabled() {
- return Settings.Secure.getIntForUser(mResolver,
- Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mCurrentUserId) == 1;
+ return getBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, false);
}
public void setShowImeWithHardKeyboard(boolean show) {
- Settings.Secure.putIntForUser(mResolver, Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
- show ? 1 : 0, mCurrentUserId);
+ putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show);
}
+ @UserIdInt
public int getCurrentUserId() {
return mCurrentUserId;
}
@@ -1315,6 +1390,13 @@ public class InputMethodUtils {
}
return enabledInputMethodAndSubtypes;
}
+
+ public void dumpLocked(final Printer pw, final String prefix) {
+ pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+ pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds));
+ pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite);
+ pw.println(prefix + "mEnabledInputMethodsStrCache=" + mEnabledInputMethodsStrCache);
+ }
}
// For spell checker service manager.
diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java
new file mode 100644
index 000000000000..99bb4cbea14a
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/LocaleUtils.java
@@ -0,0 +1,142 @@
+/*
+ * 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.inputmethod;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.LocaleList;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+public final class LocaleUtils {
+
+ @VisibleForTesting
+ public interface LocaleExtractor<T> {
+ @Nullable
+ Locale get(@Nullable T source);
+ }
+
+ @Nullable
+ private static String getLanguage(@Nullable Locale locale) {
+ if (locale == null) {
+ return null;
+ }
+ return locale.getLanguage();
+ }
+
+ /**
+ * Filters the given items based on language preferences.
+ *
+ * <p>For each language found in {@code preferredLanguages}, this method tries to copy at most
+ * one best-match item from {@code source} to {@code dest}. For example, if
+ * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLanguages},
+ * this method tries to copy at most one English locale, at most one Japanese, and at most one
+ * French locale from {@code source} to {@code dest}. Here the best matching English locale
+ * will be searched from {@code source} as follows.
+ * <ol>
+ * <li>The first instance in {@code sources} that exactly matches {@code "en-GB"}</li>
+ * <li>The first instance in {@code sources} that exactly matches {@code "en-AU"}</li>
+ * <li>The first instance in {@code sources} that exactly matches {@code "en-IN"}</li>
+ * <li>The first instance in {@code sources} that partially matches {@code "en"}</li>
+ * </ol>
+ * <p>Then this method iterates the same algorithm for Japanese then French.</p>
+ *
+ * @param sources Source items to be filtered.
+ * @param extractor Type converter from the source items to {@link Locale} object.
+ * @param preferredLanguages Ordered list of locales with which the input items will be
+ * filtered.
+ * @param dest Destination into which the filtered items will be added.
+ * @param <T> Type of the data items.
+ */
+ @VisibleForTesting
+ public static <T> void filterByLanguage(
+ @NonNull List<T> sources,
+ @NonNull LocaleExtractor<T> extractor,
+ @NonNull LocaleList preferredLanguages,
+ @NonNull ArrayList<T> dest) {
+ final Locale[] availableLocales = new Locale[sources.size()];
+ for (int i = 0; i < availableLocales.length; ++i) {
+ availableLocales[i] = extractor.get(sources.get(i));
+ }
+ final Locale[] sortedPreferredLanguages = new Locale[preferredLanguages.size()];
+ if (sortedPreferredLanguages.length > 0) {
+ int nextIndex = 0;
+ final int N = preferredLanguages.size();
+ languageLoop:
+ for (int i = 0; i < N; ++i) {
+ final String language = getLanguage(preferredLanguages.get(i));
+ for (int j = 0; j < nextIndex; ++j) {
+ if (TextUtils.equals(getLanguage(sortedPreferredLanguages[j]), language)) {
+ continue languageLoop;
+ }
+ }
+ for (int j = i; j < N; ++j) {
+ final Locale locale = preferredLanguages.get(j);
+ if (TextUtils.equals(language, getLanguage(locale))) {
+ sortedPreferredLanguages[nextIndex] = locale;
+ ++nextIndex;
+ }
+ }
+ }
+ }
+
+
+ for (int languageIndex = 0; languageIndex < sortedPreferredLanguages.length;) {
+ // Finding the range.
+ final String language = getLanguage(sortedPreferredLanguages[languageIndex]);
+ int nextLanguageIndex = languageIndex;
+ for (; nextLanguageIndex < sortedPreferredLanguages.length; ++nextLanguageIndex) {
+ final Locale locale = sortedPreferredLanguages[nextLanguageIndex];
+ if (!TextUtils.equals(getLanguage(locale), language)) {
+ break;
+ }
+ }
+
+ // Check exact match
+ boolean found = false;
+ for (int i = languageIndex; !found && i < nextLanguageIndex; ++i) {
+ final Locale locale = sortedPreferredLanguages[i];
+ for (int j = 0; j < availableLocales.length; ++j) {
+ if (!Objects.equals(locale, availableLocales[j])) {
+ continue;
+ }
+ dest.add(sources.get(j));
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // No exact match. Use language match.
+ for (int j = 0; j < availableLocales.length; ++j) {
+ if (!TextUtils.equals(language, getLanguage(availableLocales[j]))) {
+ continue;
+ }
+ dest.add(sources.get(j));
+ break;
+ }
+ }
+ languageIndex = nextLanguageIndex;
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 648b1a54927d..60c9e14c1d0c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -93,7 +93,7 @@ import java.util.concurrent.locks.ReentrantLock;
* battery life. All times are represented in microseconds except where indicated
* otherwise.
*/
-public final class BatteryStatsImpl extends BatteryStats {
+public class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
@@ -126,6 +126,8 @@ public final class BatteryStatsImpl extends BatteryStats {
// Number of transmit power states the Bluetooth controller can be in.
private static final int NUM_BT_TX_LEVELS = 1;
+ protected Clocks mClocks;
+
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
@@ -185,6 +187,21 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public interface Clocks {
+ public long elapsedRealtime();
+ public long uptimeMillis();
+ }
+
+ public static class SystemClocks implements Clocks {
+ public long elapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ public long uptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+ }
+
public interface ExternalStatsSync {
public static final int UPDATE_CPU = 0x01;
public static final int UPDATE_WIFI = 0x02;
@@ -236,7 +253,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// These are the objects that will want to do something when the device
// is unplugged from power.
- final TimeBase mOnBatteryTimeBase = new TimeBase();
+ protected final TimeBase mOnBatteryTimeBase = new TimeBase();
// These are the objects that will want to do something when the device
// is unplugged from power *and* the screen is off.
@@ -541,6 +558,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public BatteryStatsImpl() {
+ this(new SystemClocks());
+ }
+
+ public BatteryStatsImpl(Clocks clocks) {
+ init(clocks);
mFile = null;
mCheckinFile = null;
mDailyFile = null;
@@ -549,25 +571,40 @@ public final class BatteryStatsImpl extends BatteryStats {
clearHistoryLocked();
}
+ private void init(Clocks clocks) {
+ mClocks = clocks;
+ mMobileNetworkStats = new NetworkStats[] {
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50)
+ };
+ mWifiNetworkStats = new NetworkStats[] {
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50),
+ new NetworkStats(mClocks.elapsedRealtime(), 50)
+ };
+ }
+
public static interface TimeBaseObs {
void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime);
void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime);
}
- static class TimeBase {
- private final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
+ // methods are protected not private to be VisibleForTesting
+ public static class TimeBase {
+ protected final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
- private long mUptime;
- private long mRealtime;
+ protected long mUptime;
+ protected long mRealtime;
- private boolean mRunning;
+ protected boolean mRunning;
- private long mPastUptime;
- private long mUptimeStart;
- private long mPastRealtime;
- private long mRealtimeStart;
- private long mUnpluggedUptime;
- private long mUnpluggedRealtime;
+ protected long mPastUptime;
+ protected long mUptimeStart;
+ protected long mPastRealtime;
+ protected long mRealtimeStart;
+ protected long mUnpluggedUptime;
+ protected long mUnpluggedRealtime;
public void dump(PrintWriter pw, String prefix) {
StringBuilder sb = new StringBuilder(128);
@@ -608,6 +645,10 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public boolean hasObserver(TimeBaseObs observer) {
+ return mObservers.contains(observer);
+ }
+
public void init(long uptime, long realtime) {
mRealtime = 0;
mUptime = 0;
@@ -626,7 +667,10 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
mUptimeStart = uptime;
mRealtimeStart = realtime;
+ // TODO: Since mUptimeStart was just reset and we are running, getUptime will
+ // just return mPastUptime. Also, are we sure we don't want to reset that?
mUnpluggedUptime = getUptime(uptime);
+ // TODO: likewise.
mUnpluggedRealtime = getRealtime(realtime);
}
}
@@ -949,13 +993,14 @@ public final class BatteryStatsImpl extends BatteryStats {
* State for keeping track of timing information.
*/
public static abstract class Timer extends BatteryStats.Timer implements TimeBaseObs {
- final int mType;
- final TimeBase mTimeBase;
+ protected final Clocks mClocks;
+ protected final int mType;
+ protected final TimeBase mTimeBase;
- int mCount;
- int mLoadedCount;
- int mLastCount;
- int mUnpluggedCount;
+ protected int mCount;
+ protected int mLoadedCount;
+ protected int mLastCount;
+ protected int mUnpluggedCount;
// Times are in microseconds for better accuracy when dividing by the
// lock count, and are in "battery realtime" units.
@@ -965,32 +1010,32 @@ public final class BatteryStatsImpl extends BatteryStats {
* boot, to the last time something interesting happened in the
* current run.
*/
- long mTotalTime;
+ protected long mTotalTime;
/**
* The total time we loaded for the previous runs. Subtract this from
* mTotalTime to find the time for the current run of the system.
*/
- long mLoadedTime;
+ protected long mLoadedTime;
/**
* The run time of the last run of the system, as loaded from the
* saved data.
*/
- long mLastTime;
+ protected long mLastTime;
/**
* The value of mTotalTime when unplug() was last called. Subtract
* this from mTotalTime to find the time since the last unplug from
* power.
*/
- long mUnpluggedTime;
+ protected long mUnpluggedTime;
/**
* The total time this timer has been running until the latest mark has been set.
* Subtract this from mTotalTime to get the time spent running since the mark was set.
*/
- long mTimeBeforeMark;
+ protected long mTimeBeforeMark;
/**
* Constructs from a parcel.
@@ -998,7 +1043,8 @@ public final class BatteryStatsImpl extends BatteryStats {
* @param timeBase
* @param in
*/
- Timer(int type, TimeBase timeBase, Parcel in) {
+ public Timer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
+ mClocks = clocks;
mType = type;
mTimeBase = timeBase;
@@ -1015,7 +1061,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
}
- Timer(int type, TimeBase timeBase) {
+ public Timer(Clocks clocks, int type, TimeBase timeBase) {
+ mClocks = clocks;
mType = type;
mTimeBase = timeBase;
timeBase.add(this);
@@ -1029,7 +1076,7 @@ public final class BatteryStatsImpl extends BatteryStats {
* Clear state of this timer. Returns true if the timer is inactive
* so can be completely dropped.
*/
- boolean reset(boolean detachIfReset) {
+ public boolean reset(boolean detachIfReset) {
mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0;
mCount = mLoadedCount = mLastCount = 0;
if (detachIfReset) {
@@ -1038,7 +1085,7 @@ public final class BatteryStatsImpl extends BatteryStats {
return true;
}
- void detach() {
+ public void detach() {
mTimeBase.remove(this);
}
@@ -1142,13 +1189,13 @@ public final class BatteryStatsImpl extends BatteryStats {
}
- void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+ public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
long runTime = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
out.writeLong(runTime);
out.writeInt(mCount);
}
- void readSummaryFromParcelLocked(Parcel in) {
+ public void readSummaryFromParcelLocked(Parcel in) {
// Multiply by 1000 for backwards compatibility
mTotalTime = mLoadedTime = in.readLong();
mLastTime = 0;
@@ -1162,7 +1209,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public static final class SamplingTimer extends Timer {
+ public static class SamplingTimer extends Timer {
/**
* The most recent reported count from /proc/wakelocks.
@@ -1202,8 +1249,8 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
int mUpdateVersion;
- SamplingTimer(TimeBase timeBase, Parcel in) {
- super(0, timeBase, in);
+ SamplingTimer(Clocks clocks, TimeBase timeBase, Parcel in) {
+ super(clocks, 0, timeBase, in);
mCurrentReportedCount = in.readInt();
mUnpluggedReportedCount = in.readInt();
mCurrentReportedTotalTime = in.readLong();
@@ -1212,8 +1259,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mTimeBaseRunning = timeBase.isRunning();
}
- SamplingTimer(TimeBase timeBase, boolean trackReportedValues) {
- super(0, timeBase);
+ SamplingTimer(Clocks clocks, TimeBase timeBase, boolean trackReportedValues) {
+ super(clocks, 0, timeBase);
mTrackingReportedValues = trackReportedValues;
mTimeBaseRunning = timeBase.isRunning();
}
@@ -1301,20 +1348,20 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
- boolean reset(boolean detachIfReset) {
+ public boolean reset(boolean detachIfReset) {
super.reset(detachIfReset);
setStale();
return true;
}
- void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
+ public void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
super.writeSummaryFromParcelLocked(out, batteryRealtime);
out.writeLong(mCurrentReportedTotalTime);
out.writeInt(mCurrentReportedCount);
out.writeInt(mTrackingReportedValues ? 1 : 0);
}
- void readSummaryFromParcelLocked(Parcel in) {
+ public void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
@@ -1326,7 +1373,7 @@ public final class BatteryStatsImpl extends BatteryStats {
* A timer that increments in batches. It does not run for durations, but just jumps
* for a pre-determined amount.
*/
- public static final class BatchTimer extends Timer {
+ public static class BatchTimer extends Timer {
final Uid mUid;
/**
@@ -1344,16 +1391,16 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
boolean mInDischarge;
- BatchTimer(Uid uid, int type, TimeBase timeBase, Parcel in) {
- super(type, timeBase, in);
+ BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase, Parcel in) {
+ super(clocks, type, timeBase, in);
mUid = uid;
mLastAddedTime = in.readLong();
mLastAddedDuration = in.readLong();
mInDischarge = timeBase.isRunning();
}
- BatchTimer(Uid uid, int type, TimeBase timeBase) {
- super(type, timeBase);
+ BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase) {
+ super(clocks, type, timeBase);
mUid = uid;
mInDischarge = timeBase.isRunning();
}
@@ -1367,7 +1414,7 @@ public final class BatteryStatsImpl extends BatteryStats {
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
- recomputeLastDuration(SystemClock.elapsedRealtime() * 1000, false);
+ recomputeLastDuration(mClocks.elapsedRealtime() * 1000, false);
mInDischarge = false;
super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
}
@@ -1416,7 +1463,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void addDuration(BatteryStatsImpl stats, long durationMillis) {
- final long now = SystemClock.elapsedRealtime() * 1000;
+ final long now = mClocks.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
mLastAddedTime = now;
mLastAddedDuration = durationMillis * 1000;
@@ -1427,7 +1474,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void abortLastDuration(BatteryStatsImpl stats) {
- final long now = SystemClock.elapsedRealtime() * 1000;
+ final long now = mClocks.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
}
@@ -1438,7 +1485,7 @@ public final class BatteryStatsImpl extends BatteryStats {
@Override
protected long computeRunTimeLocked(long curBatteryRealtime) {
- final long overage = computeOverage(SystemClock.elapsedRealtime() * 1000);
+ final long overage = computeOverage(mClocks.elapsedRealtime() * 1000);
if (overage > 0) {
return mTotalTime = overage;
}
@@ -1446,8 +1493,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- boolean reset(boolean detachIfReset) {
- final long now = SystemClock.elapsedRealtime() * 1000;
+ public boolean reset(boolean detachIfReset) {
+ final long now = mClocks.elapsedRealtime() * 1000;
recomputeLastDuration(now, true);
boolean stillActive = mLastAddedTime == now;
super.reset(!stillActive && detachIfReset);
@@ -1458,7 +1505,7 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* State for keeping track of timing information.
*/
- public static final class StopwatchTimer extends Timer {
+ public static class StopwatchTimer extends Timer {
final Uid mUid;
final ArrayList<StopwatchTimer> mTimerPool;
@@ -1485,22 +1532,22 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
boolean mInList;
- StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase, Parcel in) {
- super(type, timeBase, in);
+ super(clocks, type, timeBase, in);
mUid = uid;
mTimerPool = timerPool;
mUpdateTime = in.readLong();
}
- StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
TimeBase timeBase) {
- super(type, timeBase);
+ super(clocks, type, timeBase);
mUid = uid;
mTimerPool = timerPool;
}
- void setTimeout(long timeout) {
+ public void setTimeout(long timeout) {
mTimeout = timeout;
}
@@ -1528,7 +1575,7 @@ public final class BatteryStatsImpl extends BatteryStats {
+ " mAcquireTime=" + mAcquireTime);
}
- void startRunningLocked(long elapsedRealtimeMs) {
+ public void startRunningLocked(long elapsedRealtimeMs) {
if (mNesting++ == 0) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
mUpdateTime = batteryRealtime;
@@ -1550,11 +1597,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- boolean isRunningLocked() {
+ public boolean isRunningLocked() {
return mNesting > 0;
}
- void stopRunningLocked(long elapsedRealtimeMs) {
+ public void stopRunningLocked(long elapsedRealtimeMs) {
// Ignore attempt to stop a timer that isn't running
if (mNesting == 0) {
return;
@@ -1587,7 +1634,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- void stopAllRunningLocked(long elapsedRealtimeMs) {
+ public void stopAllRunningLocked(long elapsedRealtimeMs) {
if (mNesting > 0) {
mNesting = 1;
stopRunningLocked(elapsedRealtimeMs);
@@ -1632,18 +1679,18 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- boolean reset(boolean detachIfReset) {
+ public boolean reset(boolean detachIfReset) {
boolean canDetach = mNesting <= 0;
super.reset(canDetach && detachIfReset);
if (mNesting > 0) {
- mUpdateTime = mTimeBase.getRealtime(SystemClock.elapsedRealtime() * 1000);
+ mUpdateTime = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000);
}
mAcquireTime = mTotalTime;
return canDetach;
}
@Override
- void detach() {
+ public void detach() {
super.detach();
if (mTimerPool != null) {
mTimerPool.remove(this);
@@ -1651,7 +1698,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- void readSummaryFromParcelLocked(Parcel in) {
+ public void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mNesting = 0;
}
@@ -1943,7 +1990,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public SamplingTimer getWakeupReasonTimerLocked(String name) {
SamplingTimer timer = mWakeupReasonStats.get(name);
if (timer == null) {
- timer = new SamplingTimer(mOnBatteryTimeBase, true);
+ timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, true);
mWakeupReasonStats.put(name, timer);
}
return timer;
@@ -1956,7 +2003,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public SamplingTimer getKernelWakelockTimerLocked(String name) {
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
- kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, true /* track reported values */);
+ kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
+ true /* track reported values */);
mKernelWakelockStats.put(name, kwlt);
}
return kwlt;
@@ -2729,8 +2777,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mActiveEvents.updateState(code, name, uid, 0)) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
}
@@ -2740,7 +2788,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// If the start clock time has changed by more than a year, then presumably
// the previous time was completely bogus. So we are going to figure out a
// new time based on how much time has elapsed since we started counting.
- mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000));
+ mStartClockTime = currentTime - (mClocks.elapsedRealtime()-(mRealtimeStart/1000));
return true;
}
return false;
@@ -2748,8 +2796,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteCurrentTimeChangedLocked() {
final long currentTime = System.currentTimeMillis();
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
ensureStartClockTime(currentTime);
}
@@ -2766,8 +2814,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mRecordAllHistory) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
}
@@ -2800,15 +2848,15 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mRecordAllHistory) {
return;
}
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
}
public void noteSyncStartLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStartSyncLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) {
return;
@@ -2818,8 +2866,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteSyncFinishLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStopSyncLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) {
return;
@@ -2829,8 +2877,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteJobStartLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStartJobLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) {
return;
@@ -2840,8 +2888,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteJobFinishLocked(String name, int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
getUidStatsLocked(uid).noteStopJobLocked(name, elapsedRealtime);
if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) {
return;
@@ -2854,8 +2902,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
return;
}
@@ -2867,8 +2915,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
return;
}
@@ -2898,8 +2946,8 @@ public final class BatteryStatsImpl extends BatteryStats {
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
- long mSecRealtime = SystemClock.elapsedRealtime();
- final long mSecUptime = SystemClock.uptimeMillis();
+ long mSecRealtime = mClocks.elapsedRealtime();
+ final long mSecUptime = mClocks.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
@@ -2913,8 +2961,8 @@ public final class BatteryStatsImpl extends BatteryStats {
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
HistoryItem.EVENT_PROC);
if (active != null) {
- long mSecRealtime = SystemClock.elapsedRealtime();
- final long mSecUptime = SystemClock.uptimeMillis();
+ long mSecRealtime = mClocks.elapsedRealtime();
+ final long mSecUptime = mClocks.uptimeMillis();
for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
@@ -3023,8 +3071,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, boolean unimportantForLogging) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging,
@@ -3035,8 +3083,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type, WorkSource newWs, int newPid, String newName,
String newHistoryName, int newType, boolean newUnimportantForLogging) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
// For correct semantics, we start the need worksources first, so that we won't
// make inappropriate history items as if all wake locks went away and new ones
// appeared. This is okay because tracking of wake locks allows nesting.
@@ -3053,8 +3101,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
String historyName, int type) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
@@ -3072,8 +3120,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteWakeupReasonLocked(String reason) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": "
+ Integer.toHexString(mHistoryCur.states));
aggregateLastWakeupUptimeLocked(uptime);
@@ -3147,8 +3195,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteStartSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mSensorNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
@@ -3161,8 +3209,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteStopSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mSensorNesting--;
if (mSensorNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
@@ -3177,8 +3225,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteStartGpsLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -3191,8 +3239,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteStopGpsLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -3223,8 +3271,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (state == Display.STATE_ON) {
// Screen turning on.
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3235,7 +3283,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
- SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
@@ -3248,8 +3296,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
} else if (oldState == Display.STATE_ON) {
// Screen turning off or dozing.
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3263,7 +3311,7 @@ public final class BatteryStatsImpl extends BatteryStats {
elapsedRealtime, uptime);
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
- SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
// Update discharge amounts.
if (mOnBatteryInternal) {
@@ -3279,8 +3327,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (bin < 0) bin = 0;
else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
if (mScreenBrightnessBin != bin) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
| (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
@@ -3304,15 +3352,15 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteWakeUpLocked(String reason, int reasonUid) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SCREEN_WAKE_UP,
reason, reasonUid);
}
public void noteInteractiveLocked(boolean interactive) {
if (mInteractive != interactive) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
mInteractive = interactive;
if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
if (interactive) {
@@ -3324,16 +3372,16 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteConnectivityChangedLocked(int type, String extra) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
extra, type);
mNumConnectivityChange++;
}
public void noteMobileRadioPowerState(int powerState, long timestampNs) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mMobileRadioPowerState != powerState) {
long realElapsedRealtimeMs;
final boolean active =
@@ -3375,8 +3423,8 @@ public final class BatteryStatsImpl extends BatteryStats {
int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mPowerSaveModeEnabled = enabled;
if (enabled) {
mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
@@ -3394,8 +3442,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteDeviceIdleModeLocked(int mode, String activeReason, int activeUid) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
boolean nowIdling = mode == DEVICE_IDLE_MODE_FULL;
if (mDeviceIdling && !nowIdling && activeReason == null) {
// We don't go out of general idling mode until explicitly taken out of
@@ -3460,8 +3508,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void notePackageInstalledLocked(String pkgName, int versionCode) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
pkgName, versionCode);
PackageChange pc = new PackageChange();
@@ -3472,8 +3520,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void notePackageUninstalledLocked(String pkgName) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
pkgName, 0);
PackageChange pc = new PackageChange();
@@ -3491,8 +3539,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void notePhoneOnLocked() {
if (!mPhoneOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3504,8 +3552,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void notePhoneOffLocked() {
if (mPhoneOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3516,7 +3564,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void stopAllPhoneSignalStrengthTimersLocked(int except) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
@@ -3548,8 +3596,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mPhoneSimStateRaw = simState;
mPhoneSignalStrengthBinRaw = strengthBin;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (simState == TelephonyManager.SIM_STATE_ABSENT) {
// In this case we will always be STATE_OUT_OF_SERVICE, so need
@@ -3697,8 +3745,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
| (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
@@ -3715,8 +3763,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiOnLocked() {
if (!mWifiOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -3728,8 +3776,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteWifiOffLocked() {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiOn) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
@@ -3743,8 +3791,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteAudioOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mAudioOnNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
@@ -3761,8 +3809,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mAudioOnNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -3775,8 +3823,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteVideoOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mVideoOnNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
@@ -3793,8 +3841,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mVideoOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -3807,8 +3855,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteResetAudioLocked() {
if (mAudioOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mAudioOnNesting = 0;
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -3824,8 +3872,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteResetVideoLocked() {
if (mVideoOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mAudioOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -3841,12 +3889,12 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteActivityResumedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteActivityResumedLocked(SystemClock.elapsedRealtime());
+ getUidStatsLocked(uid).noteActivityResumedLocked(mClocks.elapsedRealtime());
}
public void noteActivityPausedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteActivityPausedLocked(SystemClock.elapsedRealtime());
+ getUidStatsLocked(uid).noteActivityPausedLocked(mClocks.elapsedRealtime());
}
public void noteVibratorOnLocked(int uid, long durationMillis) {
@@ -3861,8 +3909,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteFlashlightOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mFlashlightOnNesting++ == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
@@ -3878,8 +3926,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mFlashlightOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
@@ -3892,8 +3940,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteCameraOnLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mCameraOnNesting++ == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: "
@@ -3909,8 +3957,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (--mCameraOnNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
@@ -3923,8 +3971,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteResetCameraLocked() {
if (mCameraOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mCameraOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
@@ -3940,8 +3988,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteResetFlashlightLocked() {
if (mFlashlightOnNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mFlashlightOnNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
@@ -4015,8 +4063,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteWifiRadioPowerState(int powerState, long timestampNs) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiRadioPowerState != powerState) {
final boolean active =
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
@@ -4035,8 +4083,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -4056,7 +4104,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
if (mGlobalWifiRunning) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
int N = oldWs.size();
for (int i=0; i<N; i++) {
int uid = mapUid(oldWs.get(i));
@@ -4074,8 +4122,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiStoppedLocked(WorkSource ws) {
if (mGlobalWifiRunning) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
+ Integer.toHexString(mHistoryCur.states));
@@ -4096,7 +4144,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiStateLocked(int wifiState, String accessPoint) {
if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
if (mWifiState != wifiState) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
if (mWifiState >= 0) {
mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
}
@@ -4109,8 +4157,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
if (mWifiSupplState != supplState) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiSupplState >= 0) {
mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
}
@@ -4126,7 +4174,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void stopAllWifiSignalStrengthTimersLocked(int except) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
@@ -4141,8 +4189,8 @@ public final class BatteryStatsImpl extends BatteryStats {
int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
if (mWifiSignalStrengthBin != strengthBin) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiSignalStrengthBin >= 0) {
mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
elapsedRealtime);
@@ -4168,8 +4216,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteFullWifiLockAcquiredLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiFullLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
@@ -4182,8 +4230,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteFullWifiLockReleasedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mWifiFullLockNesting--;
if (mWifiFullLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
@@ -4198,8 +4246,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiScanStartedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiScanNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
@@ -4212,8 +4260,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiScanStoppedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mWifiScanNesting--;
if (mWifiScanNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
@@ -4226,13 +4274,13 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
}
public void noteWifiBatchedScanStoppedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
}
@@ -4240,8 +4288,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiMulticastEnabledLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mWifiMulticastNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
@@ -4254,8 +4302,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWifiMulticastDisabledLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mWifiMulticastNesting--;
if (mWifiMulticastNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
@@ -4369,7 +4417,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// During device boot, qtaguid isn't enabled until after the inital
// loading of battery stats. Now that they're enabled, take our initial
// snapshot for future delta calculation.
- updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), null);
+ updateMobileRadioStateLocked(mClocks.elapsedRealtime(), null);
updateWifiStateLocked(null);
}
@@ -4623,8 +4671,8 @@ public final class BatteryStatsImpl extends BatteryStats {
@Override public long getStartClockTime() {
final long currentTime = System.currentTimeMillis();
if (ensureStartClockTime(currentTime)) {
- recordCurrentTimeChangeLocked(currentTime, SystemClock.elapsedRealtime(),
- SystemClock.uptimeMillis());
+ recordCurrentTimeChangeLocked(currentTime, mClocks.elapsedRealtime(),
+ mClocks.uptimeMillis());
}
return mStartClockTime;
}
@@ -4652,7 +4700,11 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* The statistics associated with a particular uid.
*/
- public final class Uid extends BatteryStats.Uid {
+ public static class Uid extends BatteryStats.Uid {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
final int mUid;
@@ -4717,35 +4769,25 @@ public final class BatteryStatsImpl extends BatteryStats {
long mCurStepUserTime;
long mCurStepSystemTime;
- LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
- LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
- LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase);
+ LongSamplingCounter mUserCpuTime;
+ LongSamplingCounter mSystemCpuTime;
+ LongSamplingCounter mCpuPower;
LongSamplingCounter[][] mCpuClusterSpeed;
/**
* The statistics we have collected for this uid's wake locks.
*/
- final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
- @Override public Wakelock instantiateObject() { return new Wakelock(); }
- };
+ final OverflowArrayMap<Wakelock> mWakelockStats;
/**
* The statistics we have collected for this uid's syncs.
*/
- final OverflowArrayMap<StopwatchTimer> mSyncStats = new OverflowArrayMap<StopwatchTimer>() {
- @Override public StopwatchTimer instantiateObject() {
- return new StopwatchTimer(Uid.this, SYNC, null, mOnBatteryTimeBase);
- }
- };
+ final OverflowArrayMap<StopwatchTimer> mSyncStats;
/**
* The statistics we have collected for this uid's jobs.
*/
- final OverflowArrayMap<StopwatchTimer> mJobStats = new OverflowArrayMap<StopwatchTimer>() {
- @Override public StopwatchTimer instantiateObject() {
- return new StopwatchTimer(Uid.this, JOB, null, mOnBatteryTimeBase);
- }
- };
+ final OverflowArrayMap<StopwatchTimer> mJobStats;
/**
* The statistics we have collected for this uid's sensor activations.
@@ -4767,17 +4809,41 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
final SparseArray<Pid> mPids = new SparseArray<>();
- public Uid(int uid) {
+ public Uid(BatteryStatsImpl bsi, int uid) {
+ mBsi = bsi;
mUid = uid;
- mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
- mWifiRunningTimers, mOnBatteryTimeBase);
- mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
- mFullWifiLockTimers, mOnBatteryTimeBase);
- mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
- mWifiScanTimers, mOnBatteryTimeBase);
+
+ mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+
+ mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>() {
+ @Override public Wakelock instantiateObject() {
+ return new Wakelock(mBsi, Uid.this);
+ }
+ };
+ mSyncStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+ @Override public StopwatchTimer instantiateObject() {
+ return new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null,
+ mBsi.mOnBatteryTimeBase);
+ }
+ };
+ mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+ @Override public StopwatchTimer instantiateObject() {
+ return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
+ mBsi.mOnBatteryTimeBase);
+ }
+ };
+
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_RUNNING,
+ mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, this, FULL_WIFI_LOCK,
+ mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
+ mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
- mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
- mWifiMulticastTimers, mOnBatteryTimeBase);
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_MULTICAST_ENABLED,
+ mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
}
@@ -4821,8 +4887,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mWifiRunning) {
mWifiRunning = true;
if (mWifiRunningTimer == null) {
- mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
- mWifiRunningTimers, mOnBatteryTimeBase);
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+ mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
}
mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4841,8 +4907,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mFullWifiLockOut) {
mFullWifiLockOut = true;
if (mFullWifiLockTimer == null) {
- mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
- mFullWifiLockTimers, mOnBatteryTimeBase);
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+ mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
}
mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4861,8 +4927,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mWifiScanStarted) {
mWifiScanStarted = true;
if (mWifiScanTimer == null) {
- mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
- mWifiScanTimers, mOnBatteryTimeBase);
+ mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
}
mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4911,8 +4977,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mWifiMulticastEnabled) {
mWifiMulticastEnabled = true;
if (mWifiMulticastTimer == null) {
- mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
- mWifiMulticastTimers, mOnBatteryTimeBase);
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
}
mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -4943,7 +5009,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
if (mWifiControllerActivity == null) {
- mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
}
return mWifiControllerActivity;
@@ -4951,7 +5017,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
if (mBluetoothControllerActivity == null) {
- mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
}
return mBluetoothControllerActivity;
@@ -4959,7 +5025,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
- mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS);
}
return mModemControllerActivity;
@@ -4967,8 +5033,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public StopwatchTimer createAudioTurnedOnTimerLocked() {
if (mAudioTurnedOnTimer == null) {
- mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
- mAudioTurnedOnTimers, mOnBatteryTimeBase);
+ mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+ mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mAudioTurnedOnTimer;
}
@@ -4991,8 +5057,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public StopwatchTimer createVideoTurnedOnTimerLocked() {
if (mVideoTurnedOnTimer == null) {
- mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
- mVideoTurnedOnTimers, mOnBatteryTimeBase);
+ mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+ mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mVideoTurnedOnTimer;
}
@@ -5015,8 +5081,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public StopwatchTimer createFlashlightTurnedOnTimerLocked() {
if (mFlashlightTurnedOnTimer == null) {
- mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
- mFlashlightTurnedOnTimers, mOnBatteryTimeBase);
+ mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mFlashlightTurnedOnTimer;
}
@@ -5039,8 +5105,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public StopwatchTimer createCameraTurnedOnTimerLocked() {
if (mCameraTurnedOnTimer == null) {
- mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
- mCameraTurnedOnTimers, mOnBatteryTimeBase);
+ mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+ mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase);
}
return mCameraTurnedOnTimer;
}
@@ -5063,16 +5129,16 @@ public final class BatteryStatsImpl extends BatteryStats {
public StopwatchTimer createForegroundActivityTimerLocked() {
if (mForegroundActivityTimer == null) {
- mForegroundActivityTimer = new StopwatchTimer(
- Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase);
+ mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase);
}
return mForegroundActivityTimer;
}
public StopwatchTimer createBluetoothScanTimerLocked() {
if (mBluetoothScanTimer == null) {
- mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
- mBluetoothScanOnTimers, mOnBatteryTimeBase);
+ mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase);
}
return mBluetoothScanTimer;
}
@@ -5108,18 +5174,19 @@ public final class BatteryStatsImpl extends BatteryStats {
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
- mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase);
+ mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+ mBsi.mOnBatteryTimeBase);
}
return mVibratorOnTimer;
}
public void noteVibratorOnLocked(long durationMillis) {
- createVibratorOnTimerLocked().addDuration(BatteryStatsImpl.this, durationMillis);
+ createVibratorOnTimerLocked().addDuration(mBsi, durationMillis);
}
public void noteVibratorOffLocked() {
if (mVibratorOnTimer != null) {
- mVibratorOnTimer.abortLastDuration(BatteryStatsImpl.this);
+ mVibratorOnTimer.abortLastDuration(mBsi);
}
}
@@ -5215,11 +5282,11 @@ public final class BatteryStatsImpl extends BatteryStats {
if (i < 0 || i >= NUM_PROCESS_STATE) return;
if (in == null) {
- mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
- mOnBatteryTimeBase);
+ mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+ mBsi.mOnBatteryTimeBase);
} else {
- mProcessStateTimer[i] = new StopwatchTimer(this, PROCESS_STATE, null,
- mOnBatteryTimeBase, in);
+ mProcessStateTimer[i] = new StopwatchTimer(mBsi.mClocks, this, PROCESS_STATE, null,
+ mBsi.mOnBatteryTimeBase, in);
}
}
@@ -5266,17 +5333,17 @@ public final class BatteryStatsImpl extends BatteryStats {
void makeWifiBatchedScanBin(int i, Parcel in) {
if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
- ArrayList<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
+ ArrayList<StopwatchTimer> collected = mBsi.mWifiBatchedScanTimers.get(i);
if (collected == null) {
collected = new ArrayList<StopwatchTimer>();
- mWifiBatchedScanTimers.put(i, collected);
+ mBsi.mWifiBatchedScanTimers.put(i, collected);
}
if (in == null) {
- mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
- mOnBatteryTimeBase);
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+ collected, mBsi.mOnBatteryTimeBase);
} else {
- mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
- mOnBatteryTimeBase, in);
+ mWifiBatchedScanTimer[i] = new StopwatchTimer(mBsi.mClocks, this, WIFI_BATCHED_SCAN,
+ collected, mBsi.mOnBatteryTimeBase, in);
}
}
@@ -5284,7 +5351,7 @@ public final class BatteryStatsImpl extends BatteryStats {
void initUserActivityLocked() {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
- mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase);
+ mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase);
}
}
@@ -5383,11 +5450,11 @@ public final class BatteryStatsImpl extends BatteryStats {
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
- mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
- mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+ mNetworkByteActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
}
- mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase);
- mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase);
+ mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
}
/**
@@ -5475,12 +5542,12 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiControllerActivity.reset(false);
}
- if (mBluetoothActivity != null) {
- mBluetoothActivity.reset(false);
+ if (mBsi.mBluetoothActivity != null) {
+ mBsi.mBluetoothActivity.reset(false);
}
- if (mModemActivity != null) {
- mModemActivity.reset(false);
+ if (mBsi.mModemActivity != null) {
+ mBsi.mModemActivity.reset(false);
}
mUserCpuTime.reset(false);
@@ -5871,7 +5938,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mWakelockStats.clear();
for (int j = 0; j < numWakelocks; j++) {
String wakelockName = in.readString();
- Uid.Wakelock wakelock = new Wakelock();
+ Uid.Wakelock wakelock = new Wakelock(mBsi, this);
wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
mWakelockStats.add(wakelockName, wakelock);
}
@@ -5882,7 +5949,7 @@ public final class BatteryStatsImpl extends BatteryStats {
String syncName = in.readString();
if (in.readInt() != 0) {
mSyncStats.add(syncName,
- new StopwatchTimer(Uid.this, SYNC, null, timeBase, in));
+ new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null, timeBase, in));
}
}
@@ -5891,7 +5958,8 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int j = 0; j < numJobs; j++) {
String jobName = in.readString();
if (in.readInt() != 0) {
- mJobStats.add(jobName, new StopwatchTimer(Uid.this, JOB, null, timeBase, in));
+ mJobStats.add(jobName, new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
+ timeBase, in));
}
}
@@ -5899,8 +5967,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mSensorStats.clear();
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
- Uid.Sensor sensor = new Sensor(sensorNumber);
- sensor.readFromParcelLocked(mOnBatteryTimeBase, in);
+ Uid.Sensor sensor = new Sensor(mBsi, this, sensorNumber);
+ sensor.readFromParcelLocked(mBsi.mOnBatteryTimeBase, in);
mSensorStats.put(sensorNumber, sensor);
}
@@ -5908,7 +5976,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mProcessStats.clear();
for (int k = 0; k < numProcs; k++) {
String processName = in.readString();
- Uid.Proc proc = new Proc(processName);
+ Uid.Proc proc = new Proc(mBsi, processName);
proc.readFromParcelLocked(in);
mProcessStats.put(processName, proc);
}
@@ -5917,29 +5985,29 @@ public final class BatteryStatsImpl extends BatteryStats {
mPackageStats.clear();
for (int l = 0; l < numPkgs; l++) {
String packageName = in.readString();
- Uid.Pkg pkg = new Pkg();
+ Uid.Pkg pkg = new Pkg(mBsi);
pkg.readFromParcelLocked(in);
mPackageStats.put(packageName, pkg);
}
mWifiRunning = false;
if (in.readInt() != 0) {
- mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
- mWifiRunningTimers, mOnBatteryTimeBase, in);
+ mWifiRunningTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_RUNNING,
+ mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiRunningTimer = null;
}
mFullWifiLockOut = false;
if (in.readInt() != 0) {
- mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
- mFullWifiLockTimers, mOnBatteryTimeBase, in);
+ mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, FULL_WIFI_LOCK,
+ mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mFullWifiLockTimer = null;
}
mWifiScanStarted = false;
if (in.readInt() != 0) {
- mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
- mWifiScanTimers, mOnBatteryTimeBase, in);
+ mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiScanTimer = null;
}
@@ -5953,44 +6021,44 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mWifiMulticastEnabled = false;
if (in.readInt() != 0) {
- mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
- mWifiMulticastTimers, mOnBatteryTimeBase, in);
+ mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED,
+ mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mWifiMulticastTimer = null;
}
if (in.readInt() != 0) {
- mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
- mAudioTurnedOnTimers, mOnBatteryTimeBase, in);
+ mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, AUDIO_TURNED_ON,
+ mBsi.mAudioTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mAudioTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
- mVideoTurnedOnTimers, mOnBatteryTimeBase, in);
+ mVideoTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, VIDEO_TURNED_ON,
+ mBsi.mVideoTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mVideoTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON,
- mFlashlightTurnedOnTimers, mOnBatteryTimeBase, in);
+ mFlashlightTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FLASHLIGHT_TURNED_ON, mBsi.mFlashlightTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mFlashlightTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON,
- mCameraTurnedOnTimers, mOnBatteryTimeBase, in);
+ mCameraTurnedOnTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, CAMERA_TURNED_ON,
+ mBsi.mCameraTurnedOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mCameraTurnedOnTimer = null;
}
if (in.readInt() != 0) {
- mForegroundActivityTimer = new StopwatchTimer(
- Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in);
+ mForegroundActivityTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FOREGROUND_ACTIVITY, null, mBsi.mOnBatteryTimeBase, in);
} else {
mForegroundActivityTimer = null;
}
if (in.readInt() != 0) {
- mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
- mBluetoothScanOnTimers, mOnBatteryTimeBase, in);
+ mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, in);
} else {
mBluetoothScanTimer = null;
}
@@ -6003,14 +6071,15 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
if (in.readInt() != 0) {
- mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase, in);
+ mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
+ mBsi.mOnBatteryTimeBase, in);
} else {
mVibratorOnTimer = null;
}
if (in.readInt() != 0) {
mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
- mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase, in);
+ mUserActivityCounters[i] = new Counter(mBsi.mOnBatteryTimeBase, in);
}
} else {
mUserActivityCounters = null;
@@ -6021,45 +6090,45 @@ public final class BatteryStatsImpl extends BatteryStats {
= new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i]
- = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
mNetworkPacketActivityCounters[i]
- = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
}
- mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mMobileRadioActiveTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
} else {
mNetworkByteActivityCounters = null;
mNetworkPacketActivityCounters = null;
}
if (in.readInt() != 0) {
- mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_WIFI_TX_LEVELS, in);
} else {
mWifiControllerActivity = null;
}
if (in.readInt() != 0) {
- mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
} else {
mBluetoothControllerActivity = null;
}
if (in.readInt() != 0) {
- mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS, in);
} else {
mModemControllerActivity = null;
}
- mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
if (in.readInt() != 0) {
int numCpuClusters = in.readInt();
- if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+ if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
throw new ParcelFormatException("Incompatible number of cpu clusters");
}
@@ -6067,8 +6136,8 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
if (in.readInt() != 0) {
int numSpeeds = in.readInt();
- if (mPowerProfile != null &&
- mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+ if (mBsi.mPowerProfile != null &&
+ mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
throw new ParcelFormatException("Incompatible number of cpu speeds");
}
@@ -6076,7 +6145,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mCpuClusterSpeed[cluster] = cpuSpeeds;
for (int speed = 0; speed < numSpeeds; speed++) {
if (in.readInt() != 0) {
- cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ cpuSpeeds[speed] = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
}
}
} else {
@@ -6091,7 +6160,17 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* The statistics associated with a particular wake lock.
*/
- public final class Wakelock extends BatteryStats.Uid.Wakelock {
+ public static class Wakelock extends BatteryStats.Uid.Wakelock {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected Uid mUid;
+
/**
* How long (in ms) this uid has been keeping the device partially awake.
*/
@@ -6112,6 +6191,11 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
StopwatchTimer mTimerDraw;
+ public Wakelock(BatteryStatsImpl bsi, Uid uid) {
+ mBsi = bsi;
+ mUid = uid;
+ }
+
/**
* Reads a possibly null Timer from a Parcel. The timer is associated with the
* proper timer pool from the given BatteryStatsImpl object.
@@ -6125,7 +6209,7 @@ public final class BatteryStatsImpl extends BatteryStats {
return null;
}
- return new StopwatchTimer(Uid.this, type, pool, timeBase, in);
+ return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
}
boolean reset() {
@@ -6165,10 +6249,10 @@ public final class BatteryStatsImpl extends BatteryStats {
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
- mPartialTimers, screenOffTimeBase, in);
- mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mFullTimers, timeBase, in);
- mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mWindowTimers, timeBase, in);
- mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mDrawTimers, timeBase, in);
+ mBsi.mPartialTimers, screenOffTimeBase, in);
+ mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
+ mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
+ mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
@@ -6195,32 +6279,32 @@ public final class BatteryStatsImpl extends BatteryStats {
case WAKE_TYPE_PARTIAL:
t = mTimerPartial;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
- mPartialTimers, mOnBatteryScreenOffTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
+ mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
mTimerPartial = t;
}
return t;
case WAKE_TYPE_FULL:
t = mTimerFull;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
- mFullTimers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
+ mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
mTimerFull = t;
}
return t;
case WAKE_TYPE_WINDOW:
t = mTimerWindow;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
- mWindowTimers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
+ mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
mTimerWindow = t;
}
return t;
case WAKE_TYPE_DRAW:
t = mTimerDraw;
if (t == null) {
- t = new StopwatchTimer(Uid.this, WAKE_TYPE_DRAW,
- mDrawTimers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
+ mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
mTimerDraw = t;
}
return t;
@@ -6230,11 +6314,23 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public final class Sensor extends BatteryStats.Uid.Sensor {
+ public static class Sensor extends BatteryStats.Uid.Sensor {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected Uid mUid;
+
final int mHandle;
StopwatchTimer mTimer;
- public Sensor(int handle) {
+ public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) {
+ mBsi = bsi;
+ mUid = uid;
mHandle = handle;
}
@@ -6243,12 +6339,12 @@ public final class BatteryStatsImpl extends BatteryStats {
return null;
}
- ArrayList<StopwatchTimer> pool = mSensorTimers.get(mHandle);
+ ArrayList<StopwatchTimer> pool = mBsi.mSensorTimers.get(mHandle);
if (pool == null) {
pool = new ArrayList<StopwatchTimer>();
- mSensorTimers.put(mHandle, pool);
+ mBsi.mSensorTimers.put(mHandle, pool);
}
- return new StopwatchTimer(Uid.this, 0, pool, timeBase, in);
+ return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in);
}
boolean reset() {
@@ -6281,7 +6377,12 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* The statistics associated with a particular process.
*/
- public final class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
+ public static class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
/**
* The name of this process.
*/
@@ -6384,9 +6485,10 @@ public final class BatteryStatsImpl extends BatteryStats {
ArrayList<ExcessivePower> mExcessivePower;
- Proc(String name) {
+ public Proc(BatteryStatsImpl bsi, String name) {
+ mBsi = bsi;
mName = name;
- mOnBatteryTimeBase.add(this);
+ mBsi.mOnBatteryTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6403,7 +6505,7 @@ public final class BatteryStatsImpl extends BatteryStats {
void detach() {
mActive = false;
- mOnBatteryTimeBase.remove(this);
+ mBsi.mOnBatteryTimeBase.remove(this);
}
public int countExcessivePowers() {
@@ -6617,7 +6719,12 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* The statistics associated with a particular package.
*/
- public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
+ public static class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
/**
* Number of times wakeup alarms have occurred for this app.
*/
@@ -6628,8 +6735,9 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
- Pkg() {
- mOnBatteryScreenOffTimeBase.add(this);
+ public Pkg(BatteryStatsImpl bsi) {
+ mBsi = bsi;
+ mBsi.mOnBatteryScreenOffTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6639,7 +6747,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void detach() {
- mOnBatteryScreenOffTimeBase.remove(this);
+ mBsi.mOnBatteryScreenOffTimeBase.remove(this);
}
void readFromParcelLocked(Parcel in) {
@@ -6647,14 +6755,14 @@ public final class BatteryStatsImpl extends BatteryStats {
mWakeupAlarms.clear();
for (int i=0; i<numWA; i++) {
String tag = in.readString();
- mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
+ mWakeupAlarms.put(tag, new Counter(mBsi.mOnBatteryTimeBase, in));
}
int numServs = in.readInt();
mServiceStats.clear();
for (int m = 0; m < numServs; m++) {
String serviceName = in.readString();
- Uid.Pkg.Serv serv = new Serv();
+ Uid.Pkg.Serv serv = new Serv(mBsi);
mServiceStats.put(serviceName, serv);
serv.readFromParcelLocked(in);
@@ -6686,7 +6794,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteWakeupAlarmLocked(String tag) {
Counter c = mWakeupAlarms.get(tag);
if (c == null) {
- c = new Counter(mOnBatteryTimeBase);
+ c = new Counter(mBsi.mOnBatteryTimeBase);
mWakeupAlarms.put(tag, c);
}
c.stepAtomic();
@@ -6700,99 +6808,113 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* The statistics associated with a particular service.
*/
- public final class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
+ public static class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
+ /**
+ * BatteryStatsImpl that we are associated with.
+ */
+ protected BatteryStatsImpl mBsi;
+
+ /**
+ * The android package in which this service resides.
+ */
+ protected Pkg mPkg;
+
/**
* Total time (ms in battery uptime) the service has been left started.
*/
- long mStartTime;
+ protected long mStartTime;
/**
* If service has been started and not yet stopped, this is
* when it was started.
*/
- long mRunningSince;
+ protected long mRunningSince;
/**
* True if we are currently running.
*/
- boolean mRunning;
+ protected boolean mRunning;
/**
* Total number of times startService() has been called.
*/
- int mStarts;
+ protected int mStarts;
/**
* Total time (ms in battery uptime) the service has been left launched.
*/
- long mLaunchedTime;
+ protected long mLaunchedTime;
/**
* If service has been launched and not yet exited, this is
* when it was launched (ms in battery uptime).
*/
- long mLaunchedSince;
+ protected long mLaunchedSince;
/**
* True if we are currently launched.
*/
- boolean mLaunched;
+ protected boolean mLaunched;
/**
* Total number times the service has been launched.
*/
- int mLaunches;
+ protected int mLaunches;
/**
* The amount of time spent started loaded from a previous save
* (ms in battery uptime).
*/
- long mLoadedStartTime;
+ protected long mLoadedStartTime;
/**
* The number of starts loaded from a previous save.
*/
- int mLoadedStarts;
+ protected int mLoadedStarts;
/**
* The number of launches loaded from a previous save.
*/
- int mLoadedLaunches;
+ protected int mLoadedLaunches;
/**
* The amount of time spent started as of the last run (ms
* in battery uptime).
*/
- long mLastStartTime;
+ protected long mLastStartTime;
/**
* The number of starts as of the last run.
*/
- int mLastStarts;
+ protected int mLastStarts;
/**
* The number of launches as of the last run.
*/
- int mLastLaunches;
+ protected int mLastLaunches;
/**
* The amount of time spent started when last unplugged (ms
* in battery uptime).
*/
- long mUnpluggedStartTime;
+ protected long mUnpluggedStartTime;
/**
* The number of starts when last unplugged.
*/
- int mUnpluggedStarts;
+ protected int mUnpluggedStarts;
/**
* The number of launches when last unplugged.
*/
- int mUnpluggedLaunches;
+ protected int mUnpluggedLaunches;
- Serv() {
- mOnBatteryTimeBase.add(this);
+ /**
+ * Construct a Serv. Also adds it to the on-battery time base as a listener.
+ */
+ public Serv(BatteryStatsImpl bsi) {
+ mBsi = bsi;
+ mBsi.mOnBatteryTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime,
@@ -6806,11 +6928,14 @@ public final class BatteryStatsImpl extends BatteryStats {
long baseRealtime) {
}
- void detach() {
- mOnBatteryTimeBase.remove(this);
+ /**
+ * Remove this Serv as a listener from the time base.
+ */
+ public void detach() {
+ mBsi.mOnBatteryTimeBase.remove(this);
}
- void readFromParcelLocked(Parcel in) {
+ public void readFromParcelLocked(Parcel in) {
mStartTime = in.readLong();
mRunningSince = in.readLong();
mRunning = in.readInt() != 0;
@@ -6830,7 +6955,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedLaunches = in.readInt();
}
- void writeToParcelLocked(Parcel out) {
+ public void writeToParcelLocked(Parcel out) {
out.writeLong(mStartTime);
out.writeLong(mRunningSince);
out.writeInt(mRunning ? 1 : 0);
@@ -6847,12 +6972,12 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mUnpluggedLaunches);
}
- long getLaunchTimeToNowLocked(long batteryUptime) {
+ public long getLaunchTimeToNowLocked(long batteryUptime) {
if (!mLaunched) return mLaunchedTime;
return mLaunchedTime + batteryUptime - mLaunchedSince;
}
- long getStartTimeToNowLocked(long batteryUptime) {
+ public long getStartTimeToNowLocked(long batteryUptime) {
if (!mRunning) return mStartTime;
return mStartTime + batteryUptime - mRunningSince;
}
@@ -6860,14 +6985,14 @@ public final class BatteryStatsImpl extends BatteryStats {
public void startLaunchedLocked() {
if (!mLaunched) {
mLaunches++;
- mLaunchedSince = getBatteryUptimeLocked();
+ mLaunchedSince = mBsi.getBatteryUptimeLocked();
mLaunched = true;
}
}
public void stopLaunchedLocked() {
if (mLaunched) {
- long time = getBatteryUptimeLocked() - mLaunchedSince;
+ long time = mBsi.getBatteryUptimeLocked() - mLaunchedSince;
if (time > 0) {
mLaunchedTime += time;
} else {
@@ -6880,14 +7005,14 @@ public final class BatteryStatsImpl extends BatteryStats {
public void startRunningLocked() {
if (!mRunning) {
mStarts++;
- mRunningSince = getBatteryUptimeLocked();
+ mRunningSince = mBsi.getBatteryUptimeLocked();
mRunning = true;
}
}
public void stopRunningLocked() {
if (mRunning) {
- long time = getBatteryUptimeLocked() - mRunningSince;
+ long time = mBsi.getBatteryUptimeLocked() - mRunningSince;
if (time > 0) {
mStartTime += time;
} else {
@@ -6898,7 +7023,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
+ return mBsi;
}
@Override
@@ -6937,7 +7062,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
final Serv newServiceStatsLocked() {
- return new Serv();
+ return new Serv(mBsi);
}
}
@@ -6948,7 +7073,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public Proc getProcessStatsLocked(String name) {
Proc ps = mProcessStats.get(name);
if (ps == null) {
- ps = new Proc(name);
+ ps = new Proc(mBsi, name);
mProcessStats.put(name, ps);
}
@@ -6977,7 +7102,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mProcessState == uidRunningState) return;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mBsi.mClocks.elapsedRealtime();
if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtime);
@@ -7011,7 +7136,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public Pkg getPackageStatsLocked(String name) {
Pkg ps = mPackageStats.get(name);
if (ps == null) {
- ps = new Pkg();
+ ps = new Pkg(mBsi);
mPackageStats.put(name, ps);
}
@@ -7046,7 +7171,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void readWakeSummaryFromParcelLocked(String wlName, Parcel in) {
- Wakelock wl = new Wakelock();
+ Wakelock wl = new Wakelock(mBsi, this);
mWakelockStats.add(wlName, wl);
if (in.readInt() != 0) {
wl.getStopwatchTimer(WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
@@ -7068,19 +7193,20 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!create) {
return null;
}
- se = new Sensor(sensor);
+ se = new Sensor(mBsi, this, sensor);
mSensorStats.put(sensor, se);
}
StopwatchTimer t = se.mTimer;
if (t != null) {
return t;
}
- ArrayList<StopwatchTimer> timers = mSensorTimers.get(sensor);
+ ArrayList<StopwatchTimer> timers = mBsi.mSensorTimers.get(sensor);
if (timers == null) {
timers = new ArrayList<StopwatchTimer>();
- mSensorTimers.put(sensor, timers);
+ mBsi.mSensorTimers.put(sensor, timers);
}
- t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mOnBatteryTimeBase);
+ t = new StopwatchTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
+ mBsi.mOnBatteryTimeBase);
se.mTimer = t;
return t;
}
@@ -7186,11 +7312,18 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
+ return mBsi;
}
}
public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
+ this(new SystemClocks(), systemDir, handler, externalSync);
+ }
+
+ public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
+ ExternalStatsSync externalSync) {
+ init(clocks);
+
if (systemDir != null) {
mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
new File(systemDir, "batterystats.bin.tmp"));
@@ -7202,24 +7335,28 @@ public final class BatteryStatsImpl extends BatteryStats {
mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
- mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
+ mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
- }
- mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase);
- mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
- mDeviceIdleModeLightTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase);
- mDeviceIdleModeFullTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
- mDeviceLightIdlingTimer = new StopwatchTimer(null, -15, null, mOnBatteryTimeBase);
- mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase);
- mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
+ mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
+ mOnBatteryTimeBase);
+ }
+ mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+ mOnBatteryTimeBase);
+ mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -11, null,
+ mOnBatteryTimeBase);
+ mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+ mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
+ mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
+ mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
- mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
+ mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
mOnBatteryTimeBase);
}
- mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase);
+ mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+ mOnBatteryTimeBase);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null,
+ mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i, null,
mOnBatteryTimeBase);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -7232,31 +7369,34 @@ public final class BatteryStatsImpl extends BatteryStats {
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS);
- mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
- mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
+ mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
+ mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+ mOnBatteryTimeBase);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
- mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
+ mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
+ mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
+ mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i, null,
+ mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i, null, mOnBatteryTimeBase);
+ mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i, null,
+ mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i, null,
+ mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
mOnBatteryTimeBase);
}
- mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
- mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
- mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
- mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase);
- mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
+ mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
+ mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
+ mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
- long uptime = SystemClock.uptimeMillis() * 1000;
- long realtime = SystemClock.elapsedRealtime() * 1000;
+ long uptime = mClocks.uptimeMillis() * 1000;
+ long realtime = mClocks.elapsedRealtime() * 1000;
initTimes(uptime, realtime);
mStartPlatformVersion = mEndPlatformVersion = Build.ID;
mDischargeStartLevel = 0;
@@ -7270,6 +7410,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public BatteryStatsImpl(Parcel p) {
+ this(new SystemClocks(), p);
+ }
+
+ public BatteryStatsImpl(Clocks clocks, Parcel p) {
+ init(clocks);
mFile = null;
mCheckinFile = null;
mDailyFile = null;
@@ -7808,9 +7953,9 @@ public final class BatteryStatsImpl extends BatteryStats {
public void resetAllStatsCmdLocked() {
resetAllStatsLocked();
- final long mSecUptime = SystemClock.uptimeMillis();
+ final long mSecUptime = mClocks.uptimeMillis();
long uptime = mSecUptime * 1000;
- long mSecRealtime = SystemClock.elapsedRealtime();
+ long mSecRealtime = mClocks.elapsedRealtime();
long realtime = mSecRealtime * 1000;
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
@@ -7835,7 +7980,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private void resetAllStatsLocked() {
mStartCount = 0;
- initTimes(SystemClock.uptimeMillis() * 1000, SystemClock.elapsedRealtime() * 1000);
+ initTimes(mClocks.uptimeMillis() * 1000, mClocks.elapsedRealtime() * 1000);
mScreenOnTimer.reset(false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
@@ -7983,17 +8128,8 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int NETWORK_STATS_NEXT = 1;
private static final int NETWORK_STATS_DELTA = 2;
- private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] {
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50)
- };
-
- private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] {
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50),
- new NetworkStats(SystemClock.elapsedRealtime(), 50)
- };
+ private NetworkStats[] mMobileNetworkStats;
+ private NetworkStats[] mWifiNetworkStats;
/**
* Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
@@ -8026,7 +8162,7 @@ public final class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, "Updating wifi stats");
}
- final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+ final long elapsedRealtimeMs = mClocks.elapsedRealtime();
NetworkStats delta = null;
try {
if (!ArrayUtils.isEmpty(mWifiIfaces)) {
@@ -8056,7 +8192,8 @@ public final class BatteryStatsImpl extends BatteryStats {
+ " txPackets=" + entry.txPackets);
}
- if (entry.rxBytes == 0 || entry.txBytes == 0) {
+ if (entry.rxBytes == 0 && entry.txBytes == 0) {
+ // Skip the lookup below since there is no work to do.
continue;
}
@@ -8570,7 +8707,7 @@ public final class BatteryStatsImpl extends BatteryStats {
SamplingTimer kwlt = mKernelWakelockStats.get(name);
if (kwlt == null) {
- kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
+ kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
true /* track reported val */);
mKernelWakelockStats.put(name, kwlt);
}
@@ -8663,7 +8800,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// Read the CPU data for each UID. This will internally generate a snapshot so next time
// we read, we get a delta. If we are to distribute the cpu time, then do so. Otherwise
// we just ignore the data.
- final long startTimeMs = SystemClock.elapsedRealtime();
+ final long startTimeMs = mClocks.elapsedRealtime();
mKernelUidCpuTimeReader.readDelta(!mOnBatteryInternal ? null :
new KernelUidCpuTimeReader.Callback() {
@Override
@@ -8735,7 +8872,7 @@ public final class BatteryStatsImpl extends BatteryStats {
});
if (DEBUG_ENERGY_CPU) {
- Slog.d(TAG, "Reading cpu stats took " + (SystemClock.elapsedRealtime() - startTimeMs) +
+ Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
" ms");
}
@@ -9000,8 +9137,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public void setBatteryStateLocked(int status, int health, int plugType, int level,
int temp, int volt) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
- final long uptime = SystemClock.uptimeMillis();
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
// We start out assuming that the device is plugged in (not
@@ -9147,7 +9284,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public long getAwakeTimePlugged() {
- return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
+ return (mClocks.uptimeMillis() * 1000) - getAwakeTimeBattery();
}
@Override
@@ -9310,8 +9447,8 @@ public final class BatteryStatsImpl extends BatteryStats {
return mDailyPackageChanges;
}
- long getBatteryUptimeLocked() {
- return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
+ protected long getBatteryUptimeLocked() {
+ return mOnBatteryTimeBase.getUptime(mClocks.uptimeMillis() * 1000);
}
@Override
@@ -9429,7 +9566,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public Uid getUidStatsLocked(int uid) {
Uid u = mUidStats.get(uid);
if (u == null) {
- u = new Uid(uid);
+ u = new Uid(this, uid);
mUidStats.put(uid, u);
}
return u;
@@ -9474,7 +9611,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void shutdownLocked() {
- recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+ recordShutdownLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
writeSyncLocked();
mShuttingDown = true;
}
@@ -9502,7 +9639,7 @@ public final class BatteryStatsImpl extends BatteryStats {
Parcel out = Parcel.obtain();
writeSummaryToParcel(out, true);
- mLastWriteTime = SystemClock.elapsedRealtime();
+ mLastWriteTime = mClocks.elapsedRealtime();
if (mPendingWrite != null) {
mPendingWrite.recycle();
@@ -9583,8 +9720,8 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mHistoryBuffer.dataPosition() > 0) {
mRecordingHistory = true;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (USE_OLD_HISTORY) {
addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
}
@@ -9663,7 +9800,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// We are just arbitrarily going to insert 1 minute from the sample of
// the last run until samples in this run.
if (mHistoryBaseTime > 0) {
- long oldnow = SystemClock.elapsedRealtime();
+ long oldnow = mClocks.elapsedRealtime();
mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
@@ -9870,7 +10007,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
- Uid u = new Uid(uid);
+ Uid u = new Uid(this, uid);
mUidStats.put(uid, u);
u.mWifiRunning = false;
@@ -10083,8 +10220,8 @@ public final class BatteryStatsImpl extends BatteryStats {
// if we had originally pulled a time before the RTC was set.
long startClockTime = getStartClockTime();
- final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
- final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
+ final long NOW_SYS = mClocks.uptimeMillis() * 1000;
+ final long NOWREAL_SYS = mClocks.elapsedRealtime() * 1000;
out.writeInt(VERSION);
@@ -10469,29 +10606,34 @@ public final class BatteryStatsImpl extends BatteryStats {
mOnBatteryScreenOffTimeBase.readFromParcel(in);
mScreenState = Display.STATE_UNKNOWN;
- mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
+ mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
- mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase,
- in);
+ mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
+ mOnBatteryTimeBase, in);
}
mInteractive = false;
- mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase, in);
+ mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase, in);
mPhoneOn = false;
- mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
+ mOnBatteryTimeBase, in);
mLongestLightIdleTime = in.readLong();
mLongestFullIdleTime = in.readLong();
- mDeviceIdleModeLightTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
- mDeviceIdleModeFullTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase, in);
- mDeviceLightIdlingTimer = new StopwatchTimer(null, -15, null, mOnBatteryTimeBase, in);
- mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase, in);
- mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
+ mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
+ mOnBatteryTimeBase, in);
+ mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
+ mOnBatteryTimeBase, in);
+ mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null,
+ mOnBatteryTimeBase, in);
+ mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
+ mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
- mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
+ mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
null, mOnBatteryTimeBase, in);
}
- mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase, in);
+ mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
+ mOnBatteryTimeBase, in);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
+ mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i,
null, mOnBatteryTimeBase, in);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -10499,27 +10641,29 @@ public final class BatteryStatsImpl extends BatteryStats {
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
- mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
- mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
- in);
+ mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null,
+ mOnBatteryTimeBase, in);
+ mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
+ mOnBatteryTimeBase, in);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
- mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
+ mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
+ mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null,
+ mOnBatteryTimeBase, in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
- mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
+ mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i,
+ mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i,
null, mOnBatteryTimeBase, in);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
+ mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
null, mOnBatteryTimeBase, in);
}
@@ -10537,15 +10681,15 @@ public final class BatteryStatsImpl extends BatteryStats {
mLoadedNumConnectivityChange = in.readInt();
mUnpluggedNumConnectivityChange = in.readInt();
mAudioOnNesting = 0;
- mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+ mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
mVideoOnNesting = 0;
- mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+ mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
mFlashlightOnNesting = 0;
- mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
+ mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase, in);
mCameraOnNesting = 0;
- mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in);
+ mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
mBluetoothScanNesting = 0;
- mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
+ mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -10565,7 +10709,7 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int ikw = 0; ikw < NKW; ikw++) {
if (in.readInt() != 0) {
String wakelockName = in.readString();
- SamplingTimer kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, in);
+ SamplingTimer kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase, in);
mKernelWakelockStats.put(wakelockName, kwlt);
}
}
@@ -10575,7 +10719,7 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int iwr = 0; iwr < NWR; iwr++) {
if (in.readInt() != 0) {
String reasonName = in.readString();
- SamplingTimer timer = new SamplingTimer(mOnBatteryTimeBase, in);
+ SamplingTimer timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, in);
mWakeupReasonStats.put(reasonName, timer);
}
}
@@ -10597,7 +10741,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
int uid = in.readInt();
- Uid u = new Uid(uid);
+ Uid u = new Uid(this, uid);
u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
mUidStats.append(uid, u);
}
@@ -10620,8 +10764,8 @@ public final class BatteryStatsImpl extends BatteryStats {
// if we had originally pulled a time before the RTC was set.
long startClockTime = getStartClockTime();
- final long uSecUptime = SystemClock.uptimeMillis() * 1000;
- final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long uSecUptime = mClocks.uptimeMillis() * 1000;
+ final long uSecRealtime = mClocks.elapsedRealtime() * 1000;
final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 3b8b7cb2ba2f..fff9d7c3247b 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -20,6 +20,7 @@ import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.os.Build;
+import android.os.DeadObjectException;
import android.os.Debug;
import android.os.IBinder;
import android.os.Process;
@@ -57,8 +58,7 @@ public class RuntimeInit {
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
private static int Clog_e(String tag, String msg, Throwable tr) {
- return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,
- msg + '\n' + Log.getStackTraceString(tr));
+ return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
}
/**
@@ -97,10 +97,14 @@ public class RuntimeInit {
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
- try {
- Clog_e(TAG, "Error reporting crash", t2);
- } catch (Throwable t3) {
- // Even Clog_e() fails! Oh well.
+ if (t2 instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ try {
+ Clog_e(TAG, "Error reporting crash", t2);
+ } catch (Throwable t3) {
+ // Even Clog_e() fails! Oh well.
+ }
}
} finally {
// Try everything to make sure this process goes away.
@@ -359,8 +363,12 @@ public class RuntimeInit {
System.exit(10);
}
} catch (Throwable t2) {
- Slog.e(TAG, "Error reporting WTF", t2);
- Slog.e(TAG, "Original WTF:", t);
+ if (t2 instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ Slog.e(TAG, "Error reporting WTF", t2);
+ Slog.e(TAG, "Original WTF:", t);
+ }
}
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index b2ae835be358..df48d6d0df8c 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -86,6 +86,8 @@ import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -196,7 +198,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
int mStackId;
private boolean mWindowResizeCallbacksAdded = false;
-
+ private Drawable.Callback mLastBackgroundDrawableCb = null;
private BackdropFrameRenderer mBackdropFrameRenderer = null;
private Drawable mResizingBackgroundDrawable;
private Drawable mCaptionBackgroundDrawable;
@@ -583,14 +585,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
w = 0;
}
if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed width: " + w);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if (w > 0) {
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
Math.min(w, widthSize), EXACTLY);
fixedWidth = true;
} else {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- widthMeasureSpec - mFloatingInsets.left - mFloatingInsets.right,
+ widthSize - mFloatingInsets.left - mFloatingInsets.right,
AT_MOST);
mApplyFloatingHorizontalInsets = true;
}
@@ -615,7 +617,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
if (h > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
Math.min(h, heightSize), EXACTLY);
- } else if ((mWindow.getAttributes().flags & FLAG_FULLSCREEN) == 0) {
+ } else if ((mWindow.getAttributes().flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
heightSize - mFloatingInsets.top - mFloatingInsets.bottom, AT_MOST);
mApplyFloatingVerticalInsets = true;
@@ -861,6 +863,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
if (getBackground() != drawable) {
setBackgroundDrawable(drawable);
if (drawable != null) {
+ mResizingBackgroundDrawable = drawable;
drawable.getPadding(mBackgroundPadding);
} else {
mBackgroundPadding.setEmpty();
@@ -890,10 +893,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
final WindowManager.LayoutParams attrs = mWindow.getAttributes();
mFloatingInsets.setEmpty();
- if ((attrs.flags & FLAG_FULLSCREEN) == 0) {
+ if ((attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0) {
// For dialog windows we want to make sure they don't go over the status bar or nav bar.
// We consume the system insets and we will reuse them later during the measure phase.
- // We allow the app to ignore this and handle insets itself by using FLAG_FULLSCREEN.
+ // We allow the app to ignore this and handle insets itself by using
+ // FLAG_LAYOUT_IN_SCREEN.
if (attrs.height == WindowManager.LayoutParams.WRAP_CONTENT) {
mFloatingInsets.top = insets.getSystemWindowInsetTop();
mFloatingInsets.bottom = insets.getSystemWindowInsetBottom();
@@ -998,15 +1002,28 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
boolean consumingNavBar =
(attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
&& (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
- && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
-
+ && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+ || (insets != null && insets.shouldAlwaysConsumeNavBar());
+
+ // If we didn't request fullscreen layout, but we still got it because of the
+ // mForceWindowDrawsStatusBarBackground flag, also consume top inset.
+ boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
+ && (sysUiVisibility & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+ && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
+ && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
+ && mForceWindowDrawsStatusBarBackground
+ && mLastTopInset != 0;
+
+ int consumedTop = consumingStatusBar ? mLastTopInset : 0;
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
if (mContentRoot != null
&& mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
- if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
+ if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
+ || lp.bottomMargin != consumedBottom) {
+ lp.topMargin = consumedTop;
lp.rightMargin = consumedRight;
lp.bottomMargin = consumedBottom;
mContentRoot.setLayoutParams(lp);
@@ -1020,7 +1037,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
if (insets != null) {
insets = insets.replaceSystemWindowInsets(
insets.getSystemWindowInsetLeft(),
- insets.getSystemWindowInsetTop(),
+ insets.getSystemWindowInsetTop() - consumedTop,
insets.getSystemWindowInsetRight() - consumedRight,
insets.getSystemWindowInsetBottom() - consumedBottom);
}
@@ -1716,13 +1733,22 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private void loadBackgroundDrawablesIfNeeded() {
if (mResizingBackgroundDrawable == null) {
- mResizingBackgroundDrawable = getResizingBackgroundDrawable(
+ mResizingBackgroundDrawable = getResizingBackgroundDrawable(getContext(),
mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
+ if (mResizingBackgroundDrawable == null) {
+ // We shouldn't really get here as the background fallback should be always
+ // available since it is defaulted by the system.
+ Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
+ }
}
if (mCaptionBackgroundDrawable == null) {
mCaptionBackgroundDrawable = getContext().getDrawable(
R.drawable.decor_caption_title_focused);
}
+ if (mResizingBackgroundDrawable != null) {
+ mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
+ mResizingBackgroundDrawable.setCallback(null);
+ }
}
// Free floating overlapping windows require a caption.
@@ -1815,9 +1841,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
* Returns the color used to fill areas the app has not rendered content to yet when the
* user is resizing the window of an activity in multi-window mode.
*/
- private Drawable getResizingBackgroundDrawable(int backgroundRes, int backgroundFallbackRes) {
- final Context context = getContext();
-
+ public static Drawable getResizingBackgroundDrawable(Context context, int backgroundRes,
+ int backgroundFallbackRes) {
if (backgroundRes != 0) {
final Drawable drawable = context.getDrawable(backgroundRes);
if (drawable != null) {
@@ -1831,10 +1856,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
return fallbackDrawable;
}
}
-
- // We shouldn't really get here as the background fallback should be always available since
- // it is defaulted by the system.
- Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
return null;
}
@@ -1941,6 +1962,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
/** Release the renderer thread which is usually done when the user stops resizing. */
private void releaseThreadedRenderer() {
+ if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
+ mResizingBackgroundDrawable.setCallback(mLastBackgroundDrawableCb);
+ mLastBackgroundDrawableCb = null;
+ }
+
if (mBackdropFrameRenderer != null) {
mBackdropFrameRenderer.releaseRenderer();
mBackdropFrameRenderer = null;
diff --git a/core/java/com/android/internal/policy/DockedDividerUtils.java b/core/java/com/android/internal/policy/DockedDividerUtils.java
index 00c65bd13e50..c68e50692c2a 100644
--- a/core/java/com/android/internal/policy/DockedDividerUtils.java
+++ b/core/java/com/android/internal/policy/DockedDividerUtils.java
@@ -17,9 +17,9 @@
package com.android.internal.policy;
import android.graphics.Rect;
-import android.view.WindowManager;
import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
@@ -35,46 +35,61 @@ public class DockedDividerUtils {
int displayWidth, int displayHeight, int dividerSize) {
outRect.set(0, 0, displayWidth, displayHeight);
switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
+ case DOCKED_LEFT:
outRect.right = position;
break;
- case WindowManager.DOCKED_TOP:
+ case DOCKED_TOP:
outRect.bottom = position;
break;
- case WindowManager.DOCKED_RIGHT:
+ case DOCKED_RIGHT:
outRect.left = position + dividerSize;
break;
- case WindowManager.DOCKED_BOTTOM:
+ case DOCKED_BOTTOM:
outRect.top = position + dividerSize;
break;
}
- sanitizeStackBounds(outRect);
+ sanitizeStackBounds(outRect, dockSide == DOCKED_LEFT || dockSide == DOCKED_TOP);
}
- public static void sanitizeStackBounds(Rect bounds) {
- if (bounds.left >= bounds.right) {
- bounds.left = bounds.right - 1;
- }
- if (bounds.top >= bounds.bottom) {
- bounds.top = bounds.bottom - 1;
- }
- if (bounds.right <= bounds.left) {
- bounds.right = bounds.left + 1;
- }
- if (bounds.bottom <= bounds.top) {
- bounds.bottom = bounds.top + 1;
+ /**
+ * Makes sure that the bounds are always valid, i. e. they are at least one pixel high and wide.
+ *
+ * @param bounds The bounds to sanitize.
+ * @param topLeft Pass true if the bounds are at the top/left of the screen, false if they are
+ * at the bottom/right. This is used to determine in which direction to extend
+ * the bounds.
+ */
+ public static void sanitizeStackBounds(Rect bounds, boolean topLeft) {
+
+ // If the bounds are either on the top or left of the screen, rather move it further to the
+ // left/top to make it more offscreen. If they are on the bottom or right, push them off the
+ // screen by moving it even more to the bottom/right.
+ if (topLeft) {
+ if (bounds.left >= bounds.right) {
+ bounds.left = bounds.right - 1;
+ }
+ if (bounds.top >= bounds.bottom) {
+ bounds.top = bounds.bottom - 1;
+ }
+ } else {
+ if (bounds.right <= bounds.left) {
+ bounds.right = bounds.left + 1;
+ }
+ if (bounds.bottom <= bounds.top) {
+ bounds.bottom = bounds.top + 1;
+ }
}
}
public static int calculatePositionForBounds(Rect bounds, int dockSide, int dividerSize) {
switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
+ case DOCKED_LEFT:
return bounds.right;
- case WindowManager.DOCKED_TOP:
+ case DOCKED_TOP:
return bounds.bottom;
- case WindowManager.DOCKED_RIGHT:
+ case DOCKED_RIGHT:
return bounds.left - dividerSize;
- case WindowManager.DOCKED_BOTTOM:
+ case DOCKED_BOTTOM:
return bounds.top - dividerSize;
default:
return 0;
@@ -109,16 +124,16 @@ public class DockedDividerUtils {
public static int invertDockSide(int dockSide) {
switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
- return WindowManager.DOCKED_RIGHT;
- case WindowManager.DOCKED_TOP:
- return WindowManager.DOCKED_BOTTOM;
- case WindowManager.DOCKED_RIGHT:
- return WindowManager.DOCKED_LEFT;
- case WindowManager.DOCKED_BOTTOM:
- return WindowManager.DOCKED_TOP;
+ case DOCKED_LEFT:
+ return DOCKED_RIGHT;
+ case DOCKED_TOP:
+ return DOCKED_BOTTOM;
+ case DOCKED_RIGHT:
+ return DOCKED_LEFT;
+ case DOCKED_BOTTOM:
+ return DOCKED_TOP;
default:
- return WindowManager.DOCKED_INVALID;
+ return DOCKED_INVALID;
}
}
}
diff --git a/core/java/com/android/internal/policy/IShortcutService.aidl b/core/java/com/android/internal/policy/IShortcutService.aidl
new file mode 100644
index 000000000000..85507282b4de
--- /dev/null
+++ b/core/java/com/android/internal/policy/IShortcutService.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * An interface to notify the shortcut service that a shortcut key is pressed
+ * @hide
+ */
+oneway interface IShortcutService {
+ /**
+ * @param shortcutCode the keycode packed with meta information
+ */
+ void notifyShortcutKeyPressed(long shortcutCode);
+}
+
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6e374e28103f..64c5b8de46a9 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -17,6 +17,7 @@
package com.android.internal.statusbar;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -31,7 +32,23 @@ oneway interface IStatusBar
void animateExpandNotificationsPanel();
void animateExpandSettingsPanel(String subPanel);
void animateCollapsePanels();
- void setSystemUiVisibility(int vis, int mask);
+
+ /**
+ * Notifies the status bar of a System UI visibility flag change.
+ *
+ * @param vis the visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will be reported
+ * separately in fullscreenStackVis and dockedStackVis
+ * @param fullscreenStackVis the flags which only apply in the region of the fullscreen stack,
+ * which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ * @param dockedStackVis the flags that only apply in the region of the docked stack, which is
+ * currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ * @param mask which flags to change
+ * @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates
+ * @param dockedBounds the current bounds of the docked stack, in screen coordinates
+ */
+ void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+ in Rect fullscreenBounds, in Rect dockedBounds);
+
void topAppWindowChanged(boolean menuVisible);
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
@@ -43,6 +60,7 @@ oneway interface IStatusBar
void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecentApps();
+ void toggleSplitScreen();
void preloadRecentApps();
void cancelPreloadRecentApps();
void showScreenPinningRequest();
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index bec18ec48ec2..8acf5d3070d3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -17,6 +17,7 @@
package com.android.internal.statusbar;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -37,7 +38,6 @@ interface IStatusBarService
void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
- void topAppWindowChanged(boolean menuVisible);
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
void expandSettingsPanel(String subPanel);
@@ -47,7 +47,8 @@ interface IStatusBarService
// You need the STATUS_BAR_SERVICE permission
void registerStatusBar(IStatusBar callbacks, out List<String> iconSlots,
out List<StatusBarIcon> iconList,
- out int[] switches, out List<IBinder> binders);
+ out int[] switches, out List<IBinder> binders, out Rect fullscreenStackBounds,
+ out Rect dockedStackBounds);
void onPanelRevealed(boolean clearNotificationEffects, int numItems);
void onPanelHidden();
// Mark current notifications as "seen" and stop ringing, vibrating, blinking.
diff --git a/core/java/com/android/internal/util/LineBreakBufferedWriter.java b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
index f831e7a84d2f..552a93f6666a 100644
--- a/core/java/com/android/internal/util/LineBreakBufferedWriter.java
+++ b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
@@ -96,7 +96,7 @@ public class LineBreakBufferedWriter extends PrintWriter {
@Override
public void write(int c) {
- if (bufferIndex < bufferSize) {
+ if (bufferIndex < buffer.length) {
buffer[bufferIndex] = (char)c;
bufferIndex++;
if ((char)c == '\n') {
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
new file mode 100644
index 000000000000..184245ef538d
--- /dev/null
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * Static utility class for dealing with {@link Message} objects.
+ */
+public class MessageUtils {
+
+ private static final String TAG = MessageUtils.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ /** Thrown when two different constants have the same value. */
+ public static class DuplicateConstantError extends Error {
+ private DuplicateConstantError() {}
+ public DuplicateConstantError(String name1, String name2, int value) {
+ super(String.format("Duplicate constant value: both %s and %s = %d",
+ name1, name2, value));
+ }
+ }
+
+ /**
+ * 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}.
+ *
+ * @param classes 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[] classes, String[] prefixes) {
+ SparseArray<String> messageNames = new SparseArray<>();
+ for (Class c : classes) {
+ String className = c.getName();
+ if (DBG) Log.d(TAG, "Examining class " + className);
+
+ Field[] fields;
+ try {
+ fields = c.getDeclaredFields();
+ } catch (SecurityException e) {
+ Log.e(TAG, "Can't list fields of class " + className);
+ continue;
+ }
+
+ for (Field field : fields) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isStatic(modifiers) | !Modifier.isFinal(modifiers)) {
+ continue;
+ }
+
+ String name = field.getName();
+ for (String prefix : prefixes) {
+ // Does this look like a constant?
+ if (!name.startsWith(prefix)) {
+ continue;
+ }
+
+ try {
+ // TODO: can we have the caller try to access the field instead, so we don't
+ // expose constants it does not have access to?
+ field.setAccessible(true);
+
+ // Fetch the constant's value.
+ int value;
+ try {
+ value = field.getInt(null);
+ } catch (IllegalArgumentException | ExceptionInInitializerError e) {
+ // The field is not an integer (or short or byte), or c's static
+ // initializer failed and we have no idea what its value is.
+ // Either way, give up on this field.
+ break;
+ }
+
+ // Check for duplicate values.
+ String previousName = messageNames.get(value);
+ if (previousName != null && !previousName.equals(name)) {
+ throw new DuplicateConstantError(name, previousName, value);
+ }
+
+ messageNames.put(value, name);
+ if (DBG) {
+ Log.d(TAG, String.format("Found constant: %s.%s = %d",
+ className, name, value));
+ }
+ } catch (SecurityException | IllegalAccessException e) {
+ // Not allowed to make the field accessible, or no access. Ignore.
+ continue;
+ }
+ }
+ }
+ }
+ return messageNames;
+ }
+
+ /**
+ * Default prefixes for constants.
+ */
+ public static final String[] DEFAULT_PREFIXES = {"CMD_", "EVENT_"};
+
+ /**
+ * Finds the names of integer constants. Searches the specified {@code classes}, looking for
+ * 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) {
+ return findMessageNames(classNames, DEFAULT_PREFIXES);
+ }
+}
+
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 2f26e921d03b..53cb56ebecd9 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -104,15 +104,27 @@ public class Preconditions {
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
+ * @param message exception message
* @throws IllegalStateException if {@code expression} is false
*/
- public static void checkState(final boolean expression) {
+ public static void checkState(final boolean expression, String message) {
if (!expression) {
- throw new IllegalStateException();
+ throw new IllegalStateException(message);
}
}
/**
+ * Ensures the truth of an expression involving the state of the calling
+ * instance, but not involving any parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @throws IllegalStateException if {@code expression} is false
+ */
+ public static void checkState(final boolean expression) {
+ checkState(expression, null);
+ }
+
+ /**
* Check the requested flags, throwing if any requested flags are outside
* the allowed set.
*/
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index a106f48745cf..5992f7a92e13 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -64,5 +64,6 @@ public class Protocol {
public static final int BASE_NETWORK_AGENT = 0x00081000;
public static final int BASE_NETWORK_MONITOR = 0x00082000;
public static final int BASE_NETWORK_FACTORY = 0x00083000;
+ public static final int BASE_ETHERNET = 0x00084000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 77859b8bb6a0..451078b1b047 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -21,7 +21,7 @@ import android.content.Context;
import android.os.Handler;
import android.os.Message;
- /**
+/**
* An AlarmListener that sends the specified message to a Handler and keeps the system awake until
* the message is processed.
*
@@ -33,19 +33,17 @@ import android.os.Message;
* the message, but does not guarantee that the system will be awake until the target object has
* processed it. This is because as soon as the onAlarmListener sends the message and returns, the
* AlarmManager releases its wakelock and the system is free to go to sleep again.
- *
*/
public class WakeupMessage implements AlarmManager.OnAlarmListener {
- private static AlarmManager sAlarmManager;
+ private final AlarmManager mAlarmManager;
private final Handler mHandler;
private final String mCmdName;
private final int mCmd, mArg1, mArg2;
+ private boolean mScheduled;
public WakeupMessage(Context context, Handler handler,
String cmdName, int cmd, int arg1, int arg2) {
- if (sAlarmManager == null) {
- sAlarmManager = context.getSystemService(AlarmManager.class);
- }
+ mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mHandler = handler;
mCmdName = cmdName;
mCmd = cmd;
@@ -61,19 +59,43 @@ public class WakeupMessage implements AlarmManager.OnAlarmListener {
this(context, handler, cmdName, cmd, 0, 0);
}
- public void schedule(long when) {
- sAlarmManager.setExact(
+ /**
+ * Schedule the message to be delivered at the time in milliseconds of the
+ * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
+ * the device when it goes off. If schedule is called multiple times without the message being
+ * dispatched then the alarm is rescheduled to the new time.
+ */
+ public synchronized void schedule(long when) {
+ mAlarmManager.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
+ mScheduled = true;
}
- public void cancel() {
- sAlarmManager.cancel(this);
+ /**
+ * Cancel all pending messages. This includes alarms that may have been fired, but have not been
+ * run on the handler yet.
+ */
+ public synchronized void cancel() {
+ if (mScheduled) {
+ mAlarmManager.cancel(this);
+ mScheduled = false;
+ }
}
@Override
public void onAlarm() {
- Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
- mHandler.handleMessage(msg);
- msg.recycle();
+ // Once this method is called the alarm has already been fired and removed from
+ // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
+ // be marked as unscheduled so that it can be rescheduled in the message handler.
+ final boolean stillScheduled;
+ synchronized (this) {
+ stillScheduled = mScheduled;
+ mScheduled = false;
+ }
+ if (stillScheduled) {
+ Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
+ mHandler.handleMessage(msg);
+ msg.recycle();
+ }
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index bcc310f7a9fa..ab918c832c0c 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -38,7 +38,7 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
- Rect backDropFrame, boolean forceLayout) {
+ Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index db3ecc6f2dc8..5576f13ba488 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -46,17 +46,14 @@ interface IInputMethodManager {
in IInputContext inputContext, int uid, int pid);
void removeClient(in IInputMethodClient client);
- InputBindResult startInput(/* @InputMethodClient.StartInputReason */ int startInputReason,
- in IInputMethodClient client, IInputContext inputContext, in EditorInfo attribute,
- int controlFlags);
void finishInput(in IInputMethodClient client);
boolean showSoftInput(in IInputMethodClient client, int flags,
in ResultReceiver resultReceiver);
boolean hideSoftInput(in IInputMethodClient client, int flags,
in ResultReceiver resultReceiver);
- // Report that a window has gained focus. If 'attribute' is non-null,
- // this will also do a startInput.
- InputBindResult windowGainedFocus(
+ // If windowToken is null, this just does startInput(). Otherwise this reports that a window
+ // has gained focus, and if 'attribute' is non-null then also does startInput.
+ InputBindResult startInputOrWindowGainedFocus(
/* @InputMethodClient.StartInputReason */ int startInputReason,
in IInputMethodClient client, in IBinder windowToken, int controlFlags,
int softInputMode, int windowFlags, in EditorInfo attribute,
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 94790c158559..fc672454a0a0 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -17,6 +17,7 @@
package com.android.internal.view;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
@@ -454,4 +455,9 @@ public class InputConnectionWrapper implements InputConnection {
}
return result;
}
+
+ public Handler getHandler() {
+ // Nothing should happen when called from input method.
+ return null;
+ }
}
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index cc0db51fb4d5..891c920af336 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -17,7 +17,6 @@
package com.android.internal.widget;
import android.annotation.AttrRes;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.content.Context;
@@ -107,14 +106,7 @@ public class AlertDialogLayout extends LinearLayout {
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
- // Treat all panel widths as MATCH_PARENT
- // by translating AT_MOST to EXACTLY.
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- if (widthMode == MeasureSpec.AT_MOST) {
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
- }
int childState = 0;
int usedHeight = getPaddingTop() + getPaddingBottom();
@@ -204,15 +196,52 @@ public class AlertDialogLayout extends LinearLayout {
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
}
}
+
maxWidth += getPaddingLeft() + getPaddingRight();
final int widthSizeAndState = resolveSizeAndState(maxWidth, widthMeasureSpec, childState);
final int heightSizeAndState = resolveSizeAndState(usedHeight, heightMeasureSpec, 0);
setMeasuredDimension(widthSizeAndState, heightSizeAndState);
+
+ // If the children weren't already measured EXACTLY, we need to run
+ // another measure pass to for MATCH_PARENT widths.
+ if (widthMode != MeasureSpec.EXACTLY) {
+ forceUniformWidth(count, heightMeasureSpec);
+ }
+
return true;
}
/**
+ * Remeasures child views to exactly match the layout's measured width.
+ *
+ * @param count the number of child views
+ * @param heightMeasureSpec the original height measure spec
+ */
+ private void forceUniformWidth(int count, int heightMeasureSpec) {
+ // Pretend that the linear layout has an exact size.
+ final int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(
+ getMeasuredWidth(), MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.width == LayoutParams.MATCH_PARENT) {
+ // Temporarily force children to reuse their old measured
+ // height.
+ final int oldHeight = lp.height;
+ lp.height = child.getMeasuredHeight();
+
+ // Remeasure with new dimensions.
+ measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
+ lp.height = oldHeight;
+ }
+ }
+ }
+ }
+
+ /**
* Attempts to resolve the minimum height of a view.
* <p>
* If the view doesn't have a minimum height set and only contains a single
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e239852673e8..cbc735fc065c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -283,6 +283,15 @@ public class LockPatternUtils {
getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
}
+ public int getCurrentFailedPasswordAttempts(int userId) {
+ return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
+ }
+
+ public int getMaximumFailedPasswordsForWipe(int userId) {
+ return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
+ null /* componentName */, userId);
+ }
+
/**
* Check to see if a pattern matches the saved pattern.
* If pattern matches, return an opaque attestation that the challenge
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index b45fd06c8a71..6bba1b3e1aec 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.RemoteViews;
@@ -31,16 +32,16 @@ import android.widget.RemoteViews;
* @hide
*/
@RemoteViews.RemoteView
-public class MediaNotificationView extends RelativeLayout {
+public class MediaNotificationView extends FrameLayout {
private final int mMaxImageSize;
- private final int mImageMarginBottom;
private final int mImageMinTopMargin;
private final int mNotificationContentMarginEnd;
private final int mNotificationContentImageMarginEnd;
private ImageView mRightIcon;
private View mActions;
private View mHeader;
+ private View mMainColumn;
public MediaNotificationView(Context context) {
this(context, null);
@@ -61,39 +62,49 @@ public class MediaNotificationView extends RelativeLayout {
if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
size = size - mActions.getMeasuredWidth();
ViewGroup.MarginLayoutParams layoutParams =
(MarginLayoutParams) mRightIcon.getLayoutParams();
- size -= layoutParams.getMarginEnd();
+ int imageEndMargin = layoutParams.getMarginEnd();
+ size -= imageEndMargin;
size = Math.min(size, mMaxImageSize);
size = Math.max(size, mRightIcon.getMinimumWidth());
layoutParams.width = size;
layoutParams.height = size;
- // because we can't allign it to the bottom with a margin, we add a topmargin to it
- layoutParams.topMargin = height - size - mImageMarginBottom;
- // If the topMargin is high enough we can also remove the header constraint!
- if (layoutParams.topMargin >= mImageMinTopMargin) {
- resetHeaderIndention();
- } else {
- int paddingEnd = mNotificationContentImageMarginEnd;
- ViewGroup.MarginLayoutParams headerParams =
- (MarginLayoutParams) mHeader.getLayoutParams();
- headerParams.setMarginEnd(size + layoutParams.getMarginEnd());
- if (mHeader.getPaddingEnd() != paddingEnd) {
- mHeader.setPadding(
- isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
- mHeader.getPaddingTop(),
- isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
- mHeader.getPaddingBottom());
- mHeader.setLayoutParams(headerParams);
- }
- }
mRightIcon.setLayoutParams(layoutParams);
- } else if (!hasIcon && mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
- resetHeaderIndention();
+
+ // lets ensure that the main column doesn't run into the image
+ ViewGroup.MarginLayoutParams mainParams
+ = (MarginLayoutParams) mMainColumn.getLayoutParams();
+ int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
+ if (marginEnd != mainParams.getMarginEnd()) {
+ mainParams.setMarginEnd(marginEnd);
+ mMainColumn.setLayoutParams(mainParams);
+ }
+
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ ViewGroup.MarginLayoutParams iconParams =
+ (MarginLayoutParams) mRightIcon.getLayoutParams();
+ int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
+ - iconParams.bottomMargin;
+ // If the topMargin is high enough we can also remove the header constraint!
+ if (!hasIcon || topMargin >= mImageMinTopMargin) {
+ resetHeaderIndention();
+ } else {
+ int paddingEnd = mNotificationContentImageMarginEnd;
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd());
+ if (mHeader.getPaddingEnd() != paddingEnd) {
+ mHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
+ mHeader.getPaddingTop(),
+ isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
+ mHeader.getPaddingBottom());
+ mHeader.setLayoutParams(headerParams);
+ }
+ }
}
private void resetHeaderIndention() {
@@ -115,8 +126,6 @@ public class MediaNotificationView extends RelativeLayout {
super(context, attrs, defStyleAttr, defStyleRes);
mMaxImageSize = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.media_notification_expanded_image_max_size);
- mImageMarginBottom = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.media_notification_expanded_image_margin_bottom);
mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_top)
+ getResources().getDisplayMetrics().density * 2);
@@ -132,5 +141,6 @@ public class MediaNotificationView extends RelativeLayout {
mRightIcon = (ImageView) findViewById(com.android.internal.R.id.right_icon);
mActions = findViewById(com.android.internal.R.id.media_actions);
mHeader = findViewById(com.android.internal.R.id.notification_header);
+ mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
}
}
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 92d5aea18a52..ab75b7c2775c 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -19,10 +19,10 @@ package com.android.server;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.DropBoxManager;
+import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.RecoverySystem;
@@ -30,10 +30,25 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Downloads;
+import android.util.AtomicFile;
import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
/**
* Performs a number of miscellaneous, non-system-critical actions
@@ -60,6 +75,10 @@ public class BootReceiver extends BroadcastReceiver {
// Keep a reference to the observer so the finalizer doesn't disable it.
private static FileObserver sTombstoneObserver = null;
+ private static final String LOG_FILES_FILE = "log-files.xml";
+ private static final AtomicFile sFile = new AtomicFile(new File(
+ Environment.getDataSystemDirectory(), LOG_FILES_FILE));
+
@Override
public void onReceive(final Context context, Intent intent) {
// Log boot events in the background to avoid blocking the main thread with I/O
@@ -95,7 +114,6 @@ public class BootReceiver extends BroadcastReceiver {
private void logBootEvents(Context ctx) throws IOException {
final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
- final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
final String headers = new StringBuilder(512)
.append("Build: ").append(Build.FINGERPRINT).append("\n")
.append("Hardware: ").append(Build.BOARD).append("\n")
@@ -122,9 +140,11 @@ public class BootReceiver extends BroadcastReceiver {
.toString();
}
+ HashMap<String, Long> timestamps = readTimestamps();
+
if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
if ("encrypted".equals(SystemProperties.get("ro.crypto.state"))
- && "trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))){
+ && "trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))) {
// Encrypted, first boot to get PIN/pattern/password so data is tmpfs
// Don't set ro.runtime.firstboot so that we will do this again
// when data is properly mounted
@@ -135,17 +155,16 @@ public class BootReceiver extends BroadcastReceiver {
if (db != null) db.addText("SYSTEM_BOOT", headers);
// Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
- addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+ addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
"/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
- addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
- "/sys/fs/pstore/console-ramoops", -LOG_SIZE,
- "SYSTEM_LAST_KMSG");
- addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
- -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
- addFileToDropBox(db, prefs, headers, "/cache/recovery/last_kmsg",
+ addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
+ "/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG");
+ addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE,
+ "SYSTEM_RECOVERY_LOG");
+ addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
-LOG_SIZE, "SYSTEM_RECOVERY_KMSG");
- addAuditErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_AUDIT");
- addFsckErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_FSCK");
+ addAuditErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_AUDIT");
+ addFsckErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
} else {
if (db != null) db.addText("SYSTEM_RESTART", headers);
}
@@ -154,24 +173,29 @@ public class BootReceiver extends BroadcastReceiver {
File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
if (tombstoneFiles[i].isFile()) {
- addFileToDropBox(db, prefs, headers, tombstoneFiles[i].getPath(),
+ addFileToDropBox(db, timestamps, headers, tombstoneFiles[i].getPath(),
LOG_SIZE, "SYSTEM_TOMBSTONE");
}
}
+ writeTimestamps(timestamps);
+
// Start watching for new tombstone files; will record them as they occur.
// This gets registered with the singleton file observer thread.
sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
@Override
public void onEvent(int event, String path) {
+ HashMap<String, Long> timestamps = readTimestamps();
try {
File file = new File(TOMBSTONE_DIR, path);
if (file.isFile()) {
- addFileToDropBox(db, prefs, headers, file.getPath(), LOG_SIZE, "SYSTEM_TOMBSTONE");
+ addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
+ "SYSTEM_TOMBSTONE");
}
} catch (IOException e) {
Slog.e(TAG, "Can't log tombstone", e);
}
+ writeTimestamps(timestamps);
}
};
@@ -179,14 +203,13 @@ public class BootReceiver extends BroadcastReceiver {
}
private static void addFileToDropBox(
- DropBoxManager db, SharedPreferences prefs,
+ DropBoxManager db, HashMap<String, Long> timestamps,
String headers, String filename, int maxSize, String tag) throws IOException {
- addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize,
- tag);
+ addFileWithFootersToDropBox(db, timestamps, headers, "", filename, maxSize, tag);
}
private static void addFileWithFootersToDropBox(
- DropBoxManager db, SharedPreferences prefs,
+ DropBoxManager db, HashMap<String, Long> timestamps,
String headers, String footers, String filename, int maxSize,
String tag) throws IOException {
if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
@@ -195,20 +218,20 @@ public class BootReceiver extends BroadcastReceiver {
long fileTime = file.lastModified();
if (fileTime <= 0) return; // File does not exist
- if (prefs != null) {
- long lastTime = prefs.getLong(filename, 0);
- if (lastTime == fileTime) return; // Already logged this particular file
- // TODO: move all these SharedPreferences Editor commits
- // outside this function to the end of logBootEvents
- prefs.edit().putLong(filename, fileTime).apply();
+ if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) {
+ return; // Already logged this particular file
}
+ timestamps.put(filename, fileTime);
+
Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
- db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers);
+ db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") +
+ footers);
}
- private static void addAuditErrorsToDropBox(DropBoxManager db, SharedPreferences prefs,
- String headers, int maxSize, String tag) throws IOException {
+ private static void addAuditErrorsToDropBox(DropBoxManager db,
+ HashMap<String, Long> timestamps, String headers, int maxSize, String tag)
+ throws IOException {
if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
Slog.i(TAG, "Copying audit failures to DropBox");
@@ -221,14 +244,12 @@ public class BootReceiver extends BroadcastReceiver {
if (fileTime <= 0) return; // File does not exist
- if (prefs != null) {
- long lastTime = prefs.getLong(tag, 0);
- if (lastTime == fileTime) return; // Already logged this particular file
- // TODO: move all these SharedPreferences Editor commits
- // outside this function to the end of logBootEvents
- prefs.edit().putLong(tag, fileTime).apply();
+ if (timestamps.containsKey(tag) && timestamps.get(tag) == fileTime) {
+ return; // Already logged this particular file
}
+ timestamps.put(tag, fileTime);
+
String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
StringBuilder sb = new StringBuilder();
for (String line : log.split("\n")) {
@@ -240,8 +261,9 @@ public class BootReceiver extends BroadcastReceiver {
db.addText(tag, headers + sb.toString());
}
- private static void addFsckErrorsToDropBox(DropBoxManager db, SharedPreferences prefs,
- String headers, int maxSize, String tag) throws IOException {
+ private static void addFsckErrorsToDropBox(DropBoxManager db,
+ HashMap<String, Long> timestamps, String headers, int maxSize, String tag)
+ throws IOException {
boolean upload_needed = false;
if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
Slog.i(TAG, "Checking for fsck errors");
@@ -260,10 +282,103 @@ public class BootReceiver extends BroadcastReceiver {
}
if (upload_needed) {
- addFileToDropBox(db, prefs, headers, "/dev/fscklogs/log", maxSize, tag);
+ addFileToDropBox(db, timestamps, headers, "/dev/fscklogs/log", maxSize, tag);
}
// Remove the file so we don't re-upload if the runtime restarts.
file.delete();
}
+
+ private static HashMap<String, Long> readTimestamps() {
+ synchronized (sFile) {
+ HashMap<String, Long> timestamps = new HashMap<String, Long>();
+ boolean success = false;
+ try (final FileInputStream stream = sFile.openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth(); // Skip the outer <log-files> tag.
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("log")) {
+ final String filename = parser.getAttributeValue(null, "filename");
+ final long timestamp = Long.valueOf(parser.getAttributeValue(
+ null, "timestamp"));
+ timestamps.put(filename, timestamp);
+ } else {
+ Slog.w(TAG, "Unknown tag: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ success = true;
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "No existing last log timestamp file " + sFile.getBaseFile() +
+ "; starting empty");
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ if (!success) {
+ timestamps.clear();
+ }
+ }
+ return timestamps;
+ }
+ }
+
+ private void writeTimestamps(HashMap<String, Long> timestamps) {
+ synchronized (sFile) {
+ final FileOutputStream stream;
+ try {
+ stream = sFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write timestamp file: " + e);
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, "log-files");
+
+ Iterator<String> itor = timestamps.keySet().iterator();
+ while (itor.hasNext()) {
+ String filename = itor.next();
+ out.startTag(null, "log");
+ out.attribute(null, "filename", filename);
+ out.attribute(null, "timestamp", timestamps.get(filename).toString());
+ out.endTag(null, "log");
+ }
+
+ out.endTag(null, "log-files");
+ out.endDocument();
+
+ sFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write timestamp file, using the backup: " + e);
+ sFile.failWrite(stream);
+ }
+ }
+ }
}
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index 0449340ea21a..1b4049212255 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -16,10 +16,6 @@
package com.android.server.backup;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.backup.BackupDataInputStream;
@@ -28,14 +24,21 @@ import android.app.backup.BackupHelper;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SyncAdapterType;
+import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
+import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
@@ -73,6 +76,8 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
private static final String KEY_AUTHORITY_NAME = "name";
private static final String KEY_AUTHORITY_SYNC_STATE = "syncState";
private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled";
+ private static final String STASH_FILE = Environment.getDataDirectory()
+ + "/backup/unadded_account_syncsettings.json";
private Context mContext;
private AccountManager mAccountManager;
@@ -256,41 +261,99 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
}
try {
- HashSet<Account> currentAccounts = getAccountsHashSet();
- for (int i = 0; i < accountJSONArray.length(); i++) {
- JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
- String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
- String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
-
- Account account = new Account(accountName, accountType);
-
- // Check if the account already exists. Accounts that don't exist on the device
- // yet won't be restored.
- if (currentAccounts.contains(account)) {
- restoreExistingAccountSyncSettingsFromJSON(accountJSON);
- } else {
- // TODO:
- // Stash the data to a file that the SyncManager can read from to restore
- // settings at a later date.
- }
- }
+ restoreFromJsonArray(accountJSONArray);
} finally {
// Set the master sync preference to the value from the backup set.
ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
}
-
Log.i(TAG, "Restore successful.");
} catch (IOException | JSONException e) {
Log.e(TAG, "Couldn't restore account sync settings\n" + e);
}
}
+ private void restoreFromJsonArray(JSONArray accountJSONArray)
+ throws JSONException {
+ HashSet<Account> currentAccounts = getAccounts();
+ JSONArray unaddedAccountsJSONArray = new JSONArray();
+ for (int i = 0; i < accountJSONArray.length(); i++) {
+ JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
+ String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
+ String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
+
+ Account account = null;
+ try {
+ account = new Account(accountName, accountType);
+ } catch (IllegalArgumentException iae) {
+ continue;
+ }
+
+ // Check if the account already exists. Accounts that don't exist on the device
+ // yet won't be restored.
+ if (currentAccounts.contains(account)) {
+ if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName);
+ restoreExistingAccountSyncSettingsFromJSON(accountJSON);
+ } else {
+ unaddedAccountsJSONArray.put(accountJSON);
+ }
+ }
+
+ if (unaddedAccountsJSONArray.length() > 0) {
+ try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) {
+ String jsonString = unaddedAccountsJSONArray.toString();
+ DataOutputStream out = new DataOutputStream(fOutput);
+ out.writeUTF(jsonString);
+ } catch (IOException ioe) {
+ // Error in writing to stash file
+ Log.e(TAG, "unable to write the sync settings to the stash file", ioe);
+ }
+ } else {
+ File stashFile = new File(STASH_FILE);
+ if (stashFile.exists()) stashFile.delete();
+ }
+ }
+
+ /**
+ * Restore SyncSettings for all existing accounts from a stashed backup-set
+ */
+ private void accountAddedInternal() {
+ String jsonString;
+
+ try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) {
+ DataInputStream in = new DataInputStream(fIn);
+ jsonString = in.readUTF();
+ } catch (FileNotFoundException fnfe) {
+ // This is expected to happen when there is no accounts info stashed
+ if (DEBUG) Log.d(TAG, "unable to find the stash file", fnfe);
+ return;
+ } catch (IOException ioe) {
+ if (DEBUG) Log.d(TAG, "could not read sync settings from stash file", ioe);
+ return;
+ }
+
+ try {
+ JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString);
+ restoreFromJsonArray(unaddedAccountsJSONArray);
+ } catch (JSONException jse) {
+ // Malformed jsonString
+ Log.e(TAG, "there was an error with the stashed sync settings", jse);
+ }
+ }
+
+ /**
+ * Restore SyncSettings for all existing accounts from a stashed backup-set
+ */
+ public static void accountAdded(Context context) {
+ AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context);
+ helper.accountAddedInternal();
+ }
+
/**
* Helper method - fetch accounts and return them as a HashSet.
*
* @return Accounts in a HashSet.
*/
- private HashSet<Account> getAccountsHashSet() {
+ private HashSet<Account> getAccounts() {
Account[] accounts = mAccountManager.getAccounts();
HashSet<Account> accountHashSet = new HashSet<Account>();
for (Account account : accounts) {
@@ -359,4 +422,4 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
public void writeNewStateDescription(ParcelFileDescriptor newState) {
}
-}
+} \ No newline at end of file
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1b6b53ae49f4..d5f080ae4b27 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -7,7 +7,7 @@ LOCAL_CFLAGS += -U__APPLE__
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
-LOCAL_CFLAGS += -DHWUI_NEW_OPS
+#LOCAL_CFLAGS += -DHWUI_NEW_OPS
LOCAL_CPPFLAGS += -Wno-conversion-null
ifeq ($(TARGET_ARCH), arm)
@@ -33,6 +33,7 @@ LOCAL_SRC_FILES:= \
com_android_internal_content_NativeLibraryHelper.cpp \
com_google_android_gles_jni_EGLImpl.cpp \
com_google_android_gles_jni_GLImpl.cpp.arm \
+ android_app_ApplicationLoaders.cpp \
android_app_NativeActivity.cpp \
android_auditing_SecurityLog.cpp \
android_opengl_EGL14.cpp \
@@ -177,8 +178,7 @@ LOCAL_SRC_FILES:= \
com_android_internal_net_NetworkStatsFactory.cpp \
com_android_internal_os_Zygote.cpp \
com_android_internal_util_VirtualRefBasePtr.cpp \
- com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
- android_os_HardwarePropertiesManager.cpp
+ com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
@@ -260,7 +260,8 @@ LOCAL_SHARED_LIBRARIES := \
libprocessgroup \
libnativebridge \
libradio_metadata \
- libnativeloader
+ libnativeloader \
+ libmemunreachable \
LOCAL_SHARED_LIBRARIES += \
libhwui \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 223fc1af46d5..6ed07a7c9990 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -177,6 +177,7 @@ extern int register_android_backup_BackupDataOutput(JNIEnv *env);
extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
extern int register_android_app_backup_FullBackup(JNIEnv *env);
+extern int register_android_app_ApplicationLoaders(JNIEnv* env);
extern int register_android_app_ActivityThread(JNIEnv *env);
extern int register_android_app_NativeActivity(JNIEnv *env);
extern int register_android_media_RemoteDisplay(JNIEnv *env);
@@ -198,7 +199,6 @@ extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
-extern int register_android_os_HardwarePropertiesManager(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -1372,6 +1372,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_backup_FileBackupHelperBase),
REG_JNI(register_android_backup_BackupHelperDispatcher),
REG_JNI(register_android_app_backup_FullBackup),
+ REG_JNI(register_android_app_ApplicationLoaders),
REG_JNI(register_android_app_ActivityThread),
REG_JNI(register_android_app_NativeActivity),
REG_JNI(register_android_util_jar_StrictJarFile),
@@ -1390,7 +1391,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_animation_PropertyValuesHolder),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
- REG_JNI(register_android_os_HardwarePropertiesManager),
};
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 92f781268732..29c1075a3420 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -505,12 +505,6 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
}
-// Need to buffer enough input to be able to rewind as much as might be read by a decoder
-// trying to determine the stream's format. Currently the most is 64, read by
-// SkWebpCodec.
-// FIXME: Get this number from SkCodec
-#define BYTES_TO_BUFFER 64
-
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
jobject padding, jobject options) {
@@ -519,7 +513,7 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA
if (stream.get()) {
std::unique_ptr<SkStreamRewindable> bufferedStream(
- SkFrontBufferedStream::Create(stream.release(), BYTES_TO_BUFFER));
+ SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded()));
SkASSERT(bufferedStream.get() != NULL);
bitmap = doDecode(env, bufferedStream.release(), padding, options);
}
@@ -561,11 +555,17 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
SkFILEStream::kCallerPasses_Ownership));
+ // If there is no offset for the file descriptor, we use SkFILEStream directly.
+ if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
+ assert(isSeekable(dupDescriptor));
+ return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions);
+ }
+
// Use a buffered stream. Although an SkFILEStream can be rewound, this
// ensures that SkImageDecoder::Factory never rewinds beyond the
// current position of the file descriptor.
std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
- BYTES_TO_BUFFER));
+ SkCodec::MinBufferedBytesNeeded()));
return doDecode(env, stream.release(), padding, bitmapFactoryOptions);
}
@@ -590,7 +590,7 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
- return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
+ return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE;
}
jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 7c8dbe8ecf23..2e974a3ecaa3 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -20,11 +20,13 @@
#include <core_jni_helpers.h>
#include "SkData.h"
+#include "SkFontMgr.h"
#include "SkRefCnt.h"
#include "SkTypeface.h"
#include "GraphicsJNI.h"
#include <ScopedPrimitiveArray.h>
#include <ScopedUtfChars.h>
+#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include "Utils.h"
@@ -33,6 +35,8 @@
#include <minikin/FontFamily.h>
#include "MinikinSkia.h"
+#include <memory>
+
namespace android {
static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
@@ -69,13 +73,89 @@ static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr,
return addSkTypeface(fontFamily, face);
}
+static struct {
+ jmethodID mGet;
+ jmethodID mSize;
+} gListClassInfo;
+
+static struct {
+ jfieldID mTag;
+ jfieldID mStyleValue;
+} gAxisClassInfo;
+
+static void release_global_ref(const void* /*data*/, void* context) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ bool needToAttach = (env == NULL);
+ if (needToAttach) {
+ JavaVMAttachArgs args;
+ args.version = JNI_VERSION_1_4;
+ args.name = "release_font_data";
+ args.group = NULL;
+ jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
+ if (result != JNI_OK) {
+ ALOGE("failed to attach to thread to release global ref.");
+ return;
+ }
+ }
+
+ jobject obj = reinterpret_cast<jobject>(context);
+ env->DeleteGlobalRef(obj);
+
+ if (needToAttach) {
+ AndroidRuntime::getJavaVM()->DetachCurrentThread();
+ }
+}
+
static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
- jstring path, jint ttcIndex, jint weight, jboolean isItalic) {
- NPE_CHECK_RETURN_ZERO(env, path);
- ScopedUtfChars str(env, path);
- SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
+ jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
+ NPE_CHECK_RETURN_ZERO(env, font);
+
+ // Declare axis native type.
+ std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes;
+ int skiaAxesLength = 0;
+ if (listOfAxis) {
+ jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize);
+
+ skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]);
+ skiaAxesLength = listSize;
+ for (jint i = 0; i < listSize; ++i) {
+ jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i);
+ if (!axisObject) {
+ skiaAxes[i].fTag = 0;
+ skiaAxes[i].fStyleValue = 0;
+ continue;
+ }
+
+ jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag);
+ jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue);
+ skiaAxes[i].fTag = tag;
+ skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue);
+ }
+ }
+
+ void* fontPtr = env->GetDirectBufferAddress(font);
+ if (fontPtr == NULL) {
+ ALOGE("addFont failed to create font, buffer invalid");
+ return false;
+ }
+ jlong fontSize = env->GetDirectBufferCapacity(font);
+ if (fontSize < 0) {
+ ALOGE("addFont failed to create font, buffer size invalid");
+ return false;
+ }
+ jobject fontRef = MakeGlobalRefOrDie(env, font);
+ SkAutoTUnref<SkData> data(SkData::NewWithProc(fontPtr, fontSize,
+ release_global_ref, reinterpret_cast<void*>(fontRef)));
+ std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data));
+
+ SkFontMgr::FontParameters params;
+ params.setCollectionIndex(ttcIndex);
+ params.setAxes(skiaAxes.get(), skiaAxesLength);
+
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ SkTypeface* face = fm->createFromStream(fontData.release(), params);
if (face == NULL) {
- ALOGE("addFont failed to create font %s", str.c_str());
+ ALOGE("addFont failed to create font, invalid request");
return false;
}
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
@@ -129,15 +209,26 @@ static const JNINativeMethod gFontFamilyMethods[] = {
{ "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
{ "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont },
- { "nAddFontWeightStyle", "(JLjava/lang/String;IIZ)Z", (void*)FontFamily_addFontWeightStyle },
+ { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
+ (void*)FontFamily_addFontWeightStyle },
{ "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
- (void*)FontFamily_addFontFromAsset },
+ (void*)FontFamily_addFontFromAsset },
};
int register_android_graphics_FontFamily(JNIEnv* env)
{
- return RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
- NELEM(gFontFamilyMethods));
+ 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/graphics/FontListParser$Axis");
+ gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I");
+ gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F");
+
+ return err;
}
}
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index ae99f0bff330..731d22ada710 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -39,7 +39,6 @@
#include <SkPoint.h>
#include <SkRect.h>
#include <SkTypeface.h>
-#include <SkUtils.h>
#include <hb.h>
@@ -82,17 +81,16 @@ static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint
static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData)
{
HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData);
+ SkPaint* paint = hbFontData->m_paint;
+ paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
if (unicode > 0x10ffff) {
unicode = 0xfffd;
}
- SkPaint* paint = hbFontData->m_paint;
- // It would be better to use kUTF32_TextEncoding directly
- paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ SkUnichar unichar = unicode;
+
uint16_t glyph16;
- uint16_t unichar[2];
- size_t size = SkUTF16_FromUnichar(unicode, unichar);
- paint->textToGlyphs(unichar, size * sizeof(*unichar), &glyph16);
+ paint->textToGlyphs(&unichar, sizeof(unichar), &glyph16);
*glyph = glyph16;
return !!*glyph;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index a3214eb2c9e3..d00e94ca4fd9 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -654,15 +654,14 @@ namespace PaintGlue {
size_t measuredCount = 0;
float measured = 0;
- Layout layout;
- MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
- float* advances = new float[count];
- layout.getAdvances(advances);
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
+ advancesArray.get());
for (int i = 0; i < count; i++) {
// traverse in the given direction
int index = forwardScan ? i : (count - i - 1);
- float width = advances[index];
+ float width = advancesArray[index];
if (measured + width > maxWidth) {
break;
}
@@ -672,7 +671,6 @@ namespace PaintGlue {
}
measured += width;
}
- delete[] advances;
if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
@@ -824,10 +822,15 @@ namespace PaintGlue {
static jfloat doRunAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
- Layout layout;
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize);
- return getRunAdvance(layout, buf, start, count, offset);
+ if (offset == count) {
+ return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
+ bufSize, nullptr);
+ }
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
+ advancesArray.get());
+ return getRunAdvance(advancesArray.get(), buf, start, count, offset);
}
static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle,
@@ -845,11 +848,13 @@ namespace PaintGlue {
static jint doOffsetForAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) {
- Layout layout;
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize);
- return getOffsetForAdvance(layout, buf, start, count, advance);
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
+ advancesArray.get());
+ return getOffsetForAdvance(advancesArray.get(), buf, start, count, advance);
}
+
static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle,
jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
jint contextEnd, jboolean isRtl, jfloat advance) {
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index bcd0b60308bb..0c30fdc63905 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -212,17 +212,16 @@ static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
android::Parcel* p = android::parcelForJavaObject(env, parcel);
- const size_t size = p->readInt32();
- const void* regionData = p->readInplace(size);
- if (regionData == nullptr) {
+ std::vector<int32_t> rects;
+ p->readInt32Vector(&rects);
+
+ if ((rects.size() % 4) != 0) {
return 0;
}
SkRegion* region = new SkRegion;
- size_t actualSize = region->readFromMemory(regionData, size);
- if (size != actualSize) {
- delete region;
- return 0;
+ for (size_t x = 0; x + 4 <= rects.size(); x += 4) {
+ region->op(rects[x], rects[x+1], rects[x+2], rects[x+3], SkRegion::kUnion_Op);
}
return reinterpret_cast<jlong>(region);
@@ -237,19 +236,18 @@ static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHan
android::Parcel* p = android::parcelForJavaObject(env, parcel);
- const size_t size = region->writeToMemory(nullptr);
- p->writeInt32(size);
- void* dst = p->writeInplace(size);
- if (dst == nullptr) {
- ALOGE("Region.writeToParcel could not write %zi bytes", size);
- return JNI_FALSE;
- }
- const size_t sizeWritten = region->writeToMemory(dst);
- if (sizeWritten != size) {
- ALOGE("SkRegion::writeToMemory should have written %zi bytes but wrote %zi",
- size, sizeWritten);
+ std::vector<int32_t> rects;
+ SkRegion::Iterator it(*region);
+ while (!it.done()) {
+ const SkIRect& r = it.rect();
+ rects.push_back(r.fLeft);
+ rects.push_back(r.fTop);
+ rects.push_back(r.fRight);
+ rects.push_back(r.fBottom);
+ it.next();
}
+ p->writeInt32Vector(rects);
return JNI_TRUE;
}
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 2507e4ddea7e..de32dd92c6e4 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -1,5 +1,4 @@
#include "GraphicsJNI.h"
-#include "SkComposeShader.h"
#include "SkGradientShader.h"
#include "SkShader.h"
#include "SkXfermode.h"
@@ -232,7 +231,7 @@ static jlong ComposeShader_create1(JNIEnv* env, jobject o,
SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
- SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
+ SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, mode);
return reinterpret_cast<jlong>(shader);
}
@@ -243,7 +242,7 @@ static jlong ComposeShader_create2(JNIEnv* env, jobject o,
SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
- SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
+ SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, xfermode.get());
return reinterpret_cast<jlong>(shader);
}
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 4f9ce8bfcef7..5fa445e256fe 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -116,3 +116,7 @@ jobject android::nullObjectReturn(const char msg[]) {
}
return NULL;
}
+
+bool android::isSeekable(int descriptor) {
+ return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
+}
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index c0b941004758..d1a74a0adf6c 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -68,6 +68,10 @@ private:
jobject nullObjectReturn(const char msg[]);
+/** Check if the file descriptor is seekable.
+ */
+bool isSeekable(int descriptor);
+
}; // namespace android
#endif // _ANDROID_GRAPHICS_UTILS_H_
diff --git a/core/jni/android_app_ApplicationLoaders.cpp b/core/jni/android_app_ApplicationLoaders.cpp
new file mode 100644
index 000000000000..89f22eba0f30
--- /dev/null
+++ b/core/jni/android_app_ApplicationLoaders.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 <string>
+
+#include "nativeloader/native_loader.h"
+
+#include "core_jni_helpers.h"
+
+
+static jstring createClassloaderNamespace_native(JNIEnv* env,
+ jobject clazz,
+ jobject classLoader,
+ jint targetSdkVersion,
+ jstring librarySearchPath,
+ jstring libraryPermittedPath,
+ jboolean isShared) {
+ return android::CreateClassLoaderNamespace(env, targetSdkVersion,
+ classLoader, isShared == JNI_TRUE,
+ librarySearchPath, libraryPermittedPath);
+}
+
+static const JNINativeMethod g_methods[] = {
+ { "createClassloaderNamespace",
+ "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;",
+ reinterpret_cast<void*>(createClassloaderNamespace_native) },
+};
+
+static const char* const kApplicationLoadersPathName = "android/app/ApplicationLoaders";
+
+namespace android
+{
+
+int register_android_app_ApplicationLoaders(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, kApplicationLoadersPathName, g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 88a56d2084d0..6431b94be4d3 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -259,8 +259,7 @@ static jlong
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
jobject messageQueue, jstring internalDataDir, jstring obbDir,
jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
- jbyteArray savedState, jobject classLoader, jstring libraryPath,
- jstring isolationPath) {
+ jbyteArray savedState, jobject classLoader, jstring libraryPath) {
if (kLogTrace) {
ALOGD("loadNativeCode_native");
}
@@ -269,8 +268,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName
std::unique_ptr<NativeCode> code;
bool needNativeBridge = false;
- void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader,
- false, libraryPath, isolationPath);
+ void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader, libraryPath);
if (handle == NULL) {
if (NativeBridgeIsSupported(pathStr)) {
handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
@@ -656,7 +654,7 @@ onContentRectChanged_native(JNIEnv* env, jobject clazz, jlong handle,
static const JNINativeMethod g_methods[] = {
{ "loadNativeCode",
- "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)J",
+ "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;)J",
(void*)loadNativeCode_native },
{ "getDlError", "()Ljava/lang/String;", (void*) getDlError_native },
{ "unloadNativeCode", "(J)V", (void*)unloadNativeCode_native },
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 7a3c598e0aed..4b2a72d8e28e 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -43,12 +43,13 @@ static JNIEnv* getEnv(JavaVM* vm) {
return env;
}
-static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) {
+static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) {
class AnimationListenerBridge : public AnimationListener {
public:
- AnimationListenerBridge(JNIEnv* env, jobject finishListener) {
+ AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) {
mFinishListener = env->NewGlobalRef(finishListener);
env->GetJavaVM(&mJvm);
+ mId = id;
}
virtual ~AnimationListenerBridge() {
@@ -63,7 +64,7 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis
env->CallStaticVoidMethod(
gVectorDrawableAnimatorClassInfo.clazz,
gVectorDrawableAnimatorClassInfo.callOnFinished,
- mFinishListener);
+ mFinishListener, mId);
releaseJavaObject();
}
@@ -76,8 +77,9 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis
JavaVM* mJvm;
jobject mFinishListener;
+ jint mId;
};
- return new AnimationListenerBridge(env, finishListener);
+ return new AnimationListenerBridge(env, finishListener, id);
}
static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr,
@@ -142,15 +144,16 @@ static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
holder->setPropertyDataSource(propertyData, length);
env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
}
-static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
+static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
- // TODO: keep a ref count in finish listener
- AnimationListener* listener = createAnimationListener(env, finishListener);
+ AnimationListener* listener = createAnimationListener(env, finishListener, id);
set->start(listener);
}
-static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
- // TODO: implement reverse
+static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
+ PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
+ AnimationListener* listener = createAnimationListener(env, finishListener, id);
+ set->reverse(listener);
}
static void end(JNIEnv*, jobject, jlong animatorSetPtr) {
@@ -172,13 +175,13 @@ static const JNINativeMethod gMethods[] = {
{"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
{"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
{"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData},
- {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)start},
- {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse},
+ {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
+ {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
{"nEnd", "!(J)V", (void*)end},
{"nReset", "!(J)V", (void*)reset},
};
-const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator";
+const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT";
int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {
gVectorDrawableAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName);
gVectorDrawableAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env,
@@ -186,7 +189,7 @@ int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {
gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
- "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V");
+ "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V");
return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index bb13c35ced1f..651330446382 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -31,6 +31,7 @@
#define ENCODING_AAC_LC 10
#define ENCODING_AAC_HE_V1 11
#define ENCODING_AAC_HE_V2 12
+#define ENCODING_IEC61937 13
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -64,6 +65,8 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_AAC_HE_V1;
case ENCODING_AAC_HE_V2:
return AUDIO_FORMAT_AAC_HE_V2;
+ case ENCODING_IEC61937:
+ return AUDIO_FORMAT_IEC61937;
case ENCODING_DEFAULT:
return AUDIO_FORMAT_DEFAULT;
default:
@@ -103,6 +106,8 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
return ENCODING_AAC_HE_V1;
case AUDIO_FORMAT_AAC_HE_V2:
return ENCODING_AAC_HE_V2;
+ case AUDIO_FORMAT_IEC61937:
+ return ENCODING_IEC61937;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d25da7823719..3e4e3522d5dd 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -180,54 +180,15 @@ static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioR
// ----------------------------------------------------------------------------
static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask,
- jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
+ jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
+ jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
+ jlong nativeRecordInJavaObj)
{
//ALOGV(">> Entering android_media_AudioRecord_setup");
- //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
- // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
-
- if (jaa == 0) {
- ALOGE("Error creating AudioRecord: invalid audio attributes");
- return (jint) AUDIO_JAVA_ERROR;
- }
-
- // channel index mask takes priority over channel position masks.
- if (channelIndexMask) {
- // Java channel index masks need the representation bits set.
- channelMask = audio_channel_mask_from_representation_and_bits(
- AUDIO_CHANNEL_REPRESENTATION_INDEX,
- channelIndexMask);
- }
- // Java channel position masks map directly to the native definition
-
- if (!audio_is_input_channel(channelMask)) {
- ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
- return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
- }
- uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
-
- // compare the format against the Java constants
- audio_format_t format = audioFormatToNative(audioFormat);
- if (format == AUDIO_FORMAT_INVALID) {
- ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
- return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
- }
-
- size_t bytesPerSample = audio_bytes_per_sample(format);
-
- if (buffSizeInBytes == 0) {
- ALOGE("Error creating AudioRecord: frameCount is 0.");
- return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
- }
- size_t frameSize = channelCount * bytesPerSample;
- size_t frameCount = buffSizeInBytes / frameSize;
-
- jclass clazz = env->GetObjectClass(thiz);
- if (clazz == NULL) {
- ALOGE("Can't find %s when setting up callback.", kClassPathName);
- return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
- }
+ //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d "
+ // "nativeRecordInJavaObj=0x%llX",
+ // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes, nativeRecordInJavaObj);
+ audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
if (jSession == NULL) {
ALOGE("Error creating AudioRecord: invalid session ID pointer");
@@ -243,55 +204,132 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
- ScopedUtfChars opPackageNameStr(env, opPackageName);
+ audio_attributes_t *paa = NULL;
+ sp<AudioRecord> lpRecorder = 0;
+ audiorecord_callback_cookie *lpCallbackData = NULL;
+
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ ALOGE("Can't find %s when setting up callback.", kClassPathName);
+ return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
+ }
+
+ // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
+ if (nativeRecordInJavaObj == 0) {
+ if (jaa == 0) {
+ ALOGE("Error creating AudioRecord: invalid audio attributes");
+ return (jint) AUDIO_JAVA_ERROR;
+ }
- // create an uninitialized AudioRecord object
- sp<AudioRecord> lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
+ if (jSampleRate == 0) {
+ ALOGE("Error creating AudioRecord: invalid sample rates");
+ return (jint) AUDIO_JAVA_ERROR;
+ }
+ jint elements[1];
+ env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
+ int sampleRateInHertz = elements[0];
+
+ // channel index mask takes priority over channel position masks.
+ if (channelIndexMask) {
+ // Java channel index masks need the representation bits set.
+ localChanMask = audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_INDEX,
+ channelIndexMask);
+ }
+ // Java channel position masks map directly to the native definition
- audio_attributes_t *paa = NULL;
- // read the AudioAttributes values
- paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
- const jstring jtags =
- (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
- const char* tags = env->GetStringUTFChars(jtags, NULL);
- // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
- strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
- env->ReleaseStringUTFChars(jtags, tags);
- paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
- paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
- ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
-
- audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
- if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
- flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
- }
- // create the callback information:
- // this data will be passed with every AudioRecord callback
- audiorecord_callback_cookie *lpCallbackData = new audiorecord_callback_cookie;
- lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
- // we use a weak reference so the AudioRecord object can be garbage collected.
- lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
- lpCallbackData->busy = false;
-
- const status_t status = lpRecorder->set(paa->source,
- sampleRateInHertz,
- format, // word length, PCM
- channelMask,
- frameCount,
- recorderCallback,// callback_t
- lpCallbackData,// void* user
- 0, // notificationFrames,
- true, // threadCanCallJava
- sessionId,
- AudioRecord::TRANSFER_DEFAULT,
- flags,
- -1, -1, // default uid, pid
- paa);
-
- if (status != NO_ERROR) {
- ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
- status);
- goto native_init_failure;
+ if (!audio_is_input_channel(localChanMask)) {
+ ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
+ return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
+ }
+ uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
+
+ // compare the format against the Java constants
+ audio_format_t format = audioFormatToNative(audioFormat);
+ if (format == AUDIO_FORMAT_INVALID) {
+ ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
+ return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
+ }
+
+ size_t bytesPerSample = audio_bytes_per_sample(format);
+
+ if (buffSizeInBytes == 0) {
+ ALOGE("Error creating AudioRecord: frameCount is 0.");
+ return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
+ }
+ size_t frameSize = channelCount * bytesPerSample;
+ size_t frameCount = buffSizeInBytes / frameSize;
+
+ ScopedUtfChars opPackageNameStr(env, opPackageName);
+
+ // create an uninitialized AudioRecord object
+ lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
+
+ // read the AudioAttributes values
+ paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+ const jstring jtags =
+ (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
+ const char* tags = env->GetStringUTFChars(jtags, NULL);
+ // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
+ strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ env->ReleaseStringUTFChars(jtags, tags);
+ paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
+ paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+ ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
+
+ audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+ if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
+ flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
+ }
+ // create the callback information:
+ // this data will be passed with every AudioRecord callback
+ lpCallbackData = new audiorecord_callback_cookie;
+ lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioRecord object can be garbage collected.
+ lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+ lpCallbackData->busy = false;
+
+ const status_t status = lpRecorder->set(paa->source,
+ sampleRateInHertz,
+ format, // word length, PCM
+ localChanMask,
+ frameCount,
+ recorderCallback,// callback_t
+ lpCallbackData,// void* user
+ 0, // notificationFrames,
+ true, // threadCanCallJava
+ sessionId,
+ AudioRecord::TRANSFER_DEFAULT,
+ flags,
+ -1, -1, // default uid, pid
+ paa);
+
+ if (status != NO_ERROR) {
+ ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
+ status);
+ goto native_init_failure;
+ }
+ } else { // end if nativeRecordInJavaObj == 0)
+ lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
+ // TODO: We need to find out which members of the Java AudioRecord might need to be
+ // initialized from the Native AudioRecord
+ // these are directly returned from getters:
+ // mSampleRate
+ // mRecordSource
+ // mAudioFormat
+ // mChannelMask
+ // mChannelCount
+ // mState (?)
+ // mRecordingState (?)
+ // mPreferredDevice
+
+ // create the callback information:
+ // this data will be passed with every AudioRecord callback
+ lpCallbackData = new audiorecord_callback_cookie;
+ lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioRecord object can be garbage collected.
+ lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+ lpCallbackData->busy = false;
}
nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
@@ -304,6 +342,11 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
+ {
+ const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
+ env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
+ }
+
{ // scope for the lock
Mutex::Autolock l(sLock);
sAudioRecordCallBackCookies.add(lpCallbackData);
@@ -693,11 +736,8 @@ static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
return (jint)AUDIO_JAVA_ERROR;
}
- // TODO Enable.
-#if 0
- // get the record timestamp
ExtendedTimestamp ts;
- jint status = nativeToJavaStatus(lpRecorder->getExtendedTimestamp(&ts));
+ jint status = nativeToJavaStatus(lpRecorder->getTimestamp(&ts));
if (status == AUDIO_JAVA_SUCCESS) {
// set the data
@@ -712,9 +752,6 @@ static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
}
}
return status;
-#else
- return (jint)AUDIO_JAVA_INVALID_OPERATION;
-#endif
}
// ----------------------------------------------------------------------------
@@ -723,8 +760,8 @@ static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_start", "(II)I", (void *)android_media_AudioRecord_start},
{"native_stop", "()V", (void *)android_media_AudioRecord_stop},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIII[ILjava/lang/String;)I",
- (void *)android_media_AudioRecord_setup},
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
+ (void *)android_media_AudioRecord_setup},
{"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
{"native_release", "()V", (void *)android_media_AudioRecord_release},
{"native_read_in_byte_array",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8e8f6c371204..2fb749866f62 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -128,11 +128,12 @@ static struct {
// other fields unused by JNI
} gAudioMixingRuleFields;
-static jclass gAttributeMatchCriterionClass;
+static jclass gAudioMixMatchCriterionClass;
static struct {
jfieldID mAttr;
+ jfieldID mIntProp;
jfieldID mRule;
-} gAttributeMatchCriterionFields;
+} gAudioMixMatchCriterionFields;
static jclass gAudioAttributesClass;
static struct {
@@ -387,18 +388,47 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val)
}
static void
-android_media_AudioSystem_recording_callback(int event, int session, int source)
+android_media_AudioSystem_recording_callback(int event, int session, int source,
+ const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
+ audio_patch_handle_t patchHandle)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
return;
}
+ if (clientConfig == NULL || deviceConfig == NULL) {
+ ALOGE("Unexpected null client/device configurations in recording callback");
+ return;
+ }
+ // create an array for 2*3 integers to store the record configurations (client + device)
+ // plus 1 integer for the patch handle
+ const int REC_PARAM_SIZE = 7;
+ jintArray recParamArray = env->NewIntArray(REC_PARAM_SIZE);
+ if (recParamArray == NULL) {
+ ALOGE("recording callback: Couldn't allocate int array for configuration data");
+ return;
+ }
+ jint recParamData[REC_PARAM_SIZE];
+ recParamData[0] = (jint) audioFormatFromNative(clientConfig->format);
+ // FIXME this doesn't support index-based masks
+ recParamData[1] = (jint) inChannelMaskFromNative(clientConfig->channel_mask);
+ recParamData[2] = (jint) clientConfig->sample_rate;
+ recParamData[3] = (jint) audioFormatFromNative(deviceConfig->format);
+ // FIXME this doesn't support index-based masks
+ recParamData[4] = (jint) inChannelMaskFromNative(deviceConfig->channel_mask);
+ recParamData[5] = (jint) deviceConfig->sample_rate;
+ recParamData[6] = (jint) patchHandle;
+ env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData);
+
+ // callback into java
jclass clazz = env->FindClass(kClassPathName);
env->CallStaticVoidMethod(clazz,
gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
- event, session, source);
+ event, session, source, recParamArray);
env->DeleteLocalRef(clazz);
+
+ env->DeleteLocalRef(recParamArray);
}
static jint
@@ -1563,22 +1593,32 @@ static jint convertAudioMixToNative(JNIEnv *env,
}
for (jint i = 0; i < numCriteria; i++) {
- AttributeMatchCriterion nCriterion;
+ AudioMixMatchCriterion nCriterion;
jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
- nCriterion.mRule = env->GetIntField(jCriterion, gAttributeMatchCriterionFields.mRule);
+ nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
- jobject jAttributes = env->GetObjectField(jCriterion, gAttributeMatchCriterionFields.mAttr);
- if (nCriterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
- nCriterion.mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
- nCriterion.mAttr.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
- gAudioAttributesFields.mUsage);
- } else {
- nCriterion.mAttr.mSource = (audio_source_t)env->GetIntField(jAttributes,
- gAudioAttributesFields.mSource);
+ const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
+ switch (match_rule) {
+ case RULE_MATCH_UID:
+ nCriterion.mValue.mUid = env->GetIntField(jCriterion,
+ gAudioMixMatchCriterionFields.mIntProp);
+ break;
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
+ jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
+ if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
+ nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
+ gAudioAttributesFields.mUsage);
+ } else {
+ nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
+ gAudioAttributesFields.mSource);
+ }
+ env->DeleteLocalRef(jAttributes);
+ }
+ break;
}
- env->DeleteLocalRef(jAttributes);
nAudioMix->mCriteria.add(nCriterion);
env->DeleteLocalRef(jCriterion);
@@ -1808,7 +1848,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
"dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
- "recordingCallbackFromNative", "(III)V");
+ "recordingCallbackFromNative", "(III[I)V");
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
@@ -1833,12 +1873,14 @@ int register_android_media_AudioSystem(JNIEnv *env)
gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
"Ljava/util/ArrayList;");
- jclass attributeMatchCriterionClass =
- FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion");
- gAttributeMatchCriterionClass = MakeGlobalRefOrDie(env, attributeMatchCriterionClass);
- gAttributeMatchCriterionFields.mAttr = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mAttr",
+ jclass audioMixMatchCriterionClass =
+ FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
+ gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
+ gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
"Landroid/media/AudioAttributes;");
- gAttributeMatchCriterionFields.mRule = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mRule",
+ gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
+ "I");
+ gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
"I");
jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 61f185e10f4c..660cbdcb4546 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -213,51 +213,17 @@ static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
// ----------------------------------------------------------------------------
static jint
-android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jobject jaa,
- jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask,
- jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
+android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
+ jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
+ jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
+ jlong nativeAudioTrack) {
- ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
- sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
+ ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
+ "nativeAudioTrack=0x%llX",
+ jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
+ nativeAudioTrack);
- if (jaa == 0) {
- ALOGE("Error creating AudioTrack: invalid audio attributes");
- return (jint) AUDIO_JAVA_ERROR;
- }
-
- // Invalid channel representations are caught by !audio_is_output_channel() below.
- audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
- channelPositionMask, channelIndexMask);
- if (!audio_is_output_channel(nativeChannelMask)) {
- ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
- return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
- }
-
- uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
-
- // check the format.
- // This function was called from Java, so we compare the format against the Java constants
- audio_format_t format = audioFormatToNative(audioFormat);
- if (format == AUDIO_FORMAT_INVALID) {
- ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
- return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
- }
-
- // compute the frame count
- size_t frameCount;
- if (audio_is_linear_pcm(format)) {
- const size_t bytesPerSample = audio_bytes_per_sample(format);
- frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
- } else {
- frameCount = buffSizeInBytes;
- }
-
- jclass clazz = env->GetObjectClass(thiz);
- if (clazz == NULL) {
- ALOGE("Can't find %s when setting up callback.", kClassPathName);
- return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
- }
+ sp<AudioTrack> lpTrack = 0;
if (jSession == NULL) {
ALOGE("Error creating AudioTrack: invalid session ID pointer");
@@ -273,91 +239,168 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
- // create the native AudioTrack object
- sp<AudioTrack> lpTrack = new AudioTrack();
+ AudioTrackJniStorage* lpJniStorage = NULL;
audio_attributes_t *paa = NULL;
- // read the AudioAttributes values
- paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
- const jstring jtags =
- (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
- const char* tags = env->GetStringUTFChars(jtags, NULL);
- // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
- strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
- env->ReleaseStringUTFChars(jtags, tags);
- paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
- paa->content_type =
- (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
- paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
-
- ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
- paa->usage, paa->content_type, paa->flags, paa->tags);
-
- // initialize the callback information:
- // this data will be passed with every AudioTrack callback
- AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
- lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
- // we use a weak reference so the AudioTrack object can be garbage collected.
- lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
- lpJniStorage->mCallbackData.busy = false;
-
- // initialize the native AudioTrack object
- status_t status = NO_ERROR;
- switch (memoryMode) {
- case MODE_STREAM:
-
- status = lpTrack->set(
- AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
- sampleRateInHertz,
- format,// word length, PCM
- nativeChannelMask,
- frameCount,
- AUDIO_OUTPUT_FLAG_NONE,
- audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
- 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
- 0,// shared mem
- true,// thread can call Java
- sessionId,// audio session ID
- AudioTrack::TRANSFER_SYNC,
- NULL, // default offloadInfo
- -1, -1, // default uid, pid values
- paa);
- break;
- case MODE_STATIC:
- // AudioTrack is using shared memory
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ ALOGE("Can't find %s when setting up callback.", kClassPathName);
+ return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+ }
- if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
- ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
- goto native_init_failure;
+ // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
+ if (nativeAudioTrack == 0) {
+ if (jaa == 0) {
+ ALOGE("Error creating AudioTrack: invalid audio attributes");
+ return (jint) AUDIO_JAVA_ERROR;
}
- status = lpTrack->set(
- AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
- sampleRateInHertz,
- format,// word length, PCM
- nativeChannelMask,
- frameCount,
- AUDIO_OUTPUT_FLAG_NONE,
- audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
- 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
- lpJniStorage->mMemBase,// shared mem
- true,// thread can call Java
- sessionId,// audio session ID
- AudioTrack::TRANSFER_SHARED,
- NULL, // default offloadInfo
- -1, -1, // default uid, pid values
- paa);
- break;
+ if (jSampleRate == 0) {
+ ALOGE("Error creating AudioTrack: invalid sample rates");
+ return (jint) AUDIO_JAVA_ERROR;
+ }
- default:
- ALOGE("Unknown mode %d", memoryMode);
- goto native_init_failure;
- }
+ int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
+ int sampleRateInHertz = sampleRates[0];
+ env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
- if (status != NO_ERROR) {
- ALOGE("Error %d initializing AudioTrack", status);
- goto native_init_failure;
+ // Invalid channel representations are caught by !audio_is_output_channel() below.
+ audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
+ channelPositionMask, channelIndexMask);
+ if (!audio_is_output_channel(nativeChannelMask)) {
+ ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
+ return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
+ }
+
+ uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
+
+ // check the format.
+ // This function was called from Java, so we compare the format against the Java constants
+ audio_format_t format = audioFormatToNative(audioFormat);
+ if (format == AUDIO_FORMAT_INVALID) {
+ ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
+ return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
+ }
+
+ // compute the frame count
+ size_t frameCount;
+ if (audio_is_linear_pcm(format)) {
+ const size_t bytesPerSample = audio_bytes_per_sample(format);
+ frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
+ } else {
+ frameCount = buffSizeInBytes;
+ }
+
+ // create the native AudioTrack object
+ lpTrack = new AudioTrack();
+
+ // read the AudioAttributes values
+ paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+ const jstring jtags =
+ (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
+ const char* tags = env->GetStringUTFChars(jtags, NULL);
+ // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
+ strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ env->ReleaseStringUTFChars(jtags, tags);
+ paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
+ paa->content_type =
+ (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
+ paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+
+ ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
+ paa->usage, paa->content_type, paa->flags, paa->tags);
+
+ // initialize the callback information:
+ // this data will be passed with every AudioTrack callback
+ lpJniStorage = new AudioTrackJniStorage();
+ lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioTrack object can be garbage collected.
+ lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+ lpJniStorage->mCallbackData.busy = false;
+
+ // initialize the native AudioTrack object
+ status_t status = NO_ERROR;
+ switch (memoryMode) {
+ case MODE_STREAM:
+
+ status = lpTrack->set(
+ AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
+ sampleRateInHertz,
+ format,// word length, PCM
+ nativeChannelMask,
+ frameCount,
+ AUDIO_OUTPUT_FLAG_NONE,
+ audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
+ 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+ 0,// shared mem
+ true,// thread can call Java
+ sessionId,// audio session ID
+ AudioTrack::TRANSFER_SYNC,
+ NULL, // default offloadInfo
+ -1, -1, // default uid, pid values
+ paa);
+ break;
+
+ case MODE_STATIC:
+ // AudioTrack is using shared memory
+
+ if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
+ ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
+ goto native_init_failure;
+ }
+
+ status = lpTrack->set(
+ AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
+ sampleRateInHertz,
+ format,// word length, PCM
+ nativeChannelMask,
+ frameCount,
+ AUDIO_OUTPUT_FLAG_NONE,
+ audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
+ 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+ lpJniStorage->mMemBase,// shared mem
+ true,// thread can call Java
+ sessionId,// audio session ID
+ AudioTrack::TRANSFER_SHARED,
+ NULL, // default offloadInfo
+ -1, -1, // default uid, pid values
+ paa);
+ break;
+
+ default:
+ ALOGE("Unknown mode %d", memoryMode);
+ goto native_init_failure;
+ }
+
+ if (status != NO_ERROR) {
+ ALOGE("Error %d initializing AudioTrack", status);
+ goto native_init_failure;
+ }
+ } else { // end if (nativeAudioTrack == 0)
+ lpTrack = (AudioTrack*)nativeAudioTrack;
+ // TODO: We need to find out which members of the Java AudioTrack might
+ // need to be initialized from the Native AudioTrack
+ // these are directly returned from getters:
+ // mSampleRate
+ // mAudioFormat
+ // mStreamType
+ // mChannelConfiguration
+ // mChannelCount
+ // mState (?)
+ // mPlayState (?)
+ // these may be used internally (Java AudioTrack.audioParamCheck():
+ // mChannelMask
+ // mChannelIndexMask
+ // mDataLoadMode
+
+ // initialize the callback information:
+ // this data will be passed with every AudioTrack callback
+ lpJniStorage = new AudioTrackJniStorage();
+ lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioTrack object can be garbage collected.
+ lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+ lpJniStorage->mCallbackData.busy = false;
}
nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
@@ -370,6 +413,11 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
+ {
+ const jint elements[1] = { (jint) lpTrack->getSampleRate() };
+ env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
+ }
+
{ // scope for the lock
Mutex::Autolock l(sLock);
sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
@@ -385,9 +433,11 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
// since we had audio attributes, the stream type was derived from them during the
// creation of the native AudioTrack: push the same value to the Java object
env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
- // audio attributes were copied in AudioTrack creation
- free(paa);
- paa = NULL;
+ if (paa != NULL) {
+ // audio attributes were copied in AudioTrack creation
+ free(paa);
+ paa = NULL;
+ }
return (jint) AUDIO_JAVA_SUCCESS;
@@ -409,7 +459,6 @@ native_init_failure:
return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
-
// ----------------------------------------------------------------------------
static void
android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
@@ -1008,7 +1057,7 @@ static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thi
return -1;
}
const audio_format_t format = audioFormatToNative(audioFormat);
- if (audio_is_linear_pcm(format)) {
+ if (audio_has_proportional_frames(format)) {
const size_t bytesPerSample = audio_bytes_per_sample(format);
return frameCount * channelCount * bytesPerSample;
} else {
@@ -1114,7 +1163,7 @@ static const JNINativeMethod gMethods[] = {
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I",
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJ)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index ba0876d74b17..defb88a9712f 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -39,23 +39,6 @@ extern "C" {
int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
int ifc_reset_connections(const char *ifname, int reset_mask);
-
-int dhcp_start(const char * const ifname);
-int dhcp_start_renew(const char * const ifname);
-int dhcp_get_results(const char * const ifname,
- const char *ipaddr,
- const char *gateway,
- uint32_t *prefixLength,
- const char *dns[],
- const char *server,
- uint32_t *lease,
- const char *vendorInfo,
- const char *domains,
- const char *mtu);
-
-int dhcp_stop(const char *ifname);
-int dhcp_release_lease(const char *ifname);
-char *dhcp_get_errmsg();
}
#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -64,22 +47,6 @@ namespace android {
static const uint16_t kDhcpClientPort = 68;
-/*
- * The following remembers the jfieldID's of the fields
- * of the DhcpInfo Java object, so that we don't have
- * to look them up every time.
- */
-static struct fieldIds {
- jmethodID clear;
- jmethodID setIpAddress;
- jmethodID setGateway;
- jmethodID addDns;
- jmethodID setDomains;
- jmethodID setServerAddress;
- jmethodID setLeaseDuration;
- jmethodID setVendorInfo;
-} dhcpResultsFieldIds;
-
static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
jstring ifname, jint mask)
{
@@ -95,137 +62,6 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
return (jint)result;
}
-static jboolean android_net_utils_getDhcpResults(JNIEnv* env, jobject clazz, jstring ifname,
- jobject dhcpResults)
-{
- int result;
- char ipaddr[PROPERTY_VALUE_MAX];
- uint32_t prefixLength;
- char gateway[PROPERTY_VALUE_MAX];
- char dns1[PROPERTY_VALUE_MAX];
- char dns2[PROPERTY_VALUE_MAX];
- char dns3[PROPERTY_VALUE_MAX];
- char dns4[PROPERTY_VALUE_MAX];
- const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
- char server[PROPERTY_VALUE_MAX];
- uint32_t lease;
- char vendorInfo[PROPERTY_VALUE_MAX];
- char domains[PROPERTY_VALUE_MAX];
- char mtu[PROPERTY_VALUE_MAX];
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
-
- result = ::dhcp_get_results(nameStr, ipaddr, gateway, &prefixLength,
- dns, server, &lease, vendorInfo, domains, mtu);
- if (result != 0) {
- ALOGD("dhcp_get_results failed : %s (%s)", nameStr, ::dhcp_get_errmsg());
- }
-
- env->ReleaseStringUTFChars(ifname, nameStr);
- if (result == 0) {
- env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
-
- // set the linkAddress
- // dhcpResults->addLinkAddress(inetAddress, prefixLength)
- result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress,
- env->NewStringUTF(ipaddr), prefixLength);
- }
-
- if (result == 0) {
- // set the gateway
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway));
- }
-
- if (result == 0) {
- // dhcpResults->addDns(new InetAddress(dns1))
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
- }
-
- if (result == 0) {
- env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
- env->NewStringUTF(domains));
-
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
-
- if (result == 0) {
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
- if (result == 0) {
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
- }
- }
- }
-
- if (result == 0) {
- // dhcpResults->setServerAddress(new InetAddress(server))
- result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
- env->NewStringUTF(server));
- }
-
- if (result == 0) {
- // dhcpResults->setLeaseDuration(lease)
- env->CallVoidMethod(dhcpResults,
- dhcpResultsFieldIds.setLeaseDuration, lease);
-
- // dhcpResults->setVendorInfo(vendorInfo)
- env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
- env->NewStringUTF(vendorInfo));
- }
- return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_startDhcp(JNIEnv* env, jobject clazz, jstring ifname)
-{
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
- if (::dhcp_start(nameStr) != 0) {
- ALOGD("dhcp_start failed : %s", nameStr);
- return (jboolean)false;
- }
- return (jboolean)true;
-}
-
-static jboolean android_net_utils_startDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname)
-{
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
- if (::dhcp_start_renew(nameStr) != 0) {
- ALOGD("dhcp_start_renew failed : %s", nameStr);
- return (jboolean)false;
- }
- return (jboolean)true;
-}
-
-static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_stop(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_release_lease(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
-}
-
-static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
-{
- return env->NewStringUTF(::dhcp_get_errmsg());
-}
-
static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
int fd = jniGetFDFromFileDescriptor(env, javaFd);
@@ -305,12 +141,6 @@ static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jin
static const JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
{ "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
- { "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp },
- { "startDhcpRenew", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcpRenew },
- { "getDhcpResults", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_getDhcpResults },
- { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
- { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
- { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
{ "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
@@ -322,24 +152,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
int register_android_net_NetworkUtils(JNIEnv* env)
{
- jclass dhcpResultsClass = FindClassOrDie(env, "android/net/DhcpResults");
-
- dhcpResultsFieldIds.clear = GetMethodIDOrDie(env, dhcpResultsClass, "clear", "()V");
- dhcpResultsFieldIds.setIpAddress =GetMethodIDOrDie(env, dhcpResultsClass, "setIpAddress",
- "(Ljava/lang/String;I)Z");
- dhcpResultsFieldIds.setGateway = GetMethodIDOrDie(env, dhcpResultsClass, "setGateway",
- "(Ljava/lang/String;)Z");
- dhcpResultsFieldIds.addDns = GetMethodIDOrDie(env, dhcpResultsClass, "addDns",
- "(Ljava/lang/String;)Z");
- dhcpResultsFieldIds.setDomains = GetMethodIDOrDie(env, dhcpResultsClass, "setDomains",
- "(Ljava/lang/String;)V");
- dhcpResultsFieldIds.setServerAddress = GetMethodIDOrDie(env, dhcpResultsClass,
- "setServerAddress", "(Ljava/lang/String;)Z");
- dhcpResultsFieldIds.setLeaseDuration = GetMethodIDOrDie(env, dhcpResultsClass,
- "setLeaseDuration", "(I)V");
- dhcpResultsFieldIds.setVendorInfo = GetMethodIDOrDie(env, dhcpResultsClass, "setVendorInfo",
- "(Ljava/lang/String;)V");
-
return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
NELEM(gNetworkUtilMethods));
}
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 783baef2952a..59b8911487b9 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -5171,6 +5171,21 @@ android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2
}
}
+/* void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset ) */
+static void
+android_glReadPixels__IIIIIII
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jint offset) {
+ glReadPixels(
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLenum)format,
+ (GLenum)type,
+ reinterpret_cast<GLvoid *>(offset)
+ );
+}
+
static const char *classPathName = "android/opengl/GLES30";
static const JNINativeMethod methods[] = {
@@ -5337,6 +5352,7 @@ static const JNINativeMethod methods[] = {
{"glTexStorage3D", "(IIIIII)V", (void *) android_glTexStorage3D__IIIIII },
{"glGetInternalformativ", "(IIII[II)V", (void *) android_glGetInternalformativ__IIII_3II },
{"glGetInternalformativ", "(IIIILjava/nio/IntBuffer;)V", (void *) android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2 },
+{"glReadPixels", "(IIIIIII)V", (void *) android_glReadPixels__IIIIIII },
};
int register_android_opengl_jni_GLES30(JNIEnv *_env)
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 03a1e718d2ea..3df0876532cb 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -21,6 +21,7 @@
#include "utils/misc.h"
#include "cutils/debugger.h"
#include <memtrack/memtrack.h>
+#include <memunreachable/memunreachable.h>
#include <cutils/log.h>
#include <fcntl.h>
@@ -36,6 +37,9 @@
#include <ctype.h>
#include <malloc.h>
+#include <iomanip>
+#include <string>
+
namespace android
{
@@ -1023,6 +1027,13 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz
close(fd);
}
+static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz,
+ jint limit, jboolean contents)
+{
+ std::string s = GetUnreachableMemoryString(contents, limit);
+ return env->NewStringUTF(s.c_str());
+}
+
/*
* JNI registration.
*/
@@ -1058,6 +1069,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_os_Debug_getDeathObjectCount },
{ "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
(void*)android_os_Debug_dumpNativeBacktraceToFile },
+ { "getUnreachableMemory", "(IZ)Ljava/lang/String;",
+ (void*)android_os_Debug_getUnreachableMemory },
};
int register_android_os_Debug(JNIEnv *env)
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index ae109c6566cb..abc6c4b5e7cc 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -556,7 +556,7 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
}
// For the rest of the function we will hold this lock, to serialize
- // looking/creation of Java proxies for native Binder proxies.
+ // looking/creation/destruction of Java proxies for native Binder proxies.
AutoMutex _l(mProxyLock);
// Someone else's... do we know about it?
@@ -1225,16 +1225,21 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
{
+ // Don't race with construction/initialization
+ AutoMutex _l(mProxyLock);
+
IBinder* b = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
DeathRecipientList* drl = (DeathRecipientList*)
env->GetLongField(obj, gBinderProxyOffsets.mOrgue);
LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl);
- env->SetLongField(obj, gBinderProxyOffsets.mObject, 0);
- env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0);
- drl->decStrong((void*)javaObjectForIBinder);
- b->decStrong((void*)javaObjectForIBinder);
+ if (b != nullptr) {
+ env->SetLongField(obj, gBinderProxyOffsets.mObject, 0);
+ env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0);
+ drl->decStrong((void*)javaObjectForIBinder);
+ b->decStrong((void*)javaObjectForIBinder);
+ }
IPCThreadState::self()->flushCommands();
}
diff --git a/core/jni/android_util_jar_StrictJarFile.cpp b/core/jni/android_util_jar_StrictJarFile.cpp
index 7f8f70832ab7..bfdea8fff24a 100644
--- a/core/jni/android_util_jar_StrictJarFile.cpp
+++ b/core/jni/android_util_jar_StrictJarFile.cpp
@@ -161,12 +161,14 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(StrictJarFile, nativeClose, "(J)V"),
};
-void register_android_util_jar_StrictJarFile(JNIEnv* env) {
+int register_android_util_jar_StrictJarFile(JNIEnv* env) {
jniRegisterNativeMethods(env, "android/util/jar/StrictJarFile", gMethods, NELEM(gMethods));
zipEntryCtor = env->GetMethodID(JniConstants::zipEntryClass, "<init>",
"(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V");
LOG_ALWAYS_FATAL_IF(zipEntryCtor == NULL, "Unable to find ZipEntry.<init>");
+
+ return 0;
}
}; // namespace android
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 03c94a683ec2..c87a7701786c 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -160,7 +160,7 @@ static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject
}
// In the emulator this property will be set > 0 when OpenGL ES 2.0 is
// enabled, 0 otherwise. On old emulator versions it will be undefined.
- property_get("ro.kernel.qemu.gles", prop, "0");
+ property_get("qemu.gles", prop, "0");
return atoi(prop) > 0 ? JNI_TRUE : JNI_FALSE;
}
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 0926e9b76691..c9eac79ef9b6 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -184,7 +184,7 @@ static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) {
static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) {
BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
- animator->end();
+ animator->cancel();
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index acd0501362b5..07868c54cf52 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "ThreadedRenderer"
#include <algorithm>
+#include <atomic>
#include "jni.h"
#include <nativehelper/JNIHelp.h>
@@ -41,6 +42,7 @@
#include <Animator.h>
#include <AnimationContext.h>
#include <FrameInfo.h>
+#include <FrameMetricsObserver.h>
#include <IContextFactory.h>
#include <JankTracker.h>
#include <RenderNode.h>
@@ -56,10 +58,11 @@ using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
struct {
- jfieldID buffer;
+ jfieldID frameMetrics;
+ jfieldID timingDataBuffer;
jfieldID messageQueue;
- jmethodID notifyData;
-} gFrameStatsObserverClassInfo;
+ jmethodID callback;
+} gFrameMetricsObserverClassInfo;
static JNIEnv* getenv(JavaVM* vm) {
JNIEnv* env;
@@ -161,6 +164,13 @@ public:
mPendingAnimatingRenderNodes.clear();
}
+ void destroy() {
+ for (auto& renderNode : mPendingAnimatingRenderNodes) {
+ renderNode->animators().endAllStagingAnimators();
+ }
+ mPendingAnimatingRenderNodes.clear();
+ }
+
private:
sp<Looper> mLooper;
JavaVM* mVm;
@@ -229,93 +239,137 @@ class ObserverProxy;
class NotifyHandler : public MessageHandler {
public:
- NotifyHandler(JavaVM* vm) : mVm(vm) {}
-
- void setObserver(ObserverProxy* observer) {
- mObserver = observer;
- }
-
- void setBuffer(BufferPool::Buffer* buffer) {
- mBuffer = buffer;
- }
+ NotifyHandler(JavaVM* vm, ObserverProxy* observer) : mVm(vm), mObserver(observer) {}
virtual void handleMessage(const Message& message);
private:
- JavaVM* mVm;
-
- sp<ObserverProxy> mObserver;
- BufferPool::Buffer* mBuffer;
+ JavaVM* const mVm;
+ ObserverProxy* const mObserver;
};
-class ObserverProxy : public FrameStatsObserver {
+static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) {
+ jobject frameMetrics = env->GetObjectField(
+ observer, gFrameMetricsObserverClassInfo.frameMetrics);
+ LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object");
+ jobject buffer = env->GetObjectField(
+ frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer);
+ LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer");
+ return reinterpret_cast<jlongArray>(buffer);
+}
+
+/*
+ * Implements JNI layer for hwui frame metrics reporting.
+ */
+class ObserverProxy : public FrameMetricsObserver {
public:
- ObserverProxy(JavaVM *vm, jobject fso) : mVm(vm) {
+ ObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) {
JNIEnv* env = getenv(mVm);
- jlongArray longArrayLocal = env->NewLongArray(kBufferSize);
- LOG_ALWAYS_FATAL_IF(longArrayLocal == nullptr,
- "OOM: can't allocate frame stats buffer");
- env->SetObjectField(fso, gFrameStatsObserverClassInfo.buffer, longArrayLocal);
-
- mFsoWeak = env->NewWeakGlobalRef(fso);
- LOG_ALWAYS_FATAL_IF(mFsoWeak == nullptr,
+ mObserverWeak = env->NewWeakGlobalRef(observer);
+ LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
"unable to create frame stats observer reference");
- jobject messageQueueLocal =
- env->GetObjectField(fso, gFrameStatsObserverClassInfo.messageQueue);
+ jlongArray buffer = get_metrics_buffer(env, observer);
+ jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer));
+ LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize,
+ "Mismatched Java/Native FrameMetrics data format.");
+
+ jobject messageQueueLocal = env->GetObjectField(
+ observer, gFrameMetricsObserverClassInfo.messageQueue);
mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal);
LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available");
- mMessageHandler = new NotifyHandler(mVm);
+ mMessageHandler = new NotifyHandler(mVm, this);
LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr,
"OOM: unable to allocate NotifyHandler");
}
~ObserverProxy() {
JNIEnv* env = getenv(mVm);
- env->DeleteWeakGlobalRef(mFsoWeak);
+ env->DeleteWeakGlobalRef(mObserverWeak);
+ }
+
+ jweak getObserverReference() {
+ return mObserverWeak;
}
- jweak getJavaObjectRef() {
- return mFsoWeak;
+ bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) {
+ FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
+
+ if (elem.hasData.load()) {
+ env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer);
+ *dropCount = elem.dropCount;
+ mNextInQueue = (mNextInQueue + 1) % kRingSize;
+ elem.hasData = false;
+ return true;
+ }
+
+ return false;
}
- virtual void notify(BufferPool::Buffer* buffer) {
- buffer->incRef();
- mMessageHandler->setBuffer(buffer);
- mMessageHandler->setObserver(this);
- mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
+ virtual void notify(const int64_t* stats) {
+ FrameMetricsNotification& elem = mRingBuffer[mNextFree];
+
+ if (!elem.hasData.load()) {
+ memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
+
+ elem.dropCount = mDroppedReports;
+ mDroppedReports = 0;
+
+ incStrong(nullptr);
+ mNextFree = (mNextFree + 1) % kRingSize;
+ elem.hasData = true;
+
+ mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
+ } else {
+ mDroppedReports++;
+ }
}
private:
static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes);
+ static constexpr int kRingSize = 3;
- JavaVM* mVm;
- jweak mFsoWeak;
+ class FrameMetricsNotification {
+ public:
+ FrameMetricsNotification() : hasData(false) {}
+
+ std::atomic_bool hasData;
+ int64_t buffer[kBufferSize];
+ int dropCount = 0;
+ };
+
+ JavaVM* const mVm;
+ jweak mObserverWeak;
+ jobject mJavaBufferGlobal;
sp<MessageQueue> mMessageQueue;
sp<NotifyHandler> mMessageHandler;
Message mMessage;
+
+ int mNextFree = 0;
+ int mNextInQueue = 0;
+ FrameMetricsNotification mRingBuffer[kRingSize];
+
+ int mDroppedReports = 0;
};
void NotifyHandler::handleMessage(const Message& message) {
JNIEnv* env = getenv(mVm);
- jobject target = env->NewLocalRef(mObserver->getJavaObjectRef());
+ jobject target = env->NewLocalRef(mObserver->getObserverReference());
if (target != nullptr) {
- jobject javaBuffer = env->GetObjectField(target, gFrameStatsObserverClassInfo.buffer);
- if (javaBuffer != nullptr) {
- env->SetLongArrayRegion(reinterpret_cast<jlongArray>(javaBuffer),
- 0, mBuffer->getSize(), mBuffer->getBuffer());
- env->CallVoidMethod(target, gFrameStatsObserverClassInfo.notifyData);
- env->DeleteLocalRef(target);
+ jlongArray javaBuffer = get_metrics_buffer(env, target);
+ int dropCount = 0;
+ while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) {
+ env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount);
}
+ env->DeleteLocalRef(target);
}
- mBuffer->release();
- mObserver.clear();
+ mObserver->decStrong(nullptr);
}
static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
@@ -429,7 +483,9 @@ static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject c
}
static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
- jlong proxyPtr) {
+ jlong proxyPtr, jlong rootNodePtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+ rootRenderNode->destroy();
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->destroy();
}
@@ -579,10 +635,10 @@ static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
}
// ----------------------------------------------------------------------------
-// FrameStatsObserver
+// FrameMetricsObserver
// ----------------------------------------------------------------------------
-static jlong android_view_ThreadedRenderer_addFrameStatsObserver(JNIEnv* env,
+static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env,
jclass clazz, jlong proxyPtr, jobject fso) {
JavaVM* vm = nullptr;
if (env->GetJavaVM(&vm) != JNI_OK) {
@@ -593,25 +649,18 @@ static jlong android_view_ThreadedRenderer_addFrameStatsObserver(JNIEnv* env,
renderthread::RenderProxy* renderProxy =
reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
- FrameStatsObserver* observer = new ObserverProxy(vm, fso);
- renderProxy->addFrameStatsObserver(observer);
+ FrameMetricsObserver* observer = new ObserverProxy(vm, fso);
+ renderProxy->addFrameMetricsObserver(observer);
return reinterpret_cast<jlong>(observer);
}
-static void android_view_ThreadedRenderer_removeFrameStatsObserver(JNIEnv* env, jclass clazz,
+static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env, jclass clazz,
jlong proxyPtr, jlong observerPtr) {
- FrameStatsObserver* observer = reinterpret_cast<FrameStatsObserver*>(observerPtr);
+ FrameMetricsObserver* observer = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
renderthread::RenderProxy* renderProxy =
reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
- renderProxy->removeFrameStatsObserver(observer);
-}
-
-static jint android_view_ThreadedRenderer_getDroppedFrameReportCount(JNIEnv* env, jclass clazz,
- jlong proxyPtr) {
- renderthread::RenderProxy* renderProxy =
- reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
- return renderProxy->getDroppedFrameReportCount();
+ renderProxy->removeFrameMetricsObserver(observer);
}
// ----------------------------------------------------------------------------
@@ -658,7 +707,7 @@ static const JNINativeMethod gMethods[] = {
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
{ "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
- { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
+ { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
{ "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
@@ -684,25 +733,26 @@ static const JNINativeMethod gMethods[] = {
{ "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
{ "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
{ "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
- { "nAddFrameStatsObserver",
- "(JLandroid/view/FrameStatsObserver;)J",
- (void*)android_view_ThreadedRenderer_addFrameStatsObserver },
- { "nRemoveFrameStatsObserver",
+ { "nAddFrameMetricsObserver",
+ "(JLandroid/view/FrameMetricsObserver;)J",
+ (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
+ { "nRemoveFrameMetricsObserver",
"(JJ)V",
- (void*)android_view_ThreadedRenderer_removeFrameStatsObserver },
- { "nGetDroppedFrameReportCount",
- "(J)J",
- (void*)android_view_ThreadedRenderer_getDroppedFrameReportCount },
+ (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {
- jclass clazz = FindClassOrDie(env, "android/view/FrameStatsObserver");
- gFrameStatsObserverClassInfo.messageQueue =
- GetFieldIDOrDie(env, clazz, "mMessageQueue", "Landroid/os/MessageQueue;");
- gFrameStatsObserverClassInfo.buffer =
- GetFieldIDOrDie(env, clazz, "mBuffer", "[J");
- gFrameStatsObserverClassInfo.notifyData =
- GetMethodIDOrDie(env, clazz, "notifyDataAvailable", "()V");
+ jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver");
+ gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie(
+ env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;");
+ gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie(
+ env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;");
+ gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie(
+ env, observerClass, "notifyDataAvailable", "(I)V");
+
+ jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics");
+ gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
+ env, metricsClass, "mTimingData", "[J");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4194aa410792..612f4dfd1505 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -608,8 +608,12 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jlong capabilities = 0;
// Grant CAP_WAKE_ALARM to the Bluetooth process.
+ // Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
+ // TODO: consider making such functionality an RPC to netd.
if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
+ capabilities |= (1LL << CAP_NET_RAW);
+ capabilities |= (1LL << CAP_NET_BIND_SERVICE);
}
// Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1db75e6337d1..03d93a1720df 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -237,12 +237,21 @@
<protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
- <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
+ <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
+ <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.ALLOW_CONNECT" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.DENY_CONNECT" />
<protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
<protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
<protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
-
- <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <!-- For NFC to BT handover -->
+ <protected-broadcast android:name="android.btopp.intent.action.WHITELIST_DEVICE" />
+ <protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
<protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
@@ -287,10 +296,6 @@
<protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
<protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
<protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" />
- <protected-broadcast android:name="android.intent.action.BUGREPORT_STARTED" />
- <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" />
- <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" />
- <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_DISPATCH" />
<!-- Legacy -->
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
@@ -397,6 +402,7 @@
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
<protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
+ <protected-broadcast android:name="EventConditionProvider.EVALUATE" />
<protected-broadcast android:name="wifi_scan_available" />
<protected-broadcast android:name="action.cne.started" />
@@ -425,6 +431,25 @@
<protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+
+ <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
+
+ <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
+ <protected-broadcast android:name="com.android.phone.SIP_ADD_PHONE" />
+ <protected-broadcast android:name="com.android.phone.SIP_REMOVE_PHONE" />
+ <protected-broadcast android:name="com.android.phone.SIP_CALL_OPTION_CHANGED" />
+
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_CONNECTED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED" />
+
+ <protected-broadcast android:name="android.bluetooth.input.profile.action.HANDSHAKE" />
+ <protected-broadcast android:name="android.bluetooth.input.profile.action.REPORT" />
+
+ <protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -864,92 +889,82 @@
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_PROFILE"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_PROFILE"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_SOCIAL_STREAM"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SOCIAL_STREAM"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_USER_DICTIONARY"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_USER_DICTIONARY"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SMS"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.MANAGE_ACCOUNTS"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.USE_CREDENTIALS"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.FLASHLIGHT"
android:protectionLevel="normal"
- android:permissionFlags="hidden"/>
+ android:permissionFlags="removed"/>
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
<!-- ====================================================================== -->
-` <!-- =========================================== -->
- <!-- Permissions for accessing contact metadata -->
- <!-- =========================================== -->
- <eat-comment />
-
- <!-- @SystemApi Allows an application to read/write contact metadata.
- <p>Not for use by third-party applications. -->
- <permission android:name="android.permission.READ_WRITE_CONTACT_METADATA"
- android:protectionLevel="signature|system" />
-
<!-- ================================== -->
<!-- Permissions for accessing messages -->
<!-- ================================== -->
@@ -1979,6 +1994,12 @@
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
android:protectionLevel="signature|privileged|installer" />
+ <!-- Allows an application to update the user app op restrictions.
+ Not for use by third party apps.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi Allows an application to open windows that are for use by parts
of the system user interface.
<p>Not for use by third-party applications.
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index bb423fef57ba..defa83a9b5c6 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2015 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,24 @@ Copyright (C) 2015 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="512dp"
+ android:height="512dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:pathData="M34.9,13.2c-0.8,-0.8,-4.2,-2.4,-10.9,-2.4s-10.1,1.6,-10.9,2.4c-0.8,0.8,-2.4,4.2,-2.4,10.9s1.6,10.1,2.4,10.9 c0.8,0.8,4.2,2.4,10.9,2.4s10.1,-1.6,10.9,-2.4c0.8,-0.8,2.4,-4.2,2.4,-10.9S35.6,14,34.9,13.2z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#FF7E5BBF"
+ android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
<path
- android:pathData="M34.7,13.7c0,0.8,-1.2,1.5,-3.1,2.1c-1.9,0.5,-4.6,0.8,-7.6,0.8s-5.6,-0.3,-7.6,-0.8 c-1.9,-0.5,-3.1,-1.2,-3.1,-2.1s1.2,-1.5,3.1,-2.1c1.9,-0.5,4.6,-0.8,7.6,-0.8s5.6,0.3,7.6,0.8C33.5,12.1,34.7,12.9,34.7,13.7z"
- android:fillColor="#EBEBEB"/>
+ android:fillColor="#FF7E5BBF"
+ android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
<path
- android:pathData="M30,13c-0.1,0,-0.1,0,-0.2,0c-0.4,-0.1,-0.7,-0.6,-0.6,-1l1.3,-5.5c0.1,-0.4,0.6,-0.7,1,-0.6c0.4,0.1,0.7,0.6,0.6,1 l-1.3,5.5C30.7,12.7,30.4,13,30,13z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#40000000"
+ android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
<path
- android:pathData="M18,13c-0.4,0,-0.7,-0.3,-0.8,-0.6l-1.3,-5.5c-0.1,-0.4,0.2,-0.9,0.6,-1c0.4,-0.1,0.9,0.2,1,0.6l1.3,5.5 c0.1,0.4,-0.2,0.9,-0.6,1C18.1,13,18.1,13,18,13z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#40000000"
+ android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
+ <path
+ android:fillColor="#FF55C4F5"
+ 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"/>
</vector>
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 8cc9961bf6e6..5043cba3aa5e 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) 2014 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,23 +14,23 @@ Copyright (C) 2014 The Android Open Source Project
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">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
<path
- android:pathData="M8.4,5.3c-0.2,0.0 -0.4,-0.2 -0.5,-0.4L7.1,1.6C7.0,1.4 7.2,1.1 7.4,1.0C7.7,0.9 8.0,1.1 8.0,1.4l0.8,3.3c0.1,0.3 -0.1,0.5 -0.4,0.6C8.5,5.3 8.4,5.3 8.4,5.3z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#A0FFFFFF"
+ android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
<path
- android:pathData="M15.6,5.3c0.0,0.0 -0.1,0.0 -0.1,0.0c-0.3,-0.1 -0.4,-0.3 -0.4,-0.6L16.0,1.4C16.0,1.1 16.3,0.9 16.6,1.0c0.3,0.1 0.4,0.3 0.4,0.6l-0.8,3.3C16.1,5.1 15.9,5.3 15.6,5.3z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#A0FFFFFF"
+ android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
<path
- android:pathData="M18.6,5.4c-0.1,-0.1 -0.2,-0.1 -0.3,-0.2c0.2,0.2 0.3,0.3 0.3,0.5c0.0,0.9 -2.9,1.7 -6.6,1.7S5.4,6.7 5.4,5.7c0.0,-0.2 0.1,-0.3 0.3,-0.5C5.6,5.3 5.5,5.4 5.4,5.4C5.0,5.9 4.0,8.0 4.0,12.0s1.0,6.1 1.4,6.6C5.9,19.0 8.0,20.0 12.0,20.0s6.1,-1.0 6.6,-1.4C19.0,18.1 20.0,16.0 20.0,12.0S19.0,5.9 18.6,5.4zM8.0,13.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0c0.0,-0.6 0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0C9.0,12.6 8.6,13.0 8.0,13.0zM16.0,13.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0c0.0,-0.6 0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0C17.0,12.6 16.6,13.0 16.0,13.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M5.35,5.7
- a 6.6 1.75 0 1 1 13.25 0
- a 6.6 1.75 0 1 1 -13.25 0
- z"
- android:fillColor="#BBFFFFFF" />
+ 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"/>
</vector>
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index 824f97f6585a..b9531f46e275 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -66,7 +66,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_mute"
- android:drawableStart="@drawable/ic_close"
+ android:drawableStart="@drawable/ic_eject_24dp"
style="@style/aerr_list_item"
/>
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index dd161e38486e..ca0373773577 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -19,8 +19,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="0dp"
- android:layout_margin="20dp"
- android:elevation="2dp"
+ android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
+ android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="?attr/floatingToolbarPopupBackgroundDrawable"/>
diff --git a/core/res/res/layout/language_picker_item.xml b/core/res/res/layout/language_picker_item.xml
index 22cb514b10b9..88012a939857 100644
--- a/core/res/res/layout/language_picker_item.xml
+++ b/core/res/res/layout/language_picker_item.xml
@@ -14,37 +14,16 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:layoutDirection="locale"
- android:textDirection="locale"
- android:paddingBottom="8dp"
- android:paddingTop="8dp">
-
- <TextView
- android:id="@+id/locale"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- tools:text="France"
- android:layout_weight="1"
- android:padding="12dp"
- android:paddingStart="18dp"
- android:paddingEnd="18dp"
- android:textAppearance="?android:attr/textAppearanceListItem"/>
-
- <ImageView
- android:id="@+id/l10nWarn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@android:drawable/stat_sys_warning"
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:tint="?android:attr/colorAccent"/>
-
-</LinearLayout>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/locale"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:layoutDirection="locale"
+ android:textDirection="locale"
+ android:paddingBottom="8dp"
+ android:paddingTop="8dp" />
diff --git a/core/res/res/layout/language_picker_section_header.xml b/core/res/res/layout/language_picker_section_header.xml
index c4d3069c1918..6cbd7c36e958 100644
--- a/core/res/res/layout/language_picker_section_header.xml
+++ b/core/res/res/layout/language_picker_section_header.xml
@@ -19,7 +19,9 @@
style="?android:attr/preferenceCategoryStyle"
android:layout_width="match_parent"
android:layout_height="36dp"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
+ android:gravity="center_vertical"
+ android:paddingStart="18dp"
+ android:paddingEnd="18dp"
android:textColor="?android:attr/colorAccent"
+ android:textStyle="bold"
tools:text="@string/language_picker_section_all"/>
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index 398f52df32ad..548ee0561698 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -21,6 +21,7 @@
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_gravity="center"
+ android:gravity="start|center_vertical"
android:layout_marginStart="4dp"
android:textColor="@color/notification_default_color"
android:singleLine="true"
diff --git a/core/res/res/layout/notification_material_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml
index 976448b08bb3..1f59ea02025b 100644
--- a/core/res/res/layout/notification_material_action_tombstone.xml
+++ b/core/res/res/layout/notification_material_action_tombstone.xml
@@ -18,16 +18,15 @@
<Button xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/action0"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="48dp"
- android:layout_weight="1"
+ android:layout_marginStart="4dp"
+ android:layout_gravity="center"
android:gravity="start|center_vertical"
- android:drawablePadding="8dp"
- android:paddingStart="8dp"
android:textColor="#555555"
- android:textSize="@dimen/notification_text_size"
android:singleLine="true"
android:ellipsize="end"
android:alpha="0.5"
android:enabled="false"
+ android:background="@drawable/notification_material_action_background"
/>
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index aa78eff612c8..a5ed1875d830 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -19,41 +19,45 @@
<com.android.internal.widget.MediaNotificationView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
- android:layout_height="126dp"
+ android:layout_height="wrap_content"
android:background="#00000000"
android:tag="bigMediaNarrow"
>
<include layout="@layout/notification_template_header"
android:layout_width="match_parent"
android:layout_height="48dp"
- android:layout_alignParentStart="true"/>
+ android:layout_gravity="start"/>
<LinearLayout
- android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:layout_marginBottom="@dimen/notification_content_margin_bottom"
- android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:layout_toStartOf="@id/right_icon"
- android:minHeight="@dimen/notification_min_content_height"
android:orientation="vertical"
>
- <include layout="@layout/notification_template_part_line1" />
- <include layout="@layout/notification_template_text" />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/media_actions"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true"
- android:paddingStart="8dp"
- android:paddingBottom="8dp"
- android:orientation="horizontal"
- android:layoutDirection="ltr"
- >
- <!-- media buttons will be added here -->
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginBottom="@dimen/notification_content_margin_bottom"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1" />
+ <include layout="@layout/notification_template_text" />
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-15dp"
+ android:paddingStart="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ >
+ <!-- media buttons will be added here -->
+ </LinearLayout>
</LinearLayout>
<ImageView android:id="@+id/right_icon"
@@ -61,9 +65,8 @@
android:layout_height="@dimen/media_notification_expanded_image_max_size"
android:minWidth="40dp"
android:layout_marginEnd="16dp"
- android:layout_marginTop="16dp"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
+ android:layout_marginBottom="16dp"
+ android:layout_gravity="bottom|end"
android:scaleType="centerCrop"
/>
</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index aea9b44622c4..cda063627dc5 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -36,6 +36,7 @@
android:tag="media"
>
<LinearLayout
+ android:id="@+id/notification_content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
@@ -45,7 +46,6 @@
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1"/>
- <include layout="@layout/notification_template_progress"/>
<include layout="@layout/notification_template_text"/>
</LinearLayout>
<LinearLayout
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index 17e93d0a9eae..b2589da8ea5b 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -22,8 +22,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:elevation="2dp"
- android:layout_margin="20dp"
+ android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
+ android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
android:background="@drawable/text_edit_suggestions_window"
android:dropDownSelector="@drawable/list_selector_background"
android:divider="@null">
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 78268036c827..15b18dd057e8 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -24,14 +24,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
- android:elevation="2dp"
- android:layout_margin="20dp"
+ android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
+ android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
android:orientation="vertical"
android:divider="?android:attr/listDivider"
android:showDividers="middle">
<ListView
android:id="@+id/suggestionContainer"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="0dp"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c8ab29558a26..06fcda9560aa 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Beller-ID se verstek is nie beperk nie. Volgende oproep: nie beperk nie"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Diens nie verskaf nie."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Jy kan nie die beller-ID-instelling verander nie."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Beperkte toegang het verander"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datadiens word geblokkeer."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nooddiens word geblokkeer."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Stemdiens word geblokkeer."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Stel terug en herbegin program"</string>
<string name="aerr_report" msgid="5371800241488400617">"Stuur terugvoer"</string>
<string name="aerr_close" msgid="2991640326563991340">"Maak toe"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Demp"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Demp totdat toestel herbegin"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Wag"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Maak program toe"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Raak vir meer opsies."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Raak om USB-ontfouting te deaktiveer."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Deel foutverslag met administrateur?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Jou IT-administrateur het \'n foutverslag versoek om met foutsporing te help"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Jou IT-administrateur het \'n foutverslag versoek om met die foutsporing van hierdie toestel te help. Programme en data sal dalk gedeel word en jou toestel sal dalk tydelik stadiger wees."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Jou IT-administrateur het \'n foutverslag versoek om met die foutsporing van hierdie toestel te help. Programme en data sal dalk gedeel word."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dit sal jou toestel dalk tydelik stadiger maak"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AANVAAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIER"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Neem tans foutverslag …"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Raak om te kanselleer"</string>
<string name="select_input_method" msgid="8547250819326693584">"Verander sleutelbord"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Kies sleutelborde"</string>
<string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vra ontsluitpatroon voordat jy ontspeld"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vra wagwoord voordat jy ontspeld"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Program se grootte kan nie verander word nie; rollees dit met twee vingers."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Program sal dalk nie met verdeelde skerm werk nie."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Program steun nie verdeelde skerm nie."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Deur jou administrateur geïnstalleer"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Opgedateer deur jou administrateur"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Taalvoorkeur"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Voeg \'n taal by"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Streekvoorkeur"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgestel"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Deur %1$s-administrateur gedeaktiveer. Kontak hulle om meer uit te vind."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Jy het nuwe boodskappe"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Maak SMS-program oop om te bekyk"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Party funksies dalk nie beskikbaar nie"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Raak om voort te gaan"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Gebruikerprofiel is gesluit"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Sommige funksies kan beperk wees"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tik om te ontsluit"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Gebruikerdata is gesluit"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Werkprofiel is gesluit"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tik om werkprofiel te ontsluit"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Gekoppel aan <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tik om lêers te bekyk"</string>
<string name="pin_target" msgid="3052256031352291362">"Speld vas"</string>
<string name="unpin_target" msgid="3556545602439143442">"Ontspeld"</string>
<string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ec533aa17d2e..f06d7de63d21 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"የደዋይ ID ነባሪዎች ወደአልተከለከለም። ቀጥሎ ጥሪ፡አልተከለከለም"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"አገልግሎት አልቀረበም።"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"የደዋይ መታወቂያ ቅንብሮች መለወጥ አትችልም፡፡"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ክልክል ድረስተለውጧል"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"የውሂብ አገልግሎት የታገደ ነው።"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"የአደጋ ጊዜአገልግሎት የታገደ ነው።"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"የድምፅ አገልግሎት ታግዷል።"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ዳግም ያቀናብሩ እና መተግበሪያ ዳግም ያስጀምሩት"</string>
<string name="aerr_report" msgid="5371800241488400617">"ግብረመልስ ይላኩ"</string>
<string name="aerr_close" msgid="2991640326563991340">"ዝጋ"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"ድምጽ-ከል አድርግ"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"መሣሪያ ዳግም እስኪጀመር ድረስ ድምጽ ያጥፉ"</string>
<string name="aerr_wait" msgid="3199956902437040261">"ጠብቅ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"መተግበሪያን ዝጋ"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ለተጨማሪ አማራጮች ነካ ያድርጉ።"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ማረሚያ ላለማንቃት ዳስስ።"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"የሳንካ ሪፖርት ለአስተዳዳሪ ይጋራ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"የእርስዎ የአይቲ አስተዳዳሪ መላ መፈለግ ላይ እንዲያግዝ የሳንካ ሪፖርት ጠይቀዋል"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"የሳንካ ሪፖርት ይጋራ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"የሳንካ ሪፖርትን በማጋራት ላይ…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"የእርስዎ አይቲ አስተዳዳሪ ለዚህ መሣሪያ መላ ለመፈለግ እንዲያግዝ የሳንካ ሪፖርት ጠይቀዋል። መተግበሪያዎች እና ውሂብ ሊጋሩ ይችላሉ። ይሄ መሣሪያዎን ለጊዜው ሊያዘገየው ይችላል።"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"የእርስዎ አይቲ አስተዳዳሪ ለዚህ መሣሪያ መላ ለመፈለግ የሳንካ ሪፖርት ጠይቀዋል። መተግበሪያዎች እና ውሂብ ሊጋሩ ይችላሉ።"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ይሄ መሣሪያዎን ለጊዜው ሊያዘገየው ይችላል"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ተቀበል"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ውድቅ አድርግ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"የሳንካ ሪፖርትን በመውሰድ ላይ…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ለመሰረዝ ይንኩ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ቁልፍ ሰሌዳዎችን ምረጥ"</string>
<string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ከመንቀል በፊት የማስከፈቻ ስርዓተ-ጥለት ጠይቅ"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"የመተግበሪያው መጠን ሊቀየር የሚችል አይደለም፣ በሁለት ጣቶች ያሸብልሉት።"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"በእርስዎ አስተዳዳሪ ተጭኗል"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"በአስተዳዳሪዎ ተዘምኗል"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጧል</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"የተለያዩ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
<string name="importance_from_person" msgid="9160133597262938296">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"የቋንቋ ምርጫ"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ቋንቋ ያክሉ"</string>
<string name="country_selection_title" msgid="2954859441620215513">"የክልል ምርጫ"</string>
<string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"የተጠቆሙ"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"በ%1$s አስተዳዳሪ ተሰናክሏል። የበለጠ ለመረዳት ያነጋግሯቸው።"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"አዲስ መልእክቶች አለዎት"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"ለመመልከት የኤስኤምኤስ መተግበሪያ ይክፈቱ"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"አንዳንድ ተግባሮች ላይገኙ ይችላሉ"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ለመቀጠል ይንኩ"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"የተጠቃሚ መገለጫ ተቆልፏል"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"አንዳንድ ተግባሮች የተገደቡ ሊሆኑ ይችላሉ"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"ለመክፈት መታ ያድርጉ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"የተጠቃሚ ውሂብ ተቆልፏል"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"የስራ መገለጫ ተቆልፏል"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"የስራ መገለጫውን እገዳ ለማንሳት መታ ያድርጉ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"ከ<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ጋር ተገናኝቷል"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ፋይሎችን ለመመልከት መታ ያድርጉ"</string>
<string name="pin_target" msgid="3052256031352291362">"ፒን"</string>
<string name="unpin_target" msgid="3556545602439143442">"ንቀል"</string>
<string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e927d5418099..d8a837776ab7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -92,7 +92,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"الإعداد الافتراضي لمعرف المتصل هو غير مقيّد. الاتصال التالي: غير مقيّد"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"الخدمة غير متوفرة."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"لا يمكنك تغيير إعداد معرف المتصل."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"تم تغيير الدخول المقيّد"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"خدمة البيانات محظورة."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"خدمة الطوارئ محظورة."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"الخدمة الصوتية محظورة."</string>
@@ -941,7 +940,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"إعادة ضبط التطبيق وإعادة تشغيله"</string>
<string name="aerr_report" msgid="5371800241488400617">"إرسال تعليقات"</string>
<string name="aerr_close" msgid="2991640326563991340">"إغلاق"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"تجاهل"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"التعطيل حتى إعادة تشغيل الجهاز"</string>
<string name="aerr_wait" msgid="3199956902437040261">"انتظار"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"إغلاق التطبيق"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1085,12 +1084,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"المس للحصول على مزيد من الخيارات."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏تم توصيل تصحيح أخطاء USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"‏المس لتعطيل تصحيح أخطاء USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"هل تريد مشاركة تقرير الأخطاء مع المشرف؟"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير بالأخطاء للمساعدة في تحري الخلل وإصلاحه"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"هل تريد مشاركة تقرير الخطأ؟"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"جارٍ مشاركة تقرير الخطأ…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير خطأ للمساعدة في تحرِّي مشكلة هذا الجهاز وإصلاحها. قد تتم مشاركة التطبيقات والبيانات. وقد يؤدي هذا إلى حدوث بطء مؤقت في جهازك."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير خطأ للمساعدة في تحرِّي مشكلة هذا الجهاز وإصلاحها. قد تتم مشاركة التطبيقات والبيانات."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"قد يؤدي هذا إلى حدوث بطء مؤقت في جهازك"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"رفض"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"جارٍ الحصول على تقرير بالأخطاء…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"المس للإلغاء"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"اختيار لوحات المفاتيح"</string>
<string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
@@ -1507,7 +1507,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"المطالبة برقم التعريف الشخصي قبل إزالة التثبيت"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"المطالبة بنقش إلغاء القفل قبل إزالة التثبيت"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"المطالبة بكلمة المرور قبل إزالة التثبيت"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"التطبيق غير قابل لتغيير الحجم، يمكنك تمريره بإصبعين."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"يمكن ألا يعمل التطبيق مع وضع تقسيم الشاشة."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"التطبيق لا يتيح تقسيم الشاشة."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"تم تثبيت الحزمة عن طريق المشرف"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"تم التحديث بواسطة المشرف"</string>
@@ -1613,12 +1613,11 @@
<item quantity="other">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g> من العناصر</item>
<item quantity="one">تم تحديد <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"متنوعة"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"لقد عيَّنت أهمية هذه الإشعارات."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"لقد عيَّنت أهمية هذه الإشعارات."</string>
<string name="importance_from_person" msgid="9160133597262938296">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"هل تسمح لـ <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g>؟"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"هل تسمح لـ <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"تفضيل اللغة"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"إضافة لغة"</string>
<string name="country_selection_title" msgid="2954859441620215513">"تفضيل المنطقة"</string>
<string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"المقترحة"</string>
@@ -1631,12 +1630,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"‏تم التعطيل بواسطة مشرف %1$s. يمكنك الاتصال به لمعرفة المزيد."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"لديك رسائل جديدة"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"‏فتح تطبيق الرسائل القصيرة SMS للعرض"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"قد لا تكون بعض الوظائف متاحة"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"المس للمتابعة"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"تم قفل الملف الشخصي للمستخدم"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ربما تكون بعض الوظائف مُقيّدة."</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"انقر لإلغاء القفل."</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"تم قفل بيانات المستخدم."</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"تم قفل الملف الشخصي للعمل."</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"انقر لإلغاء قفل الملف الشخصي للعمل"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"تم الاتصال بـ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"انقر لعرض الملفات"</string>
<string name="pin_target" msgid="3052256031352291362">"تثبيت"</string>
<string name="unpin_target" msgid="3556545602439143442">"إزالة تثبيت"</string>
<string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 211346fa6803..33d1616bf4d0 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Adətən zəng edənin ID\'si məhdudlaşdırılmır. Növbəti zəng: Məhdudlaşdırılmayıb"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Xidmət təmin edilməyib."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Siz zəng edənin ID nizamlarını dəyişə bilməzsiz."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Məhdudlaşdırılmış keçid dəyişdi"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Data xidmət bağlıdır."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Təcili xidmət bağlıdır."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Səs xidməti bağlıdır."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Tətbiqi sıfırlayın və yenidən başladın"</string>
<string name="aerr_report" msgid="5371800241488400617">"Geri əlaqə göndərin"</string>
<string name="aerr_close" msgid="2991640326563991340">"Bağla"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Susdur"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Cihaz yeniden başladılana kimi səssiz edin"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Gözləyin"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Tətbiqi qapadın"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1031,7 +1030,7 @@
<string name="sim_added_title" msgid="3719670512889674693">"SİM kart əlavə edildi"</string>
<string name="sim_added_message" msgid="7797975656153714319">"Mobil şəbəkəyə giriş üçün cihazınızı sıfırlayın."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Yenidən başlat"</string>
- <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Yeni SIM kartınızın düzgün işləməsi üçün, operatorunuzdan tətbiq yükləməli və açmalısınız."</string>
+ <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Yeni SIM kartınızın düzgün işləməsi üçün operatorunuzdan tətbiq yükləməli və açmalısınız."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"TƏTBİQİ ƏLDƏ EDİN"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"İNDİ YOX"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Yeni SIM kart taxılıb"</string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Əlavə seçimlər üçün toxunun."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB debaqı deaktivasiya etmək üçün toxunun."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Baq hesabatı admin ilə paylaşılsın?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT admininiz nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT admininiz bu cihazda nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi. Tətbiqlər və data paylaşıla və cihazınız surəti müvəqqəti azala bilər."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT admininiz bu cihazda nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi. Tətbiqlər və data paylaşıla bilər."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Bu cihazınızın sürətini müvəqqəti olaraq azalda bilər"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"QƏBUL EDİN"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RƏDD ET"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Baq xəbər verilir..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Ləğv etmək üçün toxunun"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturanı dəyişin"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturaları seçin"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ayırmadan öncə PIN istənilsin"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ayırmadan öncə kilid modeli istənilsin"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ayırmadan öncə parol istənilsin"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Tətbiq ölçüləndirilmədi, iki barmağınızla sürüşdürün."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Administratorunuz tərəfindən quraşdırılıb"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Sizin administrator tərəfindən yeniləndi"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Müxtəlif"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
<string name="importance_from_person" msgid="9160133597262938296">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabı ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə<xliff:g id="ACCOUNT">%2$s</xliff:g> (bu hesab ilə İstifadəçi artıq mövcuddur) hesabı ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Dil seçimi"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dil əlavə edin"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Region seçimi"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Təklif edilmiş"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s administratoru tərəfindən deaktiv edildi. Ətraflı məlumat üçün onlarla əlaqə saxlayın."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Yeni mesajlarınız var"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Baxmaq üçün SMS tətbiqini açın"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Bəzi funksiyalar əlçatan olmaya bilər"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Davam etmək üçün toxunun"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"İstifadəçi profili kilidlidir"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Bir neçə funksionallıq məhdudlaşdırıla bilər"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Kilidi açmaq üçün tıklayın"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"İstifadəçi datası kilidlidir"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"İş profili kilidlidir"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"İş profilinin kilidini açmaq üçün tıklayın"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> məhsuluna bağlandı"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Faylları görmək üçün basın"</string>
<string name="pin_target" msgid="3052256031352291362">"Pin kod"</string>
<string name="unpin_target" msgid="3556545602439143442">"Çıxarın"</string>
<string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</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 3edd5b73202c..8c00151c5fef 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -89,7 +89,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID pozivaoca podrazumevano nije ograničen. Sledeći poziv: Nije ograničen."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Usluga nije dobavljena."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete da promenite podešavanje ID-a korisnika."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ograničeni pristup je promenjen"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Usluga za podatke je blokirana."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usluga za hitne slučajeve je blokirana."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna usluga je blokirana."</string>
@@ -923,7 +922,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Resetuj i ponovo pokreni aplikaciju"</string>
<string name="aerr_report" msgid="5371800241488400617">"Pošaljite povratne informacije"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignoriši"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignoriši dok se uređaj ne pokrene ponovo"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Čekaj"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zatvori aplikaciju"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,12 +1060,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Želite li da delite izveštaj o grešci sa administratorom?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema u vezi sa ovim uređajem. Aplikacije i podaci mogu da se dele, a uređaj će se privremeno usporiti."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema u vezi sa ovim uređajem. Aplikacije i podaci mogu da se dele."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ovo će privremeno usporiti uređaj"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Izveštaj o grešci se generiše…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Dodirnite da biste otkazali"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izaberite tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
@@ -1477,7 +1477,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN pre otkačinjanja"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži šablon za otključavanje pre otkačinjanja"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži lozinku pre otkačinjanja"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veličina aplikacije ne može da se menja. Pomerajte je pomoću dva prsta."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće funkcionisati sa podeljenim ekranom."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava podeljeni ekran."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao je vaš administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao je administrator"</string>
@@ -1556,12 +1556,11 @@
<item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item>
<item quantity="other">Izabrano je <xliff:g id="COUNT_1">%1$d</xliff:g> stavki</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Vi podešavate važnost ovih obaveštenja."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Vi podešavate važnost ovih obaveštenja."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ovo je važno zbog ljudi koji učestvuju."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Želite li da dozvolite aplikaciji <xliff:g id="APP">%1$s</xliff:g> da napravi novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Želite li da dozvolite aplikaciji <xliff:g id="APP">%1$s</xliff:g> da napravi novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa ovim nalogom već postoji)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Podešavanje jezika"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dodajte jezik"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Podešavanje regiona"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženi"</string>
@@ -1574,12 +1573,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio je administrator kompanije %1$s. Kontaktirajte ga da biste saznali više."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nove poruke"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorite aplikaciju za SMS da biste pregledali"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Neke funkcije nisu dostupne"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Dodirnite da biste nastavili"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil korisnika je zaključan"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Neke funkcije su možda ograničene"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Dodirnite da biste otključali"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Podaci korisnika su zaključani"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil za Work je zaključan"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Dodirom otklj. profil za Work"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Povezano je sa proizvodom <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dodirnite za pregled datoteka"</string>
<string name="pin_target" msgid="3052256031352291362">"Zakači"</string>
<string name="unpin_target" msgid="3556545602439143442">"Otkači"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index cefa04d983d7..ac2a0ecedf52 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Стандартната идентификация на повикванията е „разрешено“. За следващото обаждане тя е разрешена."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Услугата не е обезпечена."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Не можете да променяте настройката за идентификация на обажданията."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ограниченият достъп е променен"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Услугата за данни е блокирана."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Услугата за спешни обаждания е блокирана."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Услугата за глас е блокирана."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Нулиране и рестартиране на приложението"</string>
<string name="aerr_report" msgid="5371800241488400617">"Изпращане на отзиви"</string>
<string name="aerr_close" msgid="2991640326563991340">"Затваряне"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Спиране"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Спиране, докато устройството се рестартира"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Изчакване"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Затваряне на приложението"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Докоснете за още опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Докоснете за деактивиране"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Да се сподели ли сигналът за програмна грешка с администратора?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Системният ви администратор заяви сигнал за програмна грешка с цел отстраняване на неизправностите"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели ли сигналът за програмна грешка?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Сигналът за програмна грешка се споделя…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Системният ви администратор поиска сигнал за програмна грешка с цел отстраняване на неизправностите на устройството. Възможно е да бъдат споделени приложения и данни и работата на устройството ви временно да се забави."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Системният ви администратор поиска сигнал за програмна грешка с цел отстраняване на неизправностите на това устройство. Възможно е да бъдат споделени приложения и данни."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Това може временно да забави работата на устройството ви"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЕМАМ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТХВЪРЛЯМ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Сигналът за програмна грешка се извлича…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Докоснете, за да анулирате"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Избиране на клавиатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запитване за фигура за отключване преди освобождаване"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запитване за парола преди освобождаване"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Приложението не може да се преоразмерява. Превъртете го с два пръста."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Приложението може да не работи в режим на разделен екран."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Приложението не поддържа разделен екран."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Инсталирано от администратора ви"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Актуализирано от администратора ви"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">Избрахте <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Избрахте <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Други"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Зададохте важността на тези известия."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Зададохте важността на тези известия."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Това е важно заради участващите хора."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Езиково предпочитание"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Добавяне на език"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Предпочитание за региона"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Деактивирано от администратора на %1$s. Свържете се с него, за да научите повече."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Имате нови съобщения"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Преглед в приложението за SMS"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Някои функции може да не са налице"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Докоснете, за да продължите"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Потр. профил е заключен"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Някои функции може да са огранич."</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Докоснете, за да отключите"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Потр. данни са заключени"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Служ. потр. профил е заключен"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Докоснете за откл. на служ. потр. профил"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Установена е връзка с <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Докоснете, за да прегледате файловете"</string>
<string name="pin_target" msgid="3052256031352291362">"Фиксиране"</string>
<string name="unpin_target" msgid="3556545602439143442">"Освобождаване"</string>
<string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 39fec290257a..4e6cd4bce7b4 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ডিফল্টরুপে কলার ID সীমাবদ্ধ করা থাকে না৷ পরবর্তী কল: সীমাবদ্ধ নয়"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"পরিষেবা প্রস্তুত নয়৷"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"আপনি কলার ID এর সেটিংস পরিবর্তন করতে পারবেন না৷"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"সীমিত অ্যাক্সেসের পরিবর্তন করা হয়েছে"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ডেটা পরিষেবা অবরুদ্ধ করা আছে৷"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"জরুরী পরিষেবা অবরুদ্ধ করা আছে৷"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"ভয়েস পরিষেবা অবরুদ্ধ করা আছে৷"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"পুনরায় সেট করুন এবং অ্যাপ্লিকেশান পুনরায় আরম্ভ করুন"</string>
<string name="aerr_report" msgid="5371800241488400617">"প্রতিক্রিয়া পাঠান"</string>
<string name="aerr_close" msgid="2991640326563991340">"বন্ধ করুন"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"নিঃশব্দ করুন"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ডিভাইসটি পুনরায় আরম্ভ না হওয়া পর্যন্ত নিঃশব্দ করুন"</string>
<string name="aerr_wait" msgid="3199956902437040261">"অপেক্ষা করুন"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"অ্যাপ্লিকেশান বন্ধ করুন"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"আরো বিকল্পের জন্য স্পর্শ করুন৷"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ডিবাগিং অক্ষম করতে স্পর্শ করুন৷"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"প্রশাসকের সাথে ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"আপনার IT প্রশাসক সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ত্রুটির প্রতিবেদন শেয়ার করা হচ্ছে..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"আপনার আইটি প্রশাসক এই ডিভাইসটির সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন৷ অ্যাপ্লিকেশানগুলি এবং ডেটা শেয়ার করা হতে পারে এবং আপনার ডিভাইসটিকে অস্থায়ীভাবে ধীর করে দিতে পারে৷"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"আপনার আইটি প্রশাসক এই ডিভাইসটির সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন৷ অ্যাপ্লিকেশান এবং ডেটা শেয়ার করা হতে পারে৷"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"এটি অস্থায়ীভাবে আপনার ডিভাইসটিকে ধীর করে দিতে পারে"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"স্বীকার করুন"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"অস্বীকার করুন"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ত্রুটির প্রতিবেদন নেওয়া হচ্ছে..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"বাতিল করতে স্পর্শ করুন"</string>
<string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"কীবোর্ড চয়ন করুন"</string>
<string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
@@ -1430,7 +1430,7 @@
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"বাতিল করা হয়েছে"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"সামগ্রী লেখায় ত্রুটি হয়েছে"</string>
<string name="reason_unknown" msgid="6048913880184628119">"অজানা"</string>
- <string name="reason_service_unavailable" msgid="7824008732243903268">"মুদ্রণ পরিষেবা সক্ষম করা নেই"</string>
+ <string name="reason_service_unavailable" msgid="7824008732243903268">"প্রিন্ট পরিষেবা সক্ষম করা নেই"</string>
<string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> পরিষেবা ইনস্টল হয়েছে"</string>
<string name="print_service_installed_message" msgid="5897362931070459152">"সক্ষম করতে আলতো চাপুন"</string>
<string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"প্রশাসক পিন লিখুন"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন করার আগে পিন চান"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"আনপিন করার আগে আনলক প্যাটার্ন চান"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"আনপিন করার আগে পাসওয়ার্ড চান"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"অ্যাপ্লিকেশানকে পুনরায় আকার দেওয়া যাবে না, দুটি আঙ্গুল ব্যবহার করে স্ক্রোল করুন৷"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"অ্যাপ্লিকেশানটি বিভক্ত স্ক্রীনে কাজ নাও করতে পারে৷"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রীন সমর্থন করে না৷"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"আপনার প্রশাসক দ্বারা ইনস্টল করা হয়েছে"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"আপনার প্রশাসক দ্বারা আপডেট করা হয়েছে"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"বিবিধ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
<string name="importance_from_person" msgid="9160133597262938296">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> কে <xliff:g id="ACCOUNT">%2$s</xliff:g> এর সাথে একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি দেবেন কি?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> কে <xliff:g id="ACCOUNT">%2$s</xliff:g> (একজন ব্যবহারকারী এই অ্যাকাউন্টে ইতিমধ্যেই বিদ্যমান আছেন) এর সাথে একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি দেবেন কি?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"পছন্দের ভাষা"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"একটি ভাষা যোগ করুন"</string>
<string name="country_selection_title" msgid="2954859441620215513">"পছন্দের অঞ্চল"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"প্রস্তাবিত"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s প্রশাসক অক্ষম করেছেন। আরো জানতে তাদের সাথে যোগাযোগ করুন।"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"আপনার নতুন বার্তা আছে"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"দেখার জন্য SMS অ্যাপ্লিকেশান খুলুন"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"কিছু ক্রিয়াকলাপ উপলব্ধ নাও হতে পারে"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"অবিরত রাখতে স্পর্শ করুন"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ব্যবহারকারীর প্রোফাইল লক করা আছে"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"কিছু ক্রিয়াকলাপ সীমিত হতে পারে"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"আনলক করতে আলতো চাপ দিন"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ব্যবহারকারির ডেটা লক করা হয়েছে"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"কর্মস্থলের প্রোফাইল লক করা আছে"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"কর্মস্থলের প্রোফাইল আনলক করতে আলতো চাপ দিন"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছে"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ফাইলগুলি দেখতে আলতো চাপ দিন"</string>
<string name="pin_target" msgid="3052256031352291362">"পিন করুন"</string>
<string name="unpin_target" msgid="3556545602439143442">"আনপিন করুন"</string>
<string name="app_info" msgid="6856026610594615344">"অ্যাপ্লিকেশানের তথ্য"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index ed31fcec2ec3..798f6f5c8ee7 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -20,1688 +20,909 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for byteShort (8340973892742019101) -->
- <skip />
- <!-- no translation found for kilobyteShort (5973789783504771878) -->
- <skip />
- <!-- no translation found for megabyteShort (6355851576770428922) -->
- <skip />
- <!-- no translation found for gigabyteShort (3259882455212193214) -->
- <skip />
- <!-- no translation found for terabyteShort (231613018159186962) -->
- <skip />
- <!-- no translation found for petabyteShort (5637816680144990219) -->
- <skip />
- <!-- no translation found for fileSizeSuffix (8897567456150907538) -->
- <skip />
- <!-- no translation found for durationDays (6652371460511178259) -->
- <skip />
- <!-- no translation found for durationDayHours (2713107458736744435) -->
- <skip />
- <!-- no translation found for durationDayHour (7293789639090958917) -->
- <skip />
- <!-- no translation found for durationHours (4266858287167358988) -->
- <skip />
- <!-- no translation found for durationHourMinutes (9029176248692041549) -->
- <skip />
- <!-- no translation found for durationHourMinute (2741677355177402539) -->
- <skip />
- <!-- no translation found for durationMinutes (3134226679883579347) -->
- <skip />
- <!-- no translation found for durationMinute (7155301744174623818) -->
- <skip />
- <!-- no translation found for durationMinuteSeconds (1424656185379003751) -->
- <skip />
- <!-- no translation found for durationMinuteSecond (3989228718067466680) -->
- <skip />
- <!-- no translation found for durationSeconds (8050088505238241405) -->
- <skip />
- <!-- no translation found for durationSecond (985669622276420331) -->
- <skip />
- <!-- no translation found for untitled (4638956954852782576) -->
- <skip />
- <!-- no translation found for emptyPhoneNumber (7694063042079676517) -->
- <skip />
- <!-- no translation found for unknownName (6867811765370350269) -->
- <skip />
- <!-- no translation found for defaultVoiceMailAlphaTag (2660020990097733077) -->
- <skip />
- <!-- no translation found for defaultMsisdnAlphaTag (2850889754919584674) -->
- <skip />
- <!-- no translation found for mmiError (5154499457739052907) -->
- <skip />
- <!-- no translation found for mmiFdnError (5224398216385316471) -->
- <skip />
- <!-- no translation found for serviceEnabled (8147278346414714315) -->
- <skip />
- <!-- no translation found for serviceEnabledFor (6856228140453471041) -->
- <skip />
- <!-- no translation found for serviceDisabled (1937553226592516411) -->
- <skip />
- <!-- no translation found for serviceRegistered (6275019082598102493) -->
- <skip />
- <!-- no translation found for serviceErased (1288584695297200972) -->
- <skip />
- <!-- no translation found for passwordIncorrect (7612208839450128715) -->
- <skip />
- <!-- no translation found for mmiComplete (8232527495411698359) -->
- <skip />
- <!-- no translation found for badPin (9015277645546710014) -->
- <skip />
- <!-- no translation found for badPuk (5487257647081132201) -->
- <skip />
- <!-- no translation found for mismatchPin (609379054496863419) -->
- <skip />
- <!-- no translation found for invalidPin (3850018445187475377) -->
- <skip />
- <!-- no translation found for invalidPuk (8761456210898036513) -->
- <skip />
- <!-- no translation found for needPuk (919668385956251611) -->
- <skip />
- <!-- no translation found for needPuk2 (4526033371987193070) -->
- <skip />
- <!-- no translation found for enablePin (209412020907207950) -->
- <skip />
- <!-- no translation found for pinpuk_attempts (1251012001539225582) -->
- <!-- no translation found for imei (2625429890869005782) -->
- <skip />
- <!-- no translation found for meid (4841221237681254195) -->
- <skip />
- <!-- no translation found for ClipMmi (6952821216480289285) -->
- <skip />
- <!-- no translation found for ClirMmi (7784673673446833091) -->
- <skip />
- <!-- no translation found for ColpMmi (3065121483740183974) -->
- <skip />
- <!-- no translation found for ColrMmi (4996540314421889589) -->
- <skip />
- <!-- no translation found for CfMmi (5123218989141573515) -->
- <skip />
- <!-- no translation found for CwMmi (9129678056795016867) -->
- <skip />
- <!-- no translation found for BaMmi (455193067926770581) -->
- <skip />
- <!-- no translation found for PwdMmi (7043715687905254199) -->
- <skip />
- <!-- no translation found for PinMmi (3113117780361190304) -->
- <skip />
- <!-- no translation found for CnipMmi (3110534680557857162) -->
- <skip />
- <!-- no translation found for CnirMmi (3062102121430548731) -->
- <skip />
- <!-- no translation found for ThreeWCMmi (9051047170321190368) -->
- <skip />
- <!-- no translation found for RuacMmi (7827887459138308886) -->
- <skip />
- <!-- no translation found for CndMmi (3116446237081575808) -->
- <skip />
- <!-- no translation found for DndMmi (1265478932418334331) -->
- <skip />
- <!-- no translation found for CLIRDefaultOnNextCallOn (429415409145781923) -->
- <skip />
- <!-- no translation found for CLIRDefaultOnNextCallOff (3092918006077864624) -->
- <skip />
- <!-- no translation found for CLIRDefaultOffNextCallOn (6179425182856418465) -->
- <skip />
- <!-- no translation found for CLIRDefaultOffNextCallOff (2567998633124408552) -->
- <skip />
- <!-- no translation found for serviceNotProvisioned (8614830180508686666) -->
- <skip />
- <!-- no translation found for CLIRPermanent (3377371145926835671) -->
- <skip />
- <!-- no translation found for RestrictedChangedTitle (5592189398956187498) -->
- <skip />
- <!-- no translation found for RestrictedOnData (8653794784690065540) -->
- <skip />
- <!-- no translation found for RestrictedOnEmergency (6581163779072833665) -->
- <skip />
- <!-- no translation found for RestrictedOnNormal (4953867011389750673) -->
- <skip />
- <!-- no translation found for RestrictedOnAllVoice (3396963652108151260) -->
- <skip />
- <!-- no translation found for RestrictedOnSms (8314352327461638897) -->
- <skip />
- <!-- no translation found for RestrictedOnVoiceData (996636487106171320) -->
- <skip />
- <!-- no translation found for RestrictedOnVoiceSms (1888588152792023873) -->
- <skip />
- <!-- no translation found for RestrictedOnAll (5643028264466092821) -->
- <skip />
- <!-- no translation found for peerTtyModeFull (6165351790010341421) -->
- <skip />
- <!-- no translation found for peerTtyModeHco (5728602160669216784) -->
- <skip />
- <!-- no translation found for peerTtyModeVco (1742404978686538049) -->
- <skip />
- <!-- no translation found for peerTtyModeOff (3280819717850602205) -->
- <skip />
- <!-- no translation found for serviceClassVoice (1258393812335258019) -->
- <skip />
- <!-- no translation found for serviceClassData (872456782077937893) -->
- <skip />
- <!-- no translation found for serviceClassFAX (5566624998840486475) -->
- <skip />
- <!-- no translation found for serviceClassSMS (2015460373701527489) -->
- <skip />
- <!-- no translation found for serviceClassDataAsync (4523454783498551468) -->
- <skip />
- <!-- no translation found for serviceClassDataSync (7530000519646054776) -->
- <skip />
- <!-- no translation found for serviceClassPacket (6991006557993423453) -->
- <skip />
- <!-- no translation found for serviceClassPAD (3235259085648271037) -->
- <skip />
- <!-- no translation found for roamingText0 (7170335472198694945) -->
- <skip />
- <!-- no translation found for roamingText1 (5314861519752538922) -->
- <skip />
- <!-- no translation found for roamingText2 (8969929049081268115) -->
- <skip />
- <!-- no translation found for roamingText3 (5148255027043943317) -->
- <skip />
- <!-- no translation found for roamingText4 (8808456682550796530) -->
- <skip />
- <!-- no translation found for roamingText5 (7604063252850354350) -->
- <skip />
- <!-- no translation found for roamingText6 (2059440825782871513) -->
- <skip />
- <!-- no translation found for roamingText7 (7112078724097233605) -->
- <skip />
- <!-- no translation found for roamingText8 (5989569778604089291) -->
- <skip />
- <!-- no translation found for roamingText9 (7969296811355152491) -->
- <skip />
- <!-- no translation found for roamingText10 (3992906999815316417) -->
- <skip />
- <!-- no translation found for roamingText11 (4154476854426920970) -->
- <skip />
- <!-- no translation found for roamingText12 (1189071119992726320) -->
- <skip />
- <!-- no translation found for roamingTextSearching (8360141885972279963) -->
- <skip />
- <!-- no translation found for wfcRegErrorTitle (2301376280632110664) -->
- <skip />
+ <string name="byteShort" msgid="8340973892742019101">"B"</string>
+ <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
+ <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
+ <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
+ <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
+ <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dana"</string>
+ <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dan <xliff:g id="HOURS">%2$d</xliff:g> sati"</string>
+ <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dan <xliff:g id="HOURS">%2$d</xliff:g> sat"</string>
+ <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> sati"</string>
+ <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> sat <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+ <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> sat <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+ <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
+ <string name="durationMinute" msgid="7155301744174623818">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
+ <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
+ <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
+ <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
+ <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
+ <string name="untitled" msgid="4638956954852782576">"&lt;Bez naslova&gt;"</string>
+ <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nema broja telefona)"</string>
+ <string name="unknownName" msgid="6867811765370350269">"Nepoznato"</string>
+ <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Govorna pošta"</string>
+ <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
+ <string name="mmiError" msgid="5154499457739052907">"Problem sa povezivanjem ili nevažeći MMI kôd."</string>
+ <string name="mmiFdnError" msgid="5224398216385316471">"Operacija je ograničena samo na brojeve fiksnog biranja."</string>
+ <string name="serviceEnabled" msgid="8147278346414714315">"Usluga je omogućena."</string>
+ <string name="serviceEnabledFor" msgid="6856228140453471041">"Usluga je omogućena za:"</string>
+ <string name="serviceDisabled" msgid="1937553226592516411">"Usluga je onemogućena."</string>
+ <string name="serviceRegistered" msgid="6275019082598102493">"Registracija je uspješno izvršena."</string>
+ <string name="serviceErased" msgid="1288584695297200972">"Brisanje je uspješno izvršeno."</string>
+ <string name="passwordIncorrect" msgid="7612208839450128715">"Netačna lozinka."</string>
+ <string name="mmiComplete" msgid="8232527495411698359">"MMI kôd izvršen."</string>
+ <string name="badPin" msgid="9015277645546710014">"Stari PIN koji ste unijeli nije ispravan."</string>
+ <string name="badPuk" msgid="5487257647081132201">"PUK koji ste unijeli nije ispravan."</string>
+ <string name="mismatchPin" msgid="609379054496863419">"PIN-ovi koje ste unijeli se ne podudaraju."</string>
+ <string name="invalidPin" msgid="3850018445187475377">"Unesite PIN koji sadrži 4 do 8 brojeva."</string>
+ <string name="invalidPuk" msgid="8761456210898036513">"Unesite PUK koji sadrži 8 ili više brojeva."</string>
+ <string name="needPuk" msgid="919668385956251611">"SIM kartica je zaključana PUK-om. Unesite PUK kôd za otključavanje kartice."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Unesite PUK2 kako biste deblokirali SIM karticu."</string>
+ <string name="enablePin" msgid="209412020907207950">"Nije uspjelo. Prvo omogućite SIM/RUIM zaključavanje."</string>
+ <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+ <item quantity="one">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj prije nego se SIM kartica zaključa.</item>
+ <item quantity="few">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego se SIM kartica zaključa.</item>
+ <item quantity="other">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego se SIM kartica zaključa.</item>
+ </plurals>
+ <string name="imei" msgid="2625429890869005782">"IMEI"</string>
+ <string name="meid" msgid="4841221237681254195">"MEID"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"ID dolaznog poziva"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"ID odlaznog poziva"</string>
+ <string name="ColpMmi" msgid="3065121483740183974">"Identifikacija povezane linije"</string>
+ <string name="ColrMmi" msgid="4996540314421889589">"Ograničenje identifikacije povezane linije"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"Preusmjeravanje poziva"</string>
+ <string name="CwMmi" msgid="9129678056795016867">"Poziv na čekanju"</string>
+ <string name="BaMmi" msgid="455193067926770581">"Zabrana poziva"</string>
+ <string name="PwdMmi" msgid="7043715687905254199">"Promjena lozinke"</string>
+ <string name="PinMmi" msgid="3113117780361190304">"Promjena PIN-a"</string>
+ <string name="CnipMmi" msgid="3110534680557857162">"Broj pozivaoca dostupan"</string>
+ <string name="CnirMmi" msgid="3062102121430548731">"Broj pozivaoca zabranjen"</string>
+ <string name="ThreeWCMmi" msgid="9051047170321190368">"Poziv između tri osobe"</string>
+ <string name="RuacMmi" msgid="7827887459138308886">"Odbijanje neželjenih i dosadnih poziva"</string>
+ <string name="CndMmi" msgid="3116446237081575808">"Isporuka broja pozivaoca"</string>
+ <string name="DndMmi" msgid="1265478932418334331">"Ne ometaj"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Prikaz ID-a pozivaoca u zadanim postavkama zabranjen. Sljedeći poziv: zabranjen"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Prikaz ID-a pozivaoca u zadanim postavkama zabranjen. Sljedeći poziv: nije zabranjen"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Prikaz ID-a pozivaoca u zadanim postavkama nije zabranjen. Sljedeći poziv: zabranjen"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Prikaz ID-a pozivaoca u zadanim postavkama nije zabranjen. Sljedeći poziv: nije zabranjen"</string>
+ <string name="serviceNotProvisioned" msgid="8614830180508686666">"Uslugu nije moguće koristiti."</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete promijeniti postavke ID-a pozivaoca."</string>
+ <string name="RestrictedOnData" msgid="8653794784690065540">"Usluga prijenosa podataka je blokirana."</string>
+ <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hitni pozivi su blokirani."</string>
+ <string name="RestrictedOnNormal" msgid="4953867011389750673">"Govorne usluge su blokirane."</string>
+ <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Sve govorne usluge su blokirane."</string>
+ <string name="RestrictedOnSms" msgid="8314352327461638897">"SMS usluga je blokirana."</string>
+ <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Blokirane su govorne usluge i usluge prijenosa podataka."</string>
+ <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Blokirane su govorne/SMS usluge."</string>
+ <string name="RestrictedOnAll" msgid="5643028264466092821">"Blokirane su sve govorne i SMS usluge te usluge prijenosa podataka."</string>
+ <string name="peerTtyModeFull" msgid="6165351790010341421">"Ravnopravni uređaj zatražio TTY PUNI način rada"</string>
+ <string name="peerTtyModeHco" msgid="5728602160669216784">"Ravnopravni uređaj zatražio TTY HCO način rada"</string>
+ <string name="peerTtyModeVco" msgid="1742404978686538049">"Ravnopravni uređaj zatražio TTY VCO način rada"</string>
+ <string name="peerTtyModeOff" msgid="3280819717850602205">"Ravnopravni uređaj zatražio TTY ISKLJUČENI način rada"</string>
+ <string name="serviceClassVoice" msgid="1258393812335258019">"Govorna"</string>
+ <string name="serviceClassData" msgid="872456782077937893">"Podatke"</string>
+ <string name="serviceClassFAX" msgid="5566624998840486475">"Faks"</string>
+ <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
+ <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asinhroni"</string>
+ <string name="serviceClassDataSync" msgid="7530000519646054776">"Sinhroni"</string>
+ <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
+ <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="roamingText0" msgid="7170335472198694945">"Uključen pokazatelj da je uređaj u roamingu"</string>
+ <string name="roamingText1" msgid="5314861519752538922">"Isključen pokazatelj da je uređaj u roamingu"</string>
+ <string name="roamingText2" msgid="8969929049081268115">"Pokazatelj da je uređaj u roamingu treperi"</string>
+ <string name="roamingText3" msgid="5148255027043943317">"Izvan naselja"</string>
+ <string name="roamingText4" msgid="8808456682550796530">"Izvan zgrade"</string>
+ <string name="roamingText5" msgid="7604063252850354350">"Roaming - preferirani sistem"</string>
+ <string name="roamingText6" msgid="2059440825782871513">"Roaming - sistem dostupan"</string>
+ <string name="roamingText7" msgid="7112078724097233605">"Roaming - udruženi partner"</string>
+ <string name="roamingText8" msgid="5989569778604089291">"Roaming - premium partner"</string>
+ <string name="roamingText9" msgid="7969296811355152491">"Roaming - sve usluge potpuno dostupne"</string>
+ <string name="roamingText10" msgid="3992906999815316417">"Roaming - djelimična funkcionalnost usluga"</string>
+ <string name="roamingText11" msgid="4154476854426920970">"Oznaka da je uređaj u roamingu uključena"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"Oznaka da je uređaj u roamingu ugašena"</string>
+ <string name="roamingTextSearching" msgid="8360141885972279963">"Traženje usluge"</string>
+ <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi pozivanje"</string>
<string-array name="wfcOperatorErrorAlertMessages">
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
</string-array>
- <!-- no translation found for wfcSpnFormat (8211621332478306568) -->
- <skip />
- <!-- no translation found for wfcDataSpnFormat (1118052028767666883) -->
- <skip />
- <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
- <skip />
- <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
- <skip />
- <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
- <skip />
- <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
- <skip />
- <!-- no translation found for cfTemplateNotForwarded (1683685883841272560) -->
- <skip />
- <!-- no translation found for cfTemplateForwarded (1302922117498590521) -->
- <skip />
- <!-- no translation found for cfTemplateForwardedTime (9206251736527085256) -->
- <skip />
- <!-- no translation found for cfTemplateRegistered (5073237827620166285) -->
- <skip />
- <!-- no translation found for cfTemplateRegisteredTime (6781621964320635172) -->
- <skip />
- <!-- no translation found for fcComplete (3118848230966886575) -->
- <skip />
- <!-- no translation found for fcError (3327560126588500777) -->
- <skip />
- <!-- no translation found for httpErrorOk (1191919378083472204) -->
- <skip />
- <!-- no translation found for httpError (7956392511146698522) -->
- <skip />
- <!-- no translation found for httpErrorLookup (4711687456111963163) -->
- <skip />
- <!-- no translation found for httpErrorUnsupportedAuthScheme (6299980280442076799) -->
- <skip />
- <!-- no translation found for httpErrorAuth (1435065629438044534) -->
- <skip />
- <!-- no translation found for httpErrorProxyAuth (1788207010559081331) -->
- <skip />
- <!-- no translation found for httpErrorConnect (8714273236364640549) -->
- <skip />
- <!-- no translation found for httpErrorIO (2340558197489302188) -->
- <skip />
- <!-- no translation found for httpErrorTimeout (4743403703762883954) -->
- <skip />
- <!-- no translation found for httpErrorRedirectLoop (8679596090392779516) -->
- <skip />
- <!-- no translation found for httpErrorUnsupportedScheme (5015730812906192208) -->
- <skip />
- <!-- no translation found for httpErrorFailedSslHandshake (96549606000658641) -->
- <skip />
- <!-- no translation found for httpErrorBadUrl (3636929722728881972) -->
- <skip />
- <!-- no translation found for httpErrorFile (2170788515052558676) -->
- <skip />
- <!-- no translation found for httpErrorFileNotFound (6203856612042655084) -->
- <skip />
- <!-- no translation found for httpErrorTooManyRequests (1235396927087188253) -->
- <skip />
- <!-- no translation found for notification_title (8967710025036163822) -->
- <skip />
- <!-- no translation found for contentServiceSync (8353523060269335667) -->
- <skip />
- <!-- no translation found for contentServiceSyncNotificationTitle (397743349191901458) -->
- <skip />
- <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8100981435080696431) -->
- <skip />
- <!-- no translation found for low_memory (6494019234102154896) -->
- <skip />
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
- <!-- no translation found for low_memory (516619861191025923) -->
- <skip />
- <!-- no translation found for low_memory (3475999286680000541) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_noti_by_administrator (550758088185764312) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
- <skip />
- <!-- no translation found for work_profile_deleted (5005572078641980632) -->
- <skip />
- <!-- no translation found for work_profile_deleted_description (6305147513054341102) -->
- <skip />
- <!-- no translation found for work_profile_deleted_details (226615743462361248) -->
- <skip />
- <!-- no translation found for work_profile_deleted_description_dpm_wipe (6019770344820507579) -->
- <skip />
- <!-- no translation found for factory_reset_warning (5423253125642394387) -->
- <skip />
- <!-- no translation found for factory_reset_message (4905025204141900666) -->
- <skip />
- <!-- no translation found for me (6545696007631404292) -->
- <skip />
- <!-- no translation found for power_dialog (8545351420865202853) -->
- <skip />
- <!-- no translation found for power_dialog (6153888706430556356) -->
- <skip />
- <!-- no translation found for power_dialog (1319919075463988638) -->
- <skip />
- <!-- no translation found for silent_mode (7167703389802618663) -->
- <skip />
- <!-- no translation found for turn_on_radio (3912793092339962371) -->
- <skip />
- <!-- no translation found for turn_off_radio (8198784949987062346) -->
- <skip />
- <!-- no translation found for screen_lock (799094655496098153) -->
- <skip />
- <!-- no translation found for power_off (4266614107412865048) -->
- <skip />
- <!-- no translation found for silent_mode_silent (319298163018473078) -->
- <skip />
- <!-- no translation found for silent_mode_vibrate (7072043388581551395) -->
- <skip />
- <!-- no translation found for silent_mode_ring (8592241816194074353) -->
- <skip />
- <!-- no translation found for reboot_to_update_title (6212636802536823850) -->
- <skip />
- <!-- no translation found for reboot_to_update_prepare (6305853831955310890) -->
- <skip />
- <!-- no translation found for reboot_to_update_package (3871302324500927291) -->
- <skip />
- <!-- no translation found for reboot_to_update_reboot (6428441000951565185) -->
- <skip />
- <!-- no translation found for reboot_to_reset_title (4142355915340627490) -->
- <skip />
- <!-- no translation found for reboot_to_reset_message (2432077491101416345) -->
- <skip />
- <!-- no translation found for shutdown_progress (2281079257329981203) -->
- <skip />
- <!-- no translation found for shutdown_confirm (3385745179555731470) -->
- <skip />
- <!-- no translation found for shutdown_confirm (476672373995075359) -->
- <skip />
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
- <!-- no translation found for shutdown_confirm (649792175242821353) -->
- <skip />
- <!-- no translation found for shutdown_confirm_question (2906544768881136183) -->
- <skip />
- <!-- no translation found for reboot_safemode_title (7054509914500140361) -->
- <skip />
- <!-- no translation found for reboot_safemode_confirm (55293944502784668) -->
- <skip />
- <!-- no translation found for recent_tasks_title (3691764623638127888) -->
- <skip />
- <!-- no translation found for no_recent_tasks (8794906658732193473) -->
- <skip />
- <!-- no translation found for global_actions (408477140088053665) -->
- <skip />
- <!-- no translation found for global_actions (7240386462508182976) -->
- <skip />
- <!-- no translation found for global_actions (2406416831541615258) -->
- <skip />
- <!-- no translation found for global_action_lock (2844945191792119712) -->
- <skip />
- <!-- no translation found for global_action_power_off (4471879440839879722) -->
- <skip />
- <!-- no translation found for global_action_bug_report (7934010578922304799) -->
- <skip />
- <!-- no translation found for bugreport_title (2667494803742548533) -->
- <skip />
- <!-- no translation found for bugreport_message (398447048750350456) -->
- <skip />
- <!-- no translation found for bugreport_option_interactive_title (8635056131768862479) -->
- <skip />
- <!-- no translation found for bugreport_option_interactive_summary (8180152634022797629) -->
- <skip />
- <!-- no translation found for bugreport_option_full_title (6354382025840076439) -->
- <skip />
- <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Ta opcija vam omogućava minimalno ometanje sustava kad uređaj ne reagira ili je prespor ili kada su vam potrebni svi odjeljci izvještaja. Ne izrađuje se snimka ekrana i ne možete unijeti više detalja."</string>
- <!-- no translation found for bugreport_countdown (6878900193900090368) -->
- <!-- no translation found for global_action_toggle_silent_mode (8219525344246810925) -->
- <skip />
- <!-- no translation found for global_action_silent_mode_on_status (3289841937003758806) -->
- <skip />
- <!-- no translation found for global_action_silent_mode_off_status (1506046579177066419) -->
- <skip />
- <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
- <skip />
- <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
- <skip />
- <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
- <skip />
- <!-- no translation found for global_action_settings (1756531602592545966) -->
- <skip />
- <!-- no translation found for global_action_assist (3892832961594295030) -->
- <skip />
- <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
- <skip />
- <!-- no translation found for global_action_lockdown (8751542514724332873) -->
- <skip />
- <!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
- <skip />
- <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
- <skip />
- <!-- no translation found for notification_hidden_text (1135169301897151909) -->
- <skip />
+ <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+ <string name="wfcDataSpnFormat" msgid="1118052028767666883">"%s"</string>
+ <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
+ <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi"</string>
+ <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Prednost ima mobilna mreža"</string>
+ <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Samo Wi-Fi"</string>
+ <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije proslijeđen"</string>
+ <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> za <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundi"</string>
+ <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije proslijeđen"</string>
+ <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Poziv nije proslijeđen"</string>
+ <string name="fcComplete" msgid="3118848230966886575">"Kôd za posebne usluge potpun."</string>
+ <string name="fcError" msgid="3327560126588500777">"Problem sa povezivanjem ili nevažeći kôd za posebne usluge."</string>
+ <string name="httpErrorOk" msgid="1191919378083472204">"Uredu"</string>
+ <string name="httpError" msgid="7956392511146698522">"Došlo je do greške na mreži."</string>
+ <string name="httpErrorLookup" msgid="4711687456111963163">"Pronalaženje URL-a nije uspjelo."</string>
+ <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Shema za provjeru vjerodostojnosti stranice nije podržana."</string>
+ <string name="httpErrorAuth" msgid="1435065629438044534">"Došlo je do greške prilikom provjere vjerodostojnosti."</string>
+ <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Došlo je do greške prilikom provjere vjerodostojnosti preko proksi servera."</string>
+ <string name="httpErrorConnect" msgid="8714273236364640549">"Povezivanje sa serverom nije uspjelo."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Veza sa serverom nije uspostavljena. Pokušajte ponovo kasnije."</string>
+ <string name="httpErrorTimeout" msgid="4743403703762883954">"Vrijeme za uspostavljanje veze sa serverom je isteklo."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stranica sadrži prevelik broj preusmjeravanja na server."</string>
+ <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol nije podržan."</string>
+ <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Uspostavljanje sigurne veze nije uspjelo."</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"Greška pri otvaranju stranice zbog neispravnog URL-a."</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"Pristupanje fajlu nije uspjelo."</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Pronalaženje traženog fajla nije uspjelo."</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Trenutno se obrađuje previše zahtjeva. Pokušajte ponovo kasnije."</string>
+ <string name="notification_title" msgid="8967710025036163822">"Greška u prijavi za račun <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+ <string name="contentServiceSync" msgid="8353523060269335667">"Sinhroniziranje"</string>
+ <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhroniziranje"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Obrisano previše unosa aplikacije <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"Pohrana tableta je puna. Izbrišite fajlove kako biste oslobodili prostor."</string>
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Prostor za gledanje je pun. Obrišite neke fajlove da oslobodite prostor."</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"Prostor TV-a za pohranu je pun. Obrišite neke fajlove da oslobodite prostor."</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"Pohrana telefona je puna. Izbrišite fajlove kako biste oslobodili prostor."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža može biti nadzirana"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od nepoznate treće strane"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"od strane administratora vašeg profila za posao"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Od <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
+ <string name="work_profile_deleted" msgid="5005572078641980632">"Poslovni profil je obrisan"</string>
+ <string name="work_profile_deleted_description" msgid="6305147513054341102">"Poslovni profil je obrisan jer nedostaje aplikacija administratora."</string>
+ <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="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>
+ <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcije tableta"</string>
+ <string name="power_dialog" product="tv" msgid="6153888706430556356">"Opcije za TV"</string>
+ <string name="power_dialog" product="default" msgid="1319919075463988638">"Opcije telefona"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"Nečujni način rada"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"Uključi bežičnu vezu"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"Isključi bežičnu vezu"</string>
+ <string name="screen_lock" msgid="799094655496098153">"Zaključavanje ekrana"</string>
+ <string name="power_off" msgid="4266614107412865048">"Isključi telefon"</string>
+ <string name="silent_mode_silent" msgid="319298163018473078">"Zvuk zvona isključen"</string>
+ <string name="silent_mode_vibrate" msgid="7072043388581551395">"Zvuk zvona na vibraciji"</string>
+ <string name="silent_mode_ring" msgid="8592241816194074353">"Zvuk zvona uključen"</string>
+ <string name="reboot_to_update_title" msgid="6212636802536823850">"Ažuriranje sistema Android"</string>
+ <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Priprema za ažuriranje..."</string>
+ <string name="reboot_to_update_package" msgid="3871302324500927291">"Obrađuje se paket ažuriranja..."</string>
+ <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Ponovno se pokreće..."</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"Vraćanje na tvorničke postavke"</string>
+ <string name="reboot_to_reset_message" msgid="2432077491101416345">"Ponovno se pokreće..."</string>
+ <string name="shutdown_progress" msgid="2281079257329981203">"Gašenje u toku…"</string>
+ <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Vaš tablet će se isključiti."</string>
+ <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"TV će se isključiti."</string>
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Sat će se isključiti."</string>
+ <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon će se isključiti."</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"Želite li ugasiti telefon?"</string>
+ <string name="reboot_safemode_title" msgid="7054509914500140361">"Ponovo pokreni uređaj u sigurnom načinu rada"</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"Želite li pokrenuti uređaj u sigurnom načinu rada? To će onemogućiti sve aplikacije trećih strana koje ste instalirali. One će biti obnovljene kada ponovo pokrenete uređaj."</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"Nedavni zadaci"</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"Nema nedavno pokrenutih aplikacija."</string>
+ <string name="global_actions" product="tablet" msgid="408477140088053665">"Opcije tableta"</string>
+ <string name="global_actions" product="tv" msgid="7240386462508182976">"Opcije za TV"</string>
+ <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje ekrana"</string>
+ <string name="global_action_power_off" msgid="4471879440839879722">"Isključi telefon"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"Izvještaj o greškama"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao poruka e-pošte. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
+ <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivni izvještaj"</string>
+ <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Koristite ovo u većini slučajeva. Omogućava vam praćenje progresa izvještaja i unošenje više detalja o datom problemu. Neke manje korištene oblasti za čiji izvještaj je potrebno mnogo vremena mogu biti izostavljene."</string>
+ <string name="bugreport_option_full_title" msgid="6354382025840076439">"Kompletan izvještaj"</string>
+ <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Koristite ovu opciju za minimalno ometanje sistema kad uređaj ne reaguje ili je prespor, ili kada su vam potrebni svi odjeljci izvještaja. Opcija ne uzima snimku ekrana i ne dozvoljava unošenje više detalja."</string>
+ <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+ <item quantity="one">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekundu.</item>
+ <item quantity="few">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
+ <item quantity="other">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item>
+ </plurals>
+ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Nečujni način rada"</string>
+ <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je isključen"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je uključen"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način rada u avionu"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u avionu"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Način rada u avionu ugašen"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Postavke"</string>
+ <string name="global_action_assist" msgid="3892832961594295030">"Pomoć"</string>
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
+ <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj odmah"</string>
+ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj skriven u skladu sa pravilima"</string>
- <!-- no translation found for safeMode (2788228061547930246) -->
- <skip />
- <!-- no translation found for android_system_label (6577375335728551336) -->
- <skip />
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
- <!-- no translation found for permgrouplab_contacts (3657758145679177612) -->
- <skip />
- <!-- no translation found for permgroupdesc_contacts (6951499528303668046) -->
- <skip />
- <!-- no translation found for permgrouplab_location (7275582855722310164) -->
- <skip />
- <!-- no translation found for permgroupdesc_location (1346617465127855033) -->
- <skip />
- <!-- no translation found for permgrouplab_calendar (5863508437783683902) -->
- <skip />
- <!-- no translation found for permgroupdesc_calendar (3889615280211184106) -->
- <skip />
- <!-- no translation found for permgrouplab_sms (228308803364967808) -->
- <skip />
- <!-- no translation found for permgroupdesc_sms (4656988620100940350) -->
- <skip />
- <!-- no translation found for permgrouplab_storage (1971118770546336966) -->
- <skip />
- <!-- no translation found for permgroupdesc_storage (637758554581589203) -->
- <skip />
- <!-- no translation found for permgrouplab_microphone (171539900250043464) -->
- <skip />
- <!-- no translation found for permgroupdesc_microphone (4988812113943554584) -->
- <skip />
- <!-- no translation found for permgrouplab_camera (4820372495894586615) -->
- <skip />
- <!-- no translation found for permgroupdesc_camera (3250611594678347720) -->
- <skip />
- <!-- no translation found for permgrouplab_phone (5229115638567440675) -->
- <skip />
- <!-- no translation found for permgroupdesc_phone (6234224354060641055) -->
- <skip />
- <!-- no translation found for permgrouplab_sensors (416037179223226722) -->
- <skip />
- <!-- no translation found for permgroupdesc_sensors (7147968539346634043) -->
- <skip />
- <!-- no translation found for capability_title_canRetrieveWindowContent (3901717936930170320) -->
- <skip />
- <!-- no translation found for capability_desc_canRetrieveWindowContent (3772225008605310672) -->
- <skip />
- <!-- no translation found for capability_title_canRequestTouchExploration (3108723364676667320) -->
- <skip />
- <!-- no translation found for capability_desc_canRequestTouchExploration (5800552516779249356) -->
- <skip />
- <!-- no translation found for capability_title_canRequestEnhancedWebAccessibility (1739881766522594073) -->
- <skip />
- <!-- no translation found for capability_desc_canRequestEnhancedWebAccessibility (7881063961507511765) -->
- <skip />
- <!-- no translation found for capability_title_canRequestFilterKeyEvents (2103440391902412174) -->
- <skip />
- <!-- no translation found for capability_desc_canRequestFilterKeyEvents (7463135292204152818) -->
- <skip />
- <!-- no translation found for capability_title_canControlMagnification (3593493281059424855) -->
- <skip />
- <!-- no translation found for capability_desc_canControlMagnification (4791858203568383773) -->
- <skip />
- <!-- no translation found for capability_title_canPerformGestures (7418984730362576862) -->
- <skip />
- <!-- no translation found for capability_desc_canPerformGestures (8296373021636981249) -->
- <skip />
- <!-- no translation found for permlab_statusBar (7417192629601890791) -->
- <skip />
- <!-- no translation found for permdesc_statusBar (8434669549504290975) -->
- <skip />
- <!-- no translation found for permlab_statusBarService (4826835508226139688) -->
- <skip />
- <!-- no translation found for permdesc_statusBarService (716113660795976060) -->
- <skip />
- <!-- no translation found for permlab_expandStatusBar (1148198785937489264) -->
- <skip />
- <!-- no translation found for permdesc_expandStatusBar (6917549437129401132) -->
- <skip />
- <!-- no translation found for permlab_install_shortcut (4279070216371564234) -->
- <skip />
- <!-- no translation found for permdesc_install_shortcut (8341295916286736996) -->
- <skip />
- <!-- no translation found for permlab_uninstall_shortcut (4729634524044003699) -->
- <skip />
- <!-- no translation found for permdesc_uninstall_shortcut (6745743474265057975) -->
- <skip />
- <!-- no translation found for permlab_processOutgoingCalls (3906007831192990946) -->
- <skip />
- <!-- no translation found for permdesc_processOutgoingCalls (5156385005547315876) -->
- <skip />
- <!-- no translation found for permlab_receiveSms (8673471768947895082) -->
- <skip />
- <!-- no translation found for permdesc_receiveSms (6424387754228766939) -->
- <skip />
- <!-- no translation found for permlab_receiveMms (1821317344668257098) -->
- <skip />
- <!-- no translation found for permdesc_receiveMms (533019437263212260) -->
- <skip />
- <!-- no translation found for permlab_readCellBroadcasts (1598328843619646166) -->
- <skip />
- <!-- no translation found for permdesc_readCellBroadcasts (6361972776080458979) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsRead (4756609637053353318) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsRead (5557058907906144505) -->
- <skip />
- <!-- no translation found for permlab_sendSms (7544599214260982981) -->
- <skip />
- <!-- no translation found for permdesc_sendSms (7094729298204937667) -->
- <skip />
- <!-- no translation found for permlab_readSms (8745086572213270480) -->
- <skip />
- <!-- no translation found for permdesc_readSms (2467981548684735522) -->
- <skip />
- <!-- no translation found for permdesc_readSms (5102425513647038535) -->
- <skip />
- <!-- no translation found for permdesc_readSms (3695967533457240550) -->
- <skip />
- <!-- no translation found for permlab_receiveWapPush (5991398711936590410) -->
- <skip />
- <!-- no translation found for permdesc_receiveWapPush (748232190220583385) -->
- <skip />
- <!-- no translation found for permlab_getTasks (6466095396623933906) -->
- <skip />
- <!-- no translation found for permdesc_getTasks (7454215995847658102) -->
- <skip />
- <!-- no translation found for permlab_manageProfileAndDeviceOwners (7918181259098220004) -->
- <skip />
- <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
- <skip />
- <!-- no translation found for permlab_reorderTasks (2018575526934422779) -->
- <skip />
- <!-- no translation found for permdesc_reorderTasks (7734217754877439351) -->
- <skip />
- <!-- no translation found for permlab_enableCarMode (5684504058192921098) -->
- <skip />
- <!-- no translation found for permdesc_enableCarMode (4853187425751419467) -->
- <skip />
- <!-- no translation found for permlab_killBackgroundProcesses (3914026687420177202) -->
- <skip />
- <!-- no translation found for permdesc_killBackgroundProcesses (4593353235959733119) -->
- <skip />
- <!-- no translation found for permlab_systemAlertWindow (3543347980839518613) -->
- <skip />
- <!-- no translation found for permdesc_systemAlertWindow (8584678381972820118) -->
- <skip />
- <!-- no translation found for permlab_persistentActivity (8841113627955563938) -->
- <skip />
- <!-- no translation found for permdesc_persistentActivity (8525189272329086137) -->
- <skip />
- <!-- no translation found for permdesc_persistentActivity (5086862529499103587) -->
- <skip />
- <!-- no translation found for permdesc_persistentActivity (4384760047508278272) -->
- <skip />
- <!-- no translation found for permlab_getPackageSize (7472921768357981986) -->
- <skip />
- <!-- no translation found for permdesc_getPackageSize (3921068154420738296) -->
- <skip />
- <!-- no translation found for permlab_writeSettings (2226195290955224730) -->
- <skip />
- <!-- no translation found for permdesc_writeSettings (7775723441558907181) -->
- <skip />
- <!-- no translation found for permlab_receiveBootCompleted (5312965565987800025) -->
- <skip />
- <!-- no translation found for permdesc_receiveBootCompleted (7390304664116880704) -->
- <skip />
- <!-- no translation found for permdesc_receiveBootCompleted (4525890122209673621) -->
- <skip />
- <!-- no translation found for permdesc_receiveBootCompleted (513950589102617504) -->
- <skip />
- <!-- no translation found for permlab_broadcastSticky (7919126372606881614) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSticky (7749760494399915651) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSticky (6839285697565389467) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSticky (2825803764232445091) -->
- <skip />
- <!-- no translation found for permlab_readContacts (8348481131899886131) -->
- <skip />
- <!-- no translation found for permdesc_readContacts (5294866856941149639) -->
- <skip />
- <!-- no translation found for permdesc_readContacts (1839238344654834087) -->
- <skip />
- <!-- no translation found for permdesc_readContacts (8440654152457300662) -->
- <skip />
- <!-- no translation found for permlab_writeContacts (5107492086416793544) -->
- <skip />
- <!-- no translation found for permdesc_writeContacts (897243932521953602) -->
- <skip />
- <!-- no translation found for permdesc_writeContacts (5438230957000018959) -->
- <skip />
- <!-- no translation found for permdesc_writeContacts (589869224625163558) -->
- <skip />
- <!-- no translation found for permlab_readCallLog (3478133184624102739) -->
- <skip />
- <!-- no translation found for permdesc_readCallLog (3700645184870760285) -->
- <skip />
- <!-- no translation found for permdesc_readCallLog (5611770887047387926) -->
- <skip />
- <!-- no translation found for permdesc_readCallLog (5777725796813217244) -->
- <skip />
- <!-- no translation found for permlab_writeCallLog (8552045664743499354) -->
- <skip />
- <!-- no translation found for permdesc_writeCallLog (6661806062274119245) -->
- <skip />
- <!-- no translation found for permdesc_writeCallLog (4225034892248398019) -->
- <skip />
- <!-- no translation found for permdesc_writeCallLog (683941736352787842) -->
- <skip />
- <!-- no translation found for permlab_bodySensors (4683341291818520277) -->
- <skip />
- <!-- no translation found for permdesc_bodySensors (4380015021754180431) -->
- <skip />
- <!-- no translation found for permlab_readCalendar (5972727560257612398) -->
- <skip />
- <!-- no translation found for permdesc_readCalendar (4216462049057658723) -->
- <skip />
- <!-- no translation found for permdesc_readCalendar (3191352452242394196) -->
- <skip />
- <!-- no translation found for permdesc_readCalendar (7434548682470851583) -->
- <skip />
- <!-- no translation found for permlab_writeCalendar (8438874755193825647) -->
- <skip />
- <!-- no translation found for permdesc_writeCalendar (6679035520113668528) -->
- <skip />
- <!-- no translation found for permdesc_writeCalendar (1273290605500902507) -->
- <skip />
- <!-- no translation found for permdesc_writeCalendar (2324469496327249376) -->
- <skip />
- <!-- no translation found for permlab_accessLocationExtraCommands (2836308076720553837) -->
- <skip />
- <!-- no translation found for permdesc_accessLocationExtraCommands (6078307221056649927) -->
- <skip />
- <!-- no translation found for permlab_accessFineLocation (251034415460950944) -->
- <skip />
- <!-- no translation found for permdesc_accessFineLocation (5295047563564981250) -->
- <skip />
- <!-- no translation found for permlab_accessCoarseLocation (7715277613928539434) -->
- <skip />
- <!-- no translation found for permdesc_accessCoarseLocation (2538200184373302295) -->
- <skip />
- <!-- no translation found for permlab_modifyAudioSettings (6095859937069146086) -->
- <skip />
- <!-- no translation found for permdesc_modifyAudioSettings (3522565366806248517) -->
- <skip />
- <!-- no translation found for permlab_recordAudio (3876049771427466323) -->
- <skip />
- <!-- no translation found for permdesc_recordAudio (4906839301087980680) -->
- <skip />
- <!-- no translation found for permlab_sim_communication (2935852302216852065) -->
- <skip />
- <!-- no translation found for permdesc_sim_communication (5725159654279639498) -->
- <skip />
- <!-- no translation found for permlab_camera (3616391919559751192) -->
- <skip />
- <!-- no translation found for permdesc_camera (8497216524735535009) -->
- <skip />
- <!-- no translation found for permlab_vibrate (7696427026057705834) -->
- <skip />
- <!-- no translation found for permdesc_vibrate (6284989245902300945) -->
- <skip />
- <!-- no translation found for permlab_callPhone (3925836347681847954) -->
- <skip />
- <!-- no translation found for permdesc_callPhone (3740797576113760827) -->
- <skip />
- <!-- no translation found for permlab_accessImsCallService (3574943847181793918) -->
- <skip />
- <!-- no translation found for permdesc_accessImsCallService (8992884015198298775) -->
- <skip />
- <!-- no translation found for permlab_readPhoneState (9178228524507610486) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (1639212771826125528) -->
- <skip />
- <!-- no translation found for permlab_wakeLock (1531731435011495015) -->
- <skip />
- <!-- no translation found for permlab_wakeLock (2601193288949154131) -->
- <skip />
- <!-- no translation found for permlab_wakeLock (573480187941496130) -->
- <skip />
- <!-- no translation found for permdesc_wakeLock (7311319824400447868) -->
- <skip />
- <!-- no translation found for permdesc_wakeLock (3208534859208996974) -->
- <skip />
- <!-- no translation found for permdesc_wakeLock (8559100677372928754) -->
- <skip />
- <!-- no translation found for permlab_transmitIr (7545858504238530105) -->
- <skip />
- <!-- no translation found for permdesc_transmitIr (5358308854306529170) -->
- <skip />
- <!-- no translation found for permdesc_transmitIr (3926790828514867101) -->
- <skip />
- <!-- no translation found for permdesc_transmitIr (7957763745020300725) -->
- <skip />
- <!-- no translation found for permlab_setWallpaper (6627192333373465143) -->
- <skip />
- <!-- no translation found for permdesc_setWallpaper (7373447920977624745) -->
- <skip />
- <!-- no translation found for permlab_setWallpaperHints (3278608165977736538) -->
- <skip />
- <!-- no translation found for permdesc_setWallpaperHints (8235784384223730091) -->
- <skip />
- <!-- no translation found for permlab_setTimeZone (2945079801013077340) -->
- <skip />
- <!-- no translation found for permdesc_setTimeZone (1676983712315827645) -->
- <skip />
- <!-- no translation found for permdesc_setTimeZone (888864653946175955) -->
- <skip />
- <!-- no translation found for permdesc_setTimeZone (4499943488436633398) -->
- <skip />
- <!-- no translation found for permlab_getAccounts (1086795467760122114) -->
- <skip />
- <!-- no translation found for permdesc_getAccounts (2741496534769660027) -->
- <skip />
- <!-- no translation found for permdesc_getAccounts (4190633395633907543) -->
- <skip />
- <!-- no translation found for permdesc_getAccounts (3448316822451807382) -->
- <skip />
- <!-- no translation found for permlab_accessNetworkState (4951027964348974773) -->
- <skip />
- <!-- no translation found for permdesc_accessNetworkState (8318964424675960975) -->
- <skip />
- <!-- no translation found for permlab_createNetworkSockets (7934516631384168107) -->
- <skip />
- <!-- no translation found for permdesc_createNetworkSockets (3403062187779724185) -->
- <skip />
- <!-- no translation found for permlab_changeNetworkState (958884291454327309) -->
- <skip />
- <!-- no translation found for permdesc_changeNetworkState (6789123912476416214) -->
- <skip />
- <!-- no translation found for permlab_changeTetherState (5952584964373017960) -->
- <skip />
- <!-- no translation found for permdesc_changeTetherState (1524441344412319780) -->
- <skip />
- <!-- no translation found for permlab_accessWifiState (5202012949247040011) -->
- <skip />
- <!-- no translation found for permdesc_accessWifiState (5002798077387803726) -->
- <skip />
- <!-- no translation found for permlab_changeWifiState (6550641188749128035) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiState (7137950297386127533) -->
- <skip />
- <!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiMulticastState (7969774021256336548) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiMulticastState (9031975661145014160) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiMulticastState (6851949706025349926) -->
- <skip />
- <!-- no translation found for permlab_bluetoothAdmin (6006967373935926659) -->
- <skip />
- <!-- no translation found for permdesc_bluetoothAdmin (6921177471748882137) -->
- <skip />
- <!-- no translation found for permdesc_bluetoothAdmin (3373125682645601429) -->
- <skip />
- <!-- no translation found for permdesc_bluetoothAdmin (8931682159331542137) -->
- <skip />
- <!-- no translation found for permlab_accessWimaxState (4195907010610205703) -->
- <skip />
- <!-- no translation found for permdesc_accessWimaxState (6360102877261978887) -->
- <skip />
- <!-- no translation found for permlab_changeWimaxState (340465839241528618) -->
- <skip />
- <!-- no translation found for permdesc_changeWimaxState (3156456504084201805) -->
- <skip />
- <!-- no translation found for permdesc_changeWimaxState (6022307083934827718) -->
- <skip />
- <!-- no translation found for permdesc_changeWimaxState (697025043004923798) -->
- <skip />
- <!-- no translation found for permlab_bluetooth (6127769336339276828) -->
- <skip />
- <!-- no translation found for permdesc_bluetooth (3480722181852438628) -->
- <skip />
- <!-- no translation found for permdesc_bluetooth (3974124940101104206) -->
- <skip />
- <!-- no translation found for permdesc_bluetooth (3207106324452312739) -->
- <skip />
- <!-- no translation found for permlab_nfc (4423351274757876953) -->
- <skip />
- <!-- no translation found for permdesc_nfc (7120611819401789907) -->
- <skip />
- <!-- no translation found for permlab_disableKeyguard (3598496301486439258) -->
- <skip />
- <!-- no translation found for permdesc_disableKeyguard (6034203065077122992) -->
- <skip />
- <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
- <skip />
- <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
- <skip />
- <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
- <skip />
- <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
- <skip />
- <!-- no translation found for fingerprint_acquired_partial (735082772341716043) -->
- <skip />
- <!-- no translation found for fingerprint_acquired_insufficient (4596546021310923214) -->
- <skip />
- <!-- no translation found for fingerprint_acquired_imager_dirty (1087209702421076105) -->
- <skip />
- <!-- no translation found for fingerprint_acquired_too_fast (6470642383109155969) -->
- <skip />
- <!-- no translation found for fingerprint_acquired_too_slow (59250885689661653) -->
- <skip />
+ <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
+ <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
+ <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"Poslovni"</string>
+ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupa vašim kontaktima"</string>
+ <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"pristupa lokaciji ovog uređaja"</string>
+ <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendar"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"pristupa vašem kalendaru"</string>
+ <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"šalje i pregleda SMS poruke"</string>
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"Pohrana"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"pristupa slikama, medijskim fajlovima i fajlovima na vašem uređaju"</string>
+ <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima zvuk"</string>
+ <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"slika i snima videozapise"</string>
+ <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"poziva i upravlja pozivima"</string>
+ <string name="permgrouplab_sensors" msgid="416037179223226722">"Tjelesni senzori"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pristupa podacima senzora o vašim vitalnim funkcijama"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Ponovo prikaži sadržaj prozora"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Istražite sadržaj prozora koji trenutno koristite."</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključite Istraživanje dodirom"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Stavke koje dotaknete će biti izgovorene naglas, a ekran možete istražiti pokretima"</string>
+ <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Uključite poboljšanu web pristupačnost"</string>
+ <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Možda će biti instalirana skripta kako bi sadržaj aplikacije bio dostupniji."</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Obratite pažnju na tekst koji tipkate"</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Uključuje lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
+ <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontroliranje uvećanja prikaza na ekranu"</string>
+ <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="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>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"Dozvoljava aplikaciji da postane statusna traka."</string>
+ <string name="permlab_expandStatusBar" msgid="1148198785937489264">"otvaranje/zatvaranje statusne trake"</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Dozvoljava aplikaciji otvaranje ili zatvaranje statusne trake."</string>
+ <string name="permlab_install_shortcut" msgid="4279070216371564234">"instaliranje prečica"</string>
+ <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Omogućava aplikaciji dodavanje prečice za početni ekran bez intervencije korisnika."</string>
+ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"uklanjanje prečica"</string>
+ <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Omogućava aplikaciji uklanjanje prečice početnog ekrana bez intervencije korisnika."</string>
+ <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"preusmjeravanje odlaznih poziva"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Dozvoljava aplikaciji da vidi birani broj prilikom odlaznog poziva uz opciju da poziv preusmjeri na drugi broj ili da ga skroz prekine."</string>
+ <string name="permlab_receiveSms" msgid="8673471768947895082">"primanje tekstualnih poruka (SMS)"</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"Omogućava aplikaciji primanje i obradu SMS poruka. Ovo znači da aplikacija može pratiti ili brisati poruke poslane na vaš uređaj, a da vam ih pritom ne prikazuje."</string>
+ <string name="permlab_receiveMms" msgid="1821317344668257098">"primanje tekstualnih poruka (MMS)"</string>
+ <string name="permdesc_receiveMms" msgid="533019437263212260">"Omogućava aplikaciji prijem i obradu MMS poruka. Ovo znači da aplikacija može pratiti ili brisati poruke poslane na vaš uređaj, a da vam ih pritom ne prikazuje."</string>
+ <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"čitanje poruka info servisa"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Omogućava aplikaciji čitanje poruka info servisa koje je primio vaš uređaj. Upozorenja koja emitira info servis se isporučuju na nekim lokacijama kako bi vas upozorila na vanredne situacije. Zlonamjerne aplikacije mogu ometati performanse ili rad vašeg uređaja kada primite informaciju o vanrednoj situaciji od info servisa."</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čitanje sadržaja na koje ste pretplaćeni"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Dozvoljava aplikaciji prikupljanje detalja o trenutno sinhroniziranim sadržajima."</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"slanje i pregledanje SMS poruka"</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"Omogućava aplikaciji slanje SMS poruka. Ovo može dovesti do neočekivanih troškova. Zlonamjerne aplikacije mogu trošiti vaš novac tako što će slati poruke bez vašeg znanja."</string>
+ <string name="permlab_readSms" msgid="8745086572213270480">"čitanje vaših tekstualnih poruka (SMS ili MMS)"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Omogućava aplikaciji čitanje SMS poruka koje su pohranjene na vašem telefonu ili SIM kartici. Ovo omogućava aplikaciji čitanje svih SMS poruka, bez obzira na njihov sadržaj ili povjerljivost."</string>
+ <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Dozvoljava aplikacijama čitanje SMS poruka pohranjenih na TV-u ili SIM kartici. Ovim se aplikaciji omogućava čitanje svih SMS poruka, bez obzira na njihov sadržaj ili povjerljivost."</string>
+ <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Omogućava aplikaciji čitanje SMS poruka koje su pohranjene na vašem telefonu ili SIM kartici. Ovo omogućava aplikaciji čitanje svih SMS poruka, bez obzira na njihov sadržaj ili povjerljivost."</string>
+ <string name="permlab_receiveWapPush" msgid="5991398711936590410">"primanje tekstualnih poruka (WAP)"</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Omogućava aplikaciji primanje i obradu WAP poruka. Ovo znači da aplikacija može pratiti ili brisati poruke poslane na vaš uređaj, a da vam ih pritom ne prikazuje."</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"preuzimanje informacija o pokrenutim aplikacijama"</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"Omogućava aplikaciji preuzimanje informacija o trenutnim i nedavno pokrenutim zadacima. Ovo može omogućiti aplikaciji da otkrije informacije o aplikacijama korištenim na uređaju."</string>
+ <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"upravljanje vlasnicima profila i uređaja"</string>
+ <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Omogućava aplikaciji da postavi vlasnike profila i vlasnika uređaja."</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"izmjena rasporeda pokrenutih aplikacija"</string>
+ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Omogućava aplikaciji pomjeranje zadataka u prvi plan i pozadinu. Aplikacija ovo može učiniti bez vašeg učešća."</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"omogućavanje načina rada u autu"</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Dozvoljava aplikaciji da omogući način rada u autu."</string>
+ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"zatvaranje drugih aplikacija"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Omogućava aplikaciji prekid pozadinskih procesa drugih aplikacija. Ovo može dovesti do prestanka rada drugih aplikacija."</string>
+ <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"crtanje preko drugih aplikacija"</string>
+ <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Omogućava aplikaciji crtanje po drugim aplikacijama ili dijelovima korisničkog sučelja. Ovo može ometati korištenje sučelja u bilo kojoj aplikaciji ili promijeniti ono što mislite da vidite u drugim aplikacijama."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"podešavanje aplikacije tako da je uvijek pokrenuta"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Omogućava aplikaciji da neke svoje dijelove pohrani trajno u memoriji. Ovo može ograničiti veličinu raspoložive memorije za druge aplikacije i tako usporiti tablet."</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Dozvoljava aplikaciji da jednim dijelom trajno ostaje u memoriji. Time se ostalim aplikacijama dostupna memorija može ograničiti te usporiti rad TV-a."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Omogućava aplikaciji da neke svoje dijelove pohrani trajno u memoriji. Ovo može ograničiti veličinu raspoložive memorije za druge aplikacije i tako usporiti telefon."</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"mjerenje prostora kojeg aplikacije zauzimaju u pohrani"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Dozvoljava aplikaciji preuzimanje svog kôda, podataka i veličine keš memorije"</string>
+ <string name="permlab_writeSettings" msgid="2226195290955224730">"izmjena postavki sistema"</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"Dozvoljava aplikaciji izmijenu postavki sistema. Zlonamjerne aplikacije mogu oštetiti konfiguraciju sistema."</string>
+ <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"pokrenuti pri pokretanju"</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Dozvoljava aplikaciji da se sama pokrene čim sistem završi pokretanje. Zbog toga pokretanje tableta može trajati duže i to može omogućiti aplikaciji da uspori rad čitavog tableta svojim neprekidnim radom."</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Dozvoljava aplikaciji samostalno pokretanje odmah nakon pokretanja sistema. Ovim se vrijeme pokretanja TV-a može produžiti, a aplikaciji se omogućava da uspori rad tableta tako što je stalno aktivna."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Dozvoljava aplikaciji da se sama pokrene čim sistem završi pokretanje. Zbog toga pokretanje telefona može trajati duže i to može omogućiti aplikaciji da uspori rad čitavog telefona svojim neprekidnim radom."</string>
+ <string name="permlab_broadcastSticky" msgid="7919126372606881614">"slanje ljepljivih informacija"</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Omogućava aplikaciji slanje ljepljivih informacija koje ostaju nakon prestanka emitiranja. Njihova pretjerana upotreba može usporiti ili destabilizirati rad tableta jer troši previše memorije."</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Dozvoljava aplikaciji slanje ljepljivih informacija koje ostaju nakon prestanka emitiranja. Pretjeranom upotrebom može se usporiti ili destabilizirati rad TV-a zbog korištenja previše memorije."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Omogućava aplikaciji slanje ljepljivih informacija koje ostaju nakon prestanka emitiranja. Njihova pretjerana upotreba može usporiti ili destabilizirati rad telefona jer troši previše memorije."</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"čitanje vaših kontakata"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Omogućava aplikaciji čitanje podataka o kontaktima koji su pohranjeni na vašem tabletu, uključujući učestalost vaših poziva, slanja e-pošte ili nekog drugog vida komunikacije sa određenim pojedincima. Ova dozvola omogućava aplikacijama da pohrane podatke o vašim kontaktima tako da ih zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Dozvoljava aplikaciji da čita podatke o vašim kontaktima pohranjenim na TV-u, uključujući učestalost poziva, slanja e-pošte ili komuniciranja na bilo koji način s određenim osobama. Ovom dozvolom aplikacijama se omogućava da sačuvaju podatke o kontaktima, a zlonamjerne aplikacije mogu bez vašeg znanja podijeliti ove podatke."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Omogućava aplikaciji čitanje podataka o kontaktima koji su pohranjeni na vašem telefonu, uključujući učestalost vaših poziva, slanja e-pošte ili nekog drugog vida komunikacije sa određenim pojedincima. Ova dozvola omogućava aplikacijama da pohrane podatke o vašim kontaktima tako da ih zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"izmjena podataka o kontaktima"</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Omogućava aplikaciji da izmijeni podatke o kontaktima koji su pohranjeni na vašem tabletu, uključujući učestalost vaših poziva, slanje e-pošte, ili neki drugi vid komunikacije sa određenim kontaktima. Ova dozvola omogućava aplikaciji da obriše podatke o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Dozvoljava aplikaciji izmjenu podataka o vašim kontaktima pohranjenim na TV-u, uključujući učestalost poziva, slanja e-pošte ili komuniciranja na bilo koji način s određenim kontaktima. Ovom dozvolom aplikacijama se omogućava brisanje podataka o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Omogućava aplikaciji da izmijeni podatke o kontaktima koji su pohranjeni na vašem telefonu, uključujući učestalost vaših poziva, slanje e-pošte, ili neki drugi vid komunikacije sa određenim kontaktima. Ova dozvola omogućava aplikaciji da izbriše podatke o kontaktima."</string>
+ <string name="permlab_readCallLog" msgid="3478133184624102739">"čitanje zapisnika poziva"</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Omogućava aplikaciji čitanje zapisnika poziva na vašem tabletu, uključujući podatke o dolaznim i odlaznim pozivima. Ova dozvola omogućava aplikacijama da pohrane vaš zapisnik poziva, a na taj način ga zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
+ <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Dozvoljava aplikaciji da čita evidenciju poziva s TV-a, uključujući podatke o dolaznim i odlaznim pozivima. Ovom dozvolom aplikacijama se omogućava da sačuvaju podatke o evidenciji poziva, a zlonamjerne aplikacije mogu bez vašeg znanja podijeliti ove podatke."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Omogućava aplikaciji čitanje zapisnika poziva na vašem telefonu, uključujući podatke o dolaznim i odlaznim pozivima. Ova dozvola omogućava aplikacijama da pohrane vaš zapisnik poziva, a na taj način ga zlonamjerne aplikacije mogu podijeliti bez vašeg znanja."</string>
+ <string name="permlab_writeCallLog" msgid="8552045664743499354">"pisanje zapisnika poziva"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Omogućava aplikaciji da izmijeni zapisnik poziva sa vašeg tableta, uključujući podatke o dolaznim i odlaznim pozivima. Zlonamjerne aplikacije mogu to iskoristiti za brisanje ili izmjenu vašeg zapisnika poziva."</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Dozvoljava aplikaciji izmjenu evidencije poziva s TV-a, uključujući podatke o dolaznim i odlaznim pozivima. Zlonamjerne aplikacije mogu to iskoristiti za brisanje ili izmjenu evidencije poziva."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Omogućava aplikaciji da izmijeni zapisnik poziva sa vašeg telefona, uključujući podatke o dolaznim i odlaznim pozivima. Zlonamjerne aplikacije mogu to iskoristiti za brisanje ili izmjenu vašeg zapisnika poziva."</string>
+ <string name="permlab_bodySensors" msgid="4683341291818520277">"pristup tjelesnim senzorima (poput monitora za puls)"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Dozvoljava aplikaciji pristup podacima sa senzora koji prate fizičke pokazatelje kao što je vaš puls."</string>
+ <string name="permlab_readCalendar" msgid="5972727560257612398">"čitanje događaja iz kalendara te povjerljivih informacija"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Omogućava aplikaciji čitanje svih događaja iz kalendara koji se nalaze na vašem tabletu, uključujući i one o prijateljima i saradnicima. Ovim se aplikaciji može omogućiti da podijeli ili pohrani vaše podatke iz kalendara, bez obzira na njihovu povjerljivost ili osjetljivost."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Dozvoljava aplikaciji da čita sve događaje iz kalendara koji su pohranjeni na TV-u, uključujući i one koji se odnose na prijatelje ili saradnike. Ovim se aplikaciji može omogućiti da podatke iz kalendara podijeli ili sačuva, bez obzira na njihovu povjerljivost ili osjetljivost."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Omogućava aplikaciji čitanje svih događaja iz kalendara koji se nalaze na vašem telefonu, uključujući i one o prijateljima i saradnicima. Ovim se aplikaciji može omogućiti da podijeli ili pohrani vaše podatke iz kalendara, bez obzira na njihovu povjerljivost ili osjetljivost."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"dodavanje ili izmjena kalendarskih događaja i slanje e-pošte gostima bez znanja vlasnika"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Omogućava aplikaciji da doda, ukloni i promijeni događaje koje možete izmijeniti na tabletu, uključujući i one koji se odnose na prijatelje ili saradnike. Ovim se aplikaciji može omogućiti da šalje poruke koje izgledaju kao da dolaze od vlasnika kalendara, ili da mijenja događaje bez znanja vlasnika."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Dozvoljava aplikaciji dodavanje, uklanjanje i promjenu događaja koje možete mijenjati na TV-u, uključujući i one koji se odnose na prijatelje ili saradnike. Ovim se aplikaciji može omogućiti da šalje poruke koje izgledaju kao da dolaze od vlasnika kalendara ili da bez znanja vlasnika mijenjaju događaje."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Omogućava aplikaciji da doda, ukloni i promijeni događaje koje možete izmijeniti na telefonu, uključujući i one koji se odnose na prijatelje ili saradnike. Ovim se aplikaciji može omogućiti da šalje poruke koje izgledaju kao da dolaze od vlasnika kalendara, ili da mijenja događaje bez znanja vlasnika."</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pristup dodatnim informacijama o lokaciji"</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Dozvoljava aplikaciji pristup dodatnim naredbama pružatelja lokacija. Ovim se aplikaciji može dozvoliti da ometa rad GPS-a ili drugih izvora lokacija."</string>
+ <string name="permlab_accessFineLocation" msgid="251034415460950944">"pristup preciznoj lokaciji (utvrđena preko mreže i GPS-a)"</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Omogućava aplikaciji da dobije vašu tačnu lokaciju pomoću Globalnog pozicionog sistema (GPS) ili mrežnih resursa za lociranje kao što su repetitori mobilne mreže i Wi-Fi. Ove usluge za određivanje lokacije moraju biti uključene i dostupne vašem uređaju da bi ih aplikacija koristila. Aplikacije ih mogu koristiti za određivanje vaše lokacije, a mogu uzrokovati i dodatno trošenje baterije."</string>
+ <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"pristup približnoj lokaciji (utvrđena preko mreže)"</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Omogućava aplikaciji da dobije vašu približnu lokaciju. Ta lokacija je izvedena pomoću servisa za lociranje koji koriste mrežne resurse za lociranje kao što su repetitori mobilne mreže i Wi-Fi. Ove usluge za određivanje lokacije moraju biti uključene i dostupne vašem uređaju da bi ih aplikacija koristila. Aplikacije ih mogu koristiti za određivanje vaše približne lokacije."</string>
+ <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"izmjene postavki zvuka"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Omogućava aplikaciji izmjenu općih postavki zvuka, kao što su jačina zvuka i izbor izlaznog zvučnika."</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"snimanje audiozapisa"</string>
+ <string name="permdesc_recordAudio" msgid="4906839301087980680">"Omogućava aplikaciji snimanje zvuka s mikrofona. Ova dozvola omogućava aplikaciji snimanje zvučnog zapisa u bilo kom trenutku bez vaše potvrde."</string>
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"slanje komandi SIM kartici"</string>
+ <string name="permdesc_sim_communication" msgid="5725159654279639498">"Omogućava aplikaciji slanje naredbi na SIM. Ovo je vrlo opasno."</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"snimanje slika i videozapisa"</string>
+ <string name="permdesc_camera" msgid="8497216524735535009">"Omogućava aplikaciji snimanje fotografija i videozapisa kamerom. Ova dozvola omogućava aplikaciji da bilo kada koristi kameru bez vašeg znanja."</string>
+ <string name="permlab_vibrate" msgid="7696427026057705834">"kontrola vibriranja"</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"Dozvoljava aplikaciji upravljanje vibracijom."</string>
+ <string name="permlab_callPhone" msgid="3925836347681847954">"izravno zvanje telefonskih brojeva"</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"Omogućava aplikaciji pozivanje telefonskih brojeva bez vašeg angažiranja. Ovo može uzrokovati neočekivane troškove ili pozive. Imajte na umu da ovo ne daje aplikaciji mogućnost pozivanja brojeva za hitne slučajeve. Zlonamjerne aplikacije vam mogu napraviti neočekivane troškove kroz vršenje poziva bez vašeg znanja."</string>
+ <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi IMS pozivanja"</string>
+ <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_wakeLock" product="tablet" msgid="1531731435011495015">"sprečavanje tableta da uđe u režim mirovanja"</string>
+ <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"spriječi ulazak TV-a u režim mirovanja"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečavanje telefona da uđe u režim mirovanja"</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Dozvoljava aplikaciji da spriječi tablet da ode u stanje mirovanja."</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Dozvoljava aplikaciji da spriječi ulazak TV-a u režim mirovanja."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Dozvoljava aplikaciji da spriječi telefon da ode u stanje mirovanja."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"prijenos putem infracrvenog odašiljača"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Omogućava aplikaciji korištenje infracrvenog odašiljača tableta."</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"Dozvoljava aplikaciji korištenje infracrvenog predajnika na TV-u."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Omogućava aplikaciji korištenje infracrvenog odašiljača telefona."</string>
+ <string name="permlab_setWallpaper" msgid="6627192333373465143">"postavljanje pozadinske slike"</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Dozvoljava aplikaciji postavljanje sistemske pozadine ekrana."</string>
+ <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"prilagođavanje veličine pozadine"</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Dozvoljava aplikaciji određivanje veličine sistemske pozadine ekrana."</string>
+ <string name="permlab_setTimeZone" msgid="2945079801013077340">"postavljanje vremenske zone"</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Dozvoljava aplikaciji promjenu vremenske zone tableta."</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Dozvoljava aplikaciji promjenu vremenske zone na TV-u."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Dozvoljava aplikaciji promjenu vremenske zone telefona."</string>
+ <string name="permlab_getAccounts" msgid="1086795467760122114">"pronalaženje računa na uređaju"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Omogućava aplikaciji dobijanje spiska računa koje tablet prepoznaje. Spisak može uključivati sve račune koje su kreirale instalirane aplikacije."</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Dozvoljava aplikaciji da preuzme spisak računa koje TV prepoznaje. To može obuhvatiti sve račune koji su napravljeni pomoću aplikacija koje ste instalirali."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Omogućava aplikaciji dobijanje spiska računa koje telefon prepoznaje. Spisak može uključivati sve račune koje su kreirale instalirane aplikacije."</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"prikaz mrežnih veza"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Omogućava aplikaciji pregled informacija o mrežnim vezama, npr. koje mreže postoje i koje su povezane."</string>
+ <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"ima potpuni pristup mreži"</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Omogućava aplikaciji kreiranje spojnih tačaka sa mrežom i korištenje prilagođenih mrežnih protokola. Preglednik i druge aplikacije omogućavaju slanje podataka na internet, tako da ova dozvola nije potrebna za vršenje te radnje."</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"izmjene povezivanja na mrežu"</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Dozvoljava aplikaciji izmjenu stanja mrežne povezanosti."</string>
+ <string name="permlab_changeTetherState" msgid="5952584964373017960">"izmjene podijeljenog povezivanja"</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Dozvoljava aplikaciji izmjenu stanja povezanosti na podijeljenu mrežu."</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"pregled Wi-Fi veza"</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Omogućava aplikaciji pregled informacija o Wi-Fi mrežama, npr. da li je Wi-Fi omogućen i naziv povezanih Wi-Fi uređaja."</string>
+ <string name="permlab_changeWifiState" msgid="6550641188749128035">"uspostavljanje i prekidanje Wi-Fi veze"</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Omogućava aplikaciji uspostavljanje i prekidanje veze sa Wi-Fi pristupnim tačkama, kao i promjenu konfiguracije uređaja za Wi-Fi mreže."</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"dozvoljava prijem paketa kroz Wi-Fi Multicast"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Omogućava aplikaciji prijem paketa poslanih svim uređajima na Wi-Fi mreži pomoću multicast tehnologije, a ne samo na vaš tablet. Troši više energije nego rad van multicast načina rada."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Omogućava aplikaciji prijem paketa poslanih svim uređajima na Wi-Fi mreži pomoću multicast tehnologije, a ne samo na vaš TV. Troši više energije nego rad van multicast načina rada."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Omogućava aplikaciji prijem paketa poslanih svim uređajima na Wi-Fi mreži pomoću multicast tehnologije, a ne samo na vaš telefon. Troši više energije nego rad van multicast načina rada."</string>
+ <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"pristup Bluetooth postavkama"</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Dozvoljava aplikaciji konfiguriranje lokalnog Bluetooth tableta te otkrivanje udaljenih uređaja i sparivanje s njima."</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Dozvoljava aplikaciji konfiguriranje lokalnog Bluetooth TV-a te otkrivanje i povezivanje s udaljenim uređajima."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Dozvoljava aplikaciji konfiguriranje lokalnog Bluetooth telefona te otkrivanje udaljenih uređaja i sparivanje s njima."</string>
+ <string name="permlab_accessWimaxState" msgid="4195907010610205703">"uspostavljanje i prekidanje veze sa WiMAX mrežama"</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Dozvoljava aplikaciji da utvrdi da li je WiMAX omogućen i informacije o bilo kojoj WiMAX mreži koja je povezana."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"izmjene stanja WiMAX signala"</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Omogućava aplikaciji uspostavljanje i prekidanje veze tableta sa WiMAX mrežama."</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Dozvoljava aplikaciji da TV poveže na WiMAX mreže ili da ga isključi s njih."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Omogućava aplikaciji uspostavljanje i prekidanje veze telefona sa WiMAX mrežama."</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"uparivanje sa Bluetooth uređajima"</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Omogućava aplikaciji prikaz konfiguracije za Bluetooth na tabletu, kao i uspostavljanje i prihvatanje veza sa uparenim uređajima."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Dozvoljava aplikaciji prikaz konfiguracije Bluetooth veze na TV-u te uspostavljanje i prihvatanje veza s ravnopravnim uređajima."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Omogućava aplikaciji prikaz konfiguracije za Bluetooth na telefonu, kao i uspostavljanje i prihvatanje veza sa uparenim uređajima."</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"upravljanje NFC-om"</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Dozvoljava aplikaciji komuniciranje sa NFC (komunikacija bliskog polja) oznakama, karticama i čitačima."</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivacija zaključavanja ekrana"</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Omogućava aplikaciji deaktivaciju zaključane tastature i svih povezanih zaštita. Naprimjer, telefon deaktivira zaključavanje tastature kod dolaznog telefonskog poziva, a zatim ponovo aktivira zaključavanje tastature kada je poziv završen."</string>
+ <string name="permlab_manageFingerprint" msgid="5640858826254575638">"upravljanje hardverom za otiske prstiju"</string>
+ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Omogućava aplikaciji da koristi metode za dodavanje i brisanje šablona otisaka prstiju za upotrebu."</string>
+ <string name="permlab_useFingerprint" msgid="3150478619915124905">"korištenje hardvera za otiske prstiju"</string>
+ <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Omogućava aplikaciji da za provjeru vjerodostojnosti koristi hardver za otiske prstiju"</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomičan otisak prsta. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspjela obrada otiska prsta. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prst je uklonjen prebrzo. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Prst je uklonjen presporo. Pokušajte ponovo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <!-- no translation found for fingerprint_error_hw_not_available (7955921658939936596) -->
- <skip />
- <!-- no translation found for fingerprint_error_no_space (1055819001126053318) -->
- <skip />
- <!-- no translation found for fingerprint_error_timeout (3927186043737732875) -->
- <skip />
- <!-- no translation found for fingerprint_error_canceled (4402024612660774395) -->
- <skip />
- <!-- no translation found for fingerprint_error_lockout (5536934748136933450) -->
- <skip />
- <!-- no translation found for fingerprint_error_unable_to_process (6107816084103552441) -->
- <skip />
- <!-- no translation found for fingerprint_name_template (5870957565512716938) -->
- <skip />
+ <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
+ <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta se ne može sačuvati. Uklonite postojeći otisak prsta."</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Pokušajte ponovo."</string>
+ <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
+ <string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
- <!-- no translation found for fingerprint_icon_content_description (2340202869968465936) -->
- <skip />
- <!-- no translation found for permlab_readSyncSettings (6201810008230503052) -->
- <skip />
- <!-- no translation found for permdesc_readSyncSettings (2706745674569678644) -->
- <skip />
- <!-- no translation found for permlab_writeSyncSettings (5408694875793945314) -->
- <skip />
- <!-- no translation found for permdesc_writeSyncSettings (8956262591306369868) -->
- <skip />
- <!-- no translation found for permlab_readSyncStats (7396577451360202448) -->
- <skip />
- <!-- no translation found for permdesc_readSyncStats (1510143761757606156) -->
- <skip />
- <!-- no translation found for permlab_sdcardRead (367275095159405468) -->
- <skip />
- <!-- no translation found for permlab_sdcardRead (2188156462934977940) -->
- <skip />
- <!-- no translation found for permdesc_sdcardRead (3446988712598386079) -->
- <skip />
- <!-- no translation found for permdesc_sdcardRead (2607362473654975411) -->
- <skip />
- <!-- no translation found for permlab_sdcardWrite (8485979062254666748) -->
- <skip />
- <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
- <skip />
- <!-- no translation found for permdesc_sdcardWrite (6175406299445710888) -->
- <skip />
- <!-- no translation found for permdesc_sdcardWrite (4337417790936632090) -->
- <skip />
- <!-- no translation found for permlab_use_sip (2052499390128979920) -->
- <skip />
- <!-- no translation found for permdesc_use_sip (2297804849860225257) -->
- <skip />
- <!-- no translation found for permlab_register_sim_subscription (3166535485877549177) -->
- <skip />
- <!-- no translation found for permdesc_register_sim_subscription (2138909035926222911) -->
- <skip />
- <!-- no translation found for permlab_register_call_provider (108102120289029841) -->
- <skip />
- <!-- no translation found for permdesc_register_call_provider (7034310263521081388) -->
- <skip />
- <!-- no translation found for permlab_connection_manager (1116193254522105375) -->
- <skip />
- <!-- no translation found for permdesc_connection_manager (5925480810356483565) -->
- <skip />
- <!-- no translation found for permlab_bind_incall_service (6773648341975287125) -->
- <skip />
- <!-- no translation found for permdesc_bind_incall_service (8343471381323215005) -->
- <skip />
- <!-- no translation found for permlab_bind_connection_service (3557341439297014940) -->
- <skip />
- <!-- no translation found for permdesc_bind_connection_service (4008754499822478114) -->
- <skip />
- <!-- no translation found for permlab_control_incall_experience (9061024437607777619) -->
- <skip />
- <!-- no translation found for permdesc_control_incall_experience (915159066039828124) -->
- <skip />
- <!-- no translation found for permlab_readNetworkUsageHistory (7862593283611493232) -->
- <skip />
- <!-- no translation found for permdesc_readNetworkUsageHistory (7689060749819126472) -->
- <skip />
- <!-- no translation found for permlab_manageNetworkPolicy (2562053592339859990) -->
- <skip />
- <!-- no translation found for permdesc_manageNetworkPolicy (7537586771559370668) -->
- <skip />
- <!-- no translation found for permlab_modifyNetworkAccounting (5088217309088729650) -->
- <skip />
- <!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) -->
- <skip />
- <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
- <skip />
- <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
- <skip />
- <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
- <skip />
- <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
- <skip />
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
- <!-- no translation found for permlab_bindDreamService (4153646965978563462) -->
- <skip />
- <!-- no translation found for permdesc_bindDreamService (7325825272223347863) -->
- <skip />
- <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
- <skip />
- <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
- <skip />
- <!-- no translation found for permlab_accessNetworkConditions (8206077447838909516) -->
- <skip />
- <!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
- <skip />
- <!-- no translation found for permlab_setInputCalibration (4902620118878467615) -->
- <skip />
- <!-- no translation found for permdesc_setInputCalibration (4527511047549456929) -->
- <skip />
- <!-- no translation found for permlab_accessDrmCertificates (7436886640723203615) -->
- <skip />
- <!-- no translation found for permdesc_accessDrmCertificates (8073288354426159089) -->
- <skip />
- <!-- no translation found for permlab_handoverStatus (7820353257219300883) -->
- <skip />
- <!-- no translation found for permdesc_handoverStatus (4788144087245714948) -->
- <skip />
- <!-- no translation found for permlab_removeDrmCertificates (7044888287209892751) -->
- <skip />
- <!-- no translation found for permdesc_removeDrmCertificates (7272999075113400993) -->
- <skip />
- <!-- no translation found for permlab_bindCarrierMessagingService (1490229371796969158) -->
- <skip />
- <!-- no translation found for permdesc_bindCarrierMessagingService (2762882888502113944) -->
- <skip />
- <!-- no translation found for permlab_bindCarrierServices (3233108656245526783) -->
- <skip />
- <!-- no translation found for permdesc_bindCarrierServices (1391552602551084192) -->
- <skip />
- <!-- no translation found for permlab_access_notification_policy (4247510821662059671) -->
- <skip />
- <!-- no translation found for permdesc_access_notification_policy (3296832375218749580) -->
- <skip />
- <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
- <skip />
- <!-- no translation found for policydesc_limitPassword (2502021457917874968) -->
- <skip />
- <!-- no translation found for policylab_watchLogin (914130646942199503) -->
- <skip />
- <!-- no translation found for policydesc_watchLogin (3215729294215070072) -->
- <skip />
- <!-- no translation found for policydesc_watchLogin (2707817988309890256) -->
- <skip />
- <!-- no translation found for policydesc_watchLogin (5712323091846761073) -->
- <skip />
- <!-- no translation found for policydesc_watchLogin_secondaryUser (4280246270601044505) -->
- <skip />
- <!-- no translation found for policydesc_watchLogin_secondaryUser (3484832653564483250) -->
- <skip />
- <!-- no translation found for policydesc_watchLogin_secondaryUser (2185480427217127147) -->
- <skip />
- <!-- no translation found for policylab_resetPassword (4934707632423915395) -->
- <skip />
- <!-- no translation found for policydesc_resetPassword (1278323891710619128) -->
- <skip />
- <!-- no translation found for policylab_forceLock (2274085384704248431) -->
- <skip />
- <!-- no translation found for policydesc_forceLock (1141797588403827138) -->
- <skip />
- <!-- no translation found for policylab_wipeData (3910545446758639713) -->
- <skip />
- <!-- no translation found for policydesc_wipeData (4306184096067756876) -->
- <skip />
- <!-- no translation found for policydesc_wipeData (5816221315214527028) -->
- <skip />
- <!-- no translation found for policydesc_wipeData (5096895604574188391) -->
- <skip />
- <!-- no translation found for policylab_wipeData_secondaryUser (8362863289455531813) -->
- <skip />
- <!-- no translation found for policydesc_wipeData_secondaryUser (6336255514635308054) -->
- <skip />
- <!-- no translation found for policydesc_wipeData_secondaryUser (2086473496848351810) -->
- <skip />
- <!-- no translation found for policydesc_wipeData_secondaryUser (6787904546711590238) -->
- <skip />
- <!-- no translation found for policylab_setGlobalProxy (2784828293747791446) -->
- <skip />
- <!-- no translation found for policydesc_setGlobalProxy (8459859731153370499) -->
- <skip />
- <!-- no translation found for policylab_expirePassword (5610055012328825874) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (5367525762204416046) -->
- <skip />
- <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
- <skip />
- <!-- no translation found for policydesc_encryptedStorage (2637732115325316992) -->
- <skip />
- <!-- no translation found for policylab_disableCamera (6395301023152297826) -->
- <skip />
- <!-- no translation found for policydesc_disableCamera (2306349042834754597) -->
- <skip />
- <!-- no translation found for policylab_disableKeyguardFeatures (8552277871075367771) -->
- <skip />
- <!-- no translation found for policydesc_disableKeyguardFeatures (2044755691354158439) -->
- <skip />
- <!-- no translation found for phoneTypes:0 (8901098336658710359) -->
- <!-- no translation found for phoneTypes:1 (869923650527136615) -->
- <!-- no translation found for phoneTypes:2 (7897544654242874543) -->
- <!-- no translation found for phoneTypes:3 (1103601433382158155) -->
- <!-- no translation found for phoneTypes:4 (1735177144948329370) -->
- <!-- no translation found for phoneTypes:5 (603878674477207394) -->
- <!-- no translation found for phoneTypes:6 (1650824275177931637) -->
- <!-- no translation found for phoneTypes:7 (9192514806975898961) -->
- <!-- no translation found for emailAddressTypes:0 (8073994352956129127) -->
- <!-- no translation found for emailAddressTypes:1 (7084237356602625604) -->
- <!-- no translation found for emailAddressTypes:2 (1112044410659011023) -->
- <!-- no translation found for emailAddressTypes:3 (2374913952870110618) -->
- <!-- no translation found for postalAddressTypes:0 (6880257626740047286) -->
- <!-- no translation found for postalAddressTypes:1 (5629153956045109251) -->
- <!-- no translation found for postalAddressTypes:2 (4966604264500343469) -->
- <!-- no translation found for postalAddressTypes:3 (4932682847595299369) -->
- <!-- no translation found for imAddressTypes:0 (1738585194601476694) -->
- <!-- no translation found for imAddressTypes:1 (1359644565647383708) -->
- <!-- no translation found for imAddressTypes:2 (7868549401053615677) -->
- <!-- no translation found for imAddressTypes:3 (3145118944639869809) -->
- <!-- no translation found for organizationTypes:0 (7546335612189115615) -->
- <!-- no translation found for organizationTypes:1 (4378074129049520373) -->
- <!-- no translation found for organizationTypes:2 (3455047468583965104) -->
- <!-- no translation found for imProtocols:0 (8595261363518459565) -->
- <!-- no translation found for imProtocols:1 (7390473628275490700) -->
- <!-- no translation found for imProtocols:2 (7882877134931458217) -->
- <!-- no translation found for imProtocols:3 (5035376313200585242) -->
- <!-- no translation found for imProtocols:4 (7532363178459444943) -->
- <!-- no translation found for imProtocols:5 (3713441034299660749) -->
- <!-- no translation found for imProtocols:6 (2506857312718630823) -->
- <!-- no translation found for imProtocols:7 (1648797903785279353) -->
- <!-- no translation found for phoneTypeCustom (1644738059053355820) -->
- <skip />
- <!-- no translation found for phoneTypeHome (2570923463033985887) -->
- <skip />
- <!-- no translation found for phoneTypeMobile (6501463557754751037) -->
- <skip />
- <!-- no translation found for phoneTypeWork (8863939667059911633) -->
- <skip />
- <!-- no translation found for phoneTypeFaxWork (3517792160008890912) -->
- <skip />
- <!-- no translation found for phoneTypeFaxHome (2067265972322971467) -->
- <skip />
- <!-- no translation found for phoneTypePager (7582359955394921732) -->
- <skip />
- <!-- no translation found for phoneTypeOther (1544425847868765990) -->
- <skip />
- <!-- no translation found for phoneTypeCallback (2712175203065678206) -->
- <skip />
- <!-- no translation found for phoneTypeCar (8738360689616716982) -->
- <skip />
- <!-- no translation found for phoneTypeCompanyMain (540434356461478916) -->
- <skip />
- <!-- no translation found for phoneTypeIsdn (8022453193171370337) -->
- <skip />
- <!-- no translation found for phoneTypeMain (6766137010628326916) -->
- <skip />
- <!-- no translation found for phoneTypeOtherFax (8587657145072446565) -->
- <skip />
- <!-- no translation found for phoneTypeRadio (4093738079908667513) -->
- <skip />
- <!-- no translation found for phoneTypeTelex (3367879952476250512) -->
- <skip />
- <!-- no translation found for phoneTypeTtyTdd (8606514378585000044) -->
- <skip />
- <!-- no translation found for phoneTypeWorkMobile (1311426989184065709) -->
- <skip />
- <!-- no translation found for phoneTypeWorkPager (649938731231157056) -->
- <skip />
- <!-- no translation found for phoneTypeAssistant (5596772636128562884) -->
- <skip />
- <!-- no translation found for phoneTypeMms (7254492275502768992) -->
- <skip />
- <!-- no translation found for eventTypeCustom (7837586198458073404) -->
- <skip />
- <!-- no translation found for eventTypeBirthday (2813379844211390740) -->
- <skip />
- <!-- no translation found for eventTypeAnniversary (3876779744518284000) -->
- <skip />
- <!-- no translation found for eventTypeOther (7388178939010143077) -->
- <skip />
- <!-- no translation found for emailTypeCustom (8525960257804213846) -->
- <skip />
- <!-- no translation found for emailTypeHome (449227236140433919) -->
- <skip />
- <!-- no translation found for emailTypeWork (3548058059601149973) -->
- <skip />
- <!-- no translation found for emailTypeOther (2923008695272639549) -->
- <skip />
- <!-- no translation found for emailTypeMobile (119919005321166205) -->
- <skip />
- <!-- no translation found for postalTypeCustom (8903206903060479902) -->
- <skip />
- <!-- no translation found for postalTypeHome (8165756977184483097) -->
- <skip />
- <!-- no translation found for postalTypeWork (5268172772387694495) -->
- <skip />
- <!-- no translation found for postalTypeOther (2726111966623584341) -->
- <skip />
- <!-- no translation found for imTypeCustom (2074028755527826046) -->
- <skip />
- <!-- no translation found for imTypeHome (6241181032954263892) -->
- <skip />
- <!-- no translation found for imTypeWork (1371489290242433090) -->
- <skip />
- <!-- no translation found for imTypeOther (5377007495735915478) -->
- <skip />
- <!-- no translation found for imProtocolCustom (6919453836618749992) -->
- <skip />
- <!-- no translation found for imProtocolAim (7050360612368383417) -->
- <skip />
- <!-- no translation found for imProtocolMsn (144556545420769442) -->
- <skip />
- <!-- no translation found for imProtocolYahoo (8271439408469021273) -->
- <skip />
- <!-- no translation found for imProtocolSkype (9019296744622832951) -->
- <skip />
- <!-- no translation found for imProtocolQq (8887484379494111884) -->
- <skip />
- <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
- <skip />
- <!-- no translation found for imProtocolIcq (1574870433606517315) -->
- <skip />
- <!-- no translation found for imProtocolJabber (2279917630875771722) -->
- <skip />
- <!-- no translation found for imProtocolNetMeeting (8287625655986827971) -->
- <skip />
- <!-- no translation found for orgTypeWork (29268870505363872) -->
- <skip />
- <!-- no translation found for orgTypeOther (3951781131570124082) -->
- <skip />
- <!-- no translation found for orgTypeCustom (225523415372088322) -->
- <skip />
- <!-- no translation found for relationTypeCustom (3542403679827297300) -->
- <skip />
- <!-- no translation found for relationTypeAssistant (6274334825195379076) -->
- <skip />
- <!-- no translation found for relationTypeBrother (8757913506784067713) -->
- <skip />
- <!-- no translation found for relationTypeChild (1890746277276881626) -->
- <skip />
- <!-- no translation found for relationTypeDomesticPartner (6904807112121122133) -->
- <skip />
- <!-- no translation found for relationTypeFather (5228034687082050725) -->
- <skip />
- <!-- no translation found for relationTypeFriend (7313106762483391262) -->
- <skip />
- <!-- no translation found for relationTypeManager (6365677861610137895) -->
- <skip />
- <!-- no translation found for relationTypeMother (4578571352962758304) -->
- <skip />
- <!-- no translation found for relationTypeParent (4755635567562925226) -->
- <skip />
- <!-- no translation found for relationTypePartner (7266490285120262781) -->
- <skip />
- <!-- no translation found for relationTypeReferredBy (101573059844135524) -->
- <skip />
- <!-- no translation found for relationTypeRelative (1799819930085610271) -->
- <skip />
- <!-- no translation found for relationTypeSister (1735983554479076481) -->
- <skip />
- <!-- no translation found for relationTypeSpouse (394136939428698117) -->
- <skip />
- <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
- <skip />
- <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
- <skip />
- <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
- <skip />
- <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
- <skip />
- <!-- no translation found for quick_contacts_not_available (746098007828579688) -->
- <skip />
- <!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
- <skip />
- <!-- no translation found for keyguard_password_enter_puk_code (4800725266925845333) -->
- <skip />
- <!-- no translation found for keyguard_password_enter_puk_prompt (1341112146710087048) -->
- <skip />
- <!-- no translation found for keyguard_password_enter_pin_prompt (8027680321614196258) -->
- <skip />
- <!-- no translation found for keyguard_password_entry_touch_hint (7858547464982981384) -->
- <skip />
- <!-- no translation found for keyguard_password_enter_password_code (1054721668279049780) -->
- <skip />
- <!-- no translation found for keyguard_password_enter_pin_password_code (6391755146112503443) -->
- <skip />
- <!-- no translation found for keyguard_password_wrong_pin_code (2422225591006134936) -->
- <skip />
- <!-- no translation found for keyguard_label_text (861796461028298424) -->
- <skip />
- <!-- no translation found for emergency_call_dialog_number_for_display (696192103195090970) -->
- <skip />
- <!-- no translation found for lockscreen_carrier_default (6169005837238288522) -->
- <skip />
- <!-- no translation found for lockscreen_screen_locked (7288443074806832904) -->
- <skip />
- <!-- no translation found for lockscreen_instructions_when_pattern_enabled (46154051614126049) -->
- <skip />
- <!-- no translation found for lockscreen_instructions_when_pattern_disabled (686260028797158364) -->
- <skip />
- <!-- no translation found for lockscreen_pattern_instructions (7478703254964810302) -->
- <skip />
- <!-- no translation found for lockscreen_emergency_call (5298642613417801888) -->
- <skip />
- <!-- no translation found for lockscreen_return_to_call (5244259785500040021) -->
- <skip />
- <!-- no translation found for lockscreen_pattern_correct (9039008650362261237) -->
- <skip />
- <!-- no translation found for lockscreen_pattern_wrong (4317955014948108794) -->
- <skip />
- <!-- no translation found for lockscreen_password_wrong (5737815393253165301) -->
- <skip />
- <!-- no translation found for faceunlock_multiple_failures (754137583022792429) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_message_short (5099439277819215399) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_message (151659196095791474) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_message (1943633865476989599) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_message (2186920585695169078) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_instructions (5372787138023272615) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_instructions_long (3526573099019319472) -->
- <skip />
- <!-- no translation found for lockscreen_permanent_disabled_sim_message_short (5096149665138916184) -->
- <skip />
- <!-- no translation found for lockscreen_permanent_disabled_sim_instructions (910904643433151371) -->
- <skip />
- <!-- no translation found for lockscreen_transport_prev_description (6300840251218161534) -->
- <skip />
- <!-- no translation found for lockscreen_transport_next_description (573285210424377338) -->
- <skip />
- <!-- no translation found for lockscreen_transport_pause_description (3980308465056173363) -->
- <skip />
- <!-- no translation found for lockscreen_transport_play_description (1901258823643886401) -->
- <skip />
- <!-- no translation found for lockscreen_transport_stop_description (5907083260651210034) -->
- <skip />
- <!-- no translation found for lockscreen_transport_rew_description (6944412838651990410) -->
- <skip />
- <!-- no translation found for lockscreen_transport_ffw_description (42987149870928985) -->
- <skip />
- <!-- no translation found for emergency_calls_only (6733978304386365407) -->
- <!-- no translation found for emergency_calls_only (2485604591272668370) -->
- <skip />
- <!-- no translation found for lockscreen_network_locked_message (143389224986028501) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_message (7441797339976230) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_instructions (8127916255245181063) -->
- <skip />
- <!-- no translation found for lockscreen_sim_locked_message (8066660129206001039) -->
- <skip />
- <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (595323214052881264) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6481623830344107222) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_password_attempts_dialog_message (2725973286239344555) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6216672706545696955) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (9191611984625460820) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (5316664559603394684) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (2590227559763762751) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_at_wipe (6128106399745755604) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_at_wipe (950408382418270260) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_at_wipe (8603565142156826565) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_now_wiping (280873516493934365) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_now_wiping (3195755534096192191) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_now_wiping (3025504721764922246) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (6251480343394389665) -->
- <skip />
- <!-- no translation found for lockscreen_forgot_pattern_button_text (2626999449610695930) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_forgot_pattern (2588521501166032747) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_too_many_attempts (2751368605287288808) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_instructions (3931816256100707784) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_username_hint (8846881424106484447) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_password_hint (5958028383954738528) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_submit_button (7130893694795786300) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_invalid_input (1364051473347485908) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_account_recovery_hint (1696924763690379073) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_checking_password (7114627351286933867) -->
- <skip />
- <!-- no translation found for lockscreen_unlock_label (737440483220667054) -->
- <skip />
- <!-- no translation found for lockscreen_sound_on_label (9068877576513425970) -->
- <skip />
- <!-- no translation found for lockscreen_sound_off_label (996822825154319026) -->
- <skip />
- <!-- no translation found for lockscreen_access_pattern_start (3941045502933142847) -->
- <skip />
- <!-- no translation found for lockscreen_access_pattern_cleared (5583479721001639579) -->
- <skip />
- <!-- no translation found for lockscreen_access_pattern_cell_added (6756031208359292487) -->
- <skip />
- <!-- no translation found for lockscreen_access_pattern_cell_added_verbose (7264580781744026939) -->
- <skip />
- <!-- no translation found for lockscreen_access_pattern_detected (4988730895554057058) -->
- <skip />
- <!-- no translation found for lockscreen_access_pattern_area (400813207572953209) -->
- <!-- no translation found for lockscreen_access_pattern_area () -->
- <skip />
- <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_add_widget (8273277058724924654) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_widget_empty_slot (1281505703307930757) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_unlock_area_expanded (2278106022311170299) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_unlock_area_collapsed (6366992066936076396) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_widget (6527131039741808240) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_camera (8904231194181114603) -->
- <skip />
- <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_widget_reorder_start (8736853615588828197) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_widget_reorder_end (7170190950870468320) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_widget_deleted (4426204263929224434) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_expand_lock_area (519859720934178024) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_slide_unlock (2959928478764697254) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_pattern_unlock (1490840706075246612) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_face_unlock (4817282543351718535) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_pin_unlock (2469687111784035046) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_password_unlock (7675777623912155089) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_pattern_area (7679891324509597904) -->
- <skip />
- <!-- no translation found for keyguard_accessibility_slide_area (6736064494019979544) -->
- <skip />
- <!-- no translation found for password_keyboard_label_symbol_key (992280756256536042) -->
- <skip />
- <!-- no translation found for password_keyboard_label_alpha_key (8001096175167485649) -->
- <skip />
- <!-- no translation found for password_keyboard_label_alt_key (1284820942620288678) -->
- <skip />
- <!-- no translation found for granularity_label_character (7336470535385009523) -->
- <skip />
- <!-- no translation found for granularity_label_word (7075570328374918660) -->
- <skip />
- <!-- no translation found for granularity_label_link (5815508880782488267) -->
- <skip />
- <!-- no translation found for granularity_label_line (5764267235026120888) -->
- <skip />
- <!-- no translation found for factorytest_failed (5410270329114212041) -->
- <skip />
- <!-- no translation found for factorytest_not_system (4435201656767276723) -->
- <skip />
- <!-- no translation found for factorytest_no_action (872991874799998561) -->
- <skip />
- <!-- no translation found for factorytest_reboot (6320168203050791643) -->
- <skip />
- <!-- no translation found for js_dialog_title (1987483977834603872) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
- <skip />
- <!-- no translation found for save_password_label (6860261758665825069) -->
- <skip />
- <!-- no translation found for double_tap_toast (4595046515400268881) -->
- <skip />
- <!-- no translation found for autofill_this_form (4616758841157816676) -->
- <skip />
- <!-- no translation found for setup_autofill (7103495070180590814) -->
- <skip />
- <!-- no translation found for autofill_address_name_separator (6350145154779706772) -->
- <skip />
- <!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
- <skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
- <!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
- <skip />
- <!-- no translation found for autofill_province (2231806553863422300) -->
- <skip />
- <!-- no translation found for autofill_postal_code (4696430407689377108) -->
- <skip />
- <!-- no translation found for autofill_state (6988894195520044613) -->
- <skip />
- <!-- no translation found for autofill_zip_code (8697544592627322946) -->
- <skip />
- <!-- no translation found for autofill_county (237073771020362891) -->
- <skip />
- <!-- no translation found for autofill_island (4020100875984667025) -->
- <skip />
- <!-- no translation found for autofill_district (8400735073392267672) -->
- <skip />
- <!-- no translation found for autofill_department (5343279462564453309) -->
- <skip />
- <!-- no translation found for autofill_prefecture (2028499485065800419) -->
- <skip />
- <!-- no translation found for autofill_parish (8202206105468820057) -->
- <skip />
- <!-- no translation found for autofill_area (3547409050889952423) -->
- <skip />
- <!-- no translation found for autofill_emirate (2893880978835698818) -->
- <skip />
- <!-- no translation found for permlab_readHistoryBookmarks (3775265775405106983) -->
- <skip />
- <!-- no translation found for permdesc_readHistoryBookmarks (8462378226600439658) -->
- <skip />
- <!-- no translation found for permlab_writeHistoryBookmarks (3714785165273314490) -->
- <skip />
- <!-- no translation found for permdesc_writeHistoryBookmarks (6825527469145760922) -->
- <skip />
- <!-- no translation found for permdesc_writeHistoryBookmarks (7007393823197766548) -->
- <skip />
- <!-- no translation found for permdesc_writeHistoryBookmarks (8497389531014185509) -->
- <skip />
- <!-- no translation found for permlab_setAlarm (1379294556362091814) -->
- <skip />
- <!-- no translation found for permdesc_setAlarm (316392039157473848) -->
- <skip />
- <!-- no translation found for permlab_addVoicemail (5525660026090959044) -->
- <skip />
- <!-- no translation found for permdesc_addVoicemail (6604508651428252437) -->
- <skip />
- <!-- no translation found for permlab_writeGeolocationPermissions (5962224158955273932) -->
- <skip />
- <!-- no translation found for permdesc_writeGeolocationPermissions (1083743234522638747) -->
- <skip />
- <!-- no translation found for save_password_message (767344687139195790) -->
- <skip />
- <!-- no translation found for save_password_notnow (6389675316706699758) -->
- <skip />
- <!-- no translation found for save_password_remember (6491879678996749466) -->
- <skip />
- <!-- no translation found for save_password_never (8274330296785855105) -->
- <skip />
- <!-- no translation found for open_permission_deny (7374036708316629800) -->
- <skip />
- <!-- no translation found for text_copied (4985729524670131385) -->
- <skip />
- <!-- no translation found for more_item_label (4650918923083320495) -->
- <skip />
- <!-- no translation found for prepend_shortcut_label (2572214461676015642) -->
- <skip />
- <!-- no translation found for menu_space_shortcut_label (2410328639272162537) -->
- <skip />
- <!-- no translation found for menu_enter_shortcut_label (2743362785111309668) -->
- <skip />
- <!-- no translation found for menu_delete_shortcut_label (3658178007202748164) -->
- <skip />
- <!-- no translation found for search_go (8298016669822141719) -->
- <skip />
- <!-- no translation found for search_hint (1733947260773056054) -->
- <skip />
- <!-- no translation found for searchview_description_search (6749826639098512120) -->
- <skip />
- <!-- no translation found for searchview_description_query (5911778593125355124) -->
- <skip />
- <!-- no translation found for searchview_description_clear (1330281990951833033) -->
- <skip />
- <!-- no translation found for searchview_description_submit (2688450133297983542) -->
- <skip />
- <!-- no translation found for searchview_description_voice (2453203695674994440) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
- <skip />
- <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
- <skip />
- <!-- no translation found for oneMonthDurationPast (7396384508953779925) -->
- <skip />
- <!-- no translation found for beforeOneMonthDurationPast (909134546836499826) -->
- <skip />
- <!-- no translation found for last_num_days (5104533550723932025) -->
- <!-- no translation found for last_month (3959346739979055432) -->
- <skip />
- <!-- no translation found for older (5211975022815554840) -->
- <skip />
- <!-- no translation found for preposition_for_date (9093949757757445117) -->
- <skip />
- <!-- no translation found for preposition_for_time (5506831244263083793) -->
- <skip />
- <!-- no translation found for preposition_for_year (5040395640711867177) -->
- <skip />
- <!-- no translation found for day (8144195776058119424) -->
- <skip />
- <!-- no translation found for days (4774547661021344602) -->
- <skip />
- <!-- no translation found for hour (2126771916426189481) -->
- <skip />
- <!-- no translation found for hours (894424005266852993) -->
- <skip />
- <!-- no translation found for minute (9148878657703769868) -->
- <skip />
- <!-- no translation found for minutes (5646001005827034509) -->
- <skip />
- <!-- no translation found for second (3184235808021478) -->
- <skip />
- <!-- no translation found for seconds (3161515347216589235) -->
- <skip />
- <!-- no translation found for week (5617961537173061583) -->
- <skip />
- <!-- no translation found for weeks (6509623834583944518) -->
- <skip />
- <!-- no translation found for year (4001118221013892076) -->
- <skip />
- <!-- no translation found for years (6881577717993213522) -->
- <skip />
- <!-- no translation found for duration_seconds (4527986939729687805) -->
- <!-- no translation found for duration_minutes (643786953939956125) -->
- <!-- no translation found for duration_hours (6826233369186668274) -->
- <!-- no translation found for VideoView_error_title (3534509135438353077) -->
- <skip />
- <!-- no translation found for VideoView_error_text_invalid_progressive_playback (3186670335938670444) -->
- <skip />
- <!-- no translation found for VideoView_error_text_unknown (3450439155187810085) -->
- <skip />
- <!-- no translation found for VideoView_error_button (2822238215100679592) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
- <!-- no translation found for noon (7245353528818587908) -->
- <skip />
- <!-- no translation found for Noon (3342127745230013127) -->
- <skip />
- <!-- no translation found for midnight (7166259508850457595) -->
- <skip />
- <!-- no translation found for Midnight (5630806906897892201) -->
- <skip />
- <!-- no translation found for elapsed_time_short_format_mm_ss (4431555943828711473) -->
- <skip />
- <!-- no translation found for elapsed_time_short_format_h_mm_ss (1846071997616654124) -->
- <skip />
- <!-- no translation found for selectAll (6876518925844129331) -->
- <skip />
- <!-- no translation found for cut (3092569408438626261) -->
- <skip />
- <!-- no translation found for copy (2681946229533511987) -->
- <skip />
- <!-- no translation found for paste (5629880836805036433) -->
- <skip />
- <!-- no translation found for paste_as_plain_text (5427792741908010675) -->
- <skip />
- <!-- no translation found for replace (5781686059063148930) -->
- <skip />
- <!-- no translation found for delete (6098684844021697789) -->
- <skip />
- <!-- no translation found for copyUrl (2538211579596067402) -->
- <skip />
- <!-- no translation found for selectTextMode (1018691815143165326) -->
- <skip />
- <!-- no translation found for undo (7905788502491742328) -->
- <skip />
- <!-- no translation found for redo (7759464876566803888) -->
- <skip />
- <!-- no translation found for textSelectionCABTitle (5236850394370820357) -->
- <skip />
- <!-- no translation found for addToDictionary (4352161534510057874) -->
- <skip />
- <!-- no translation found for deleteText (6979668428458199034) -->
- <skip />
- <!-- no translation found for inputMethod (1653630062304567879) -->
- <skip />
- <!-- no translation found for editTextMenuTitle (4909135564941815494) -->
- <skip />
- <!-- no translation found for low_internal_storage_view_title (5576272496365684834) -->
- <skip />
- <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
- <skip />
- <!-- no translation found for low_internal_storage_view_text_no_boot (6935190099204693424) -->
- <skip />
- <!-- no translation found for app_running_notification_title (8718335121060787914) -->
- <skip />
- <!-- no translation found for app_running_notification_text (4653586947747330058) -->
- <skip />
- <!-- no translation found for ok (5970060430562524910) -->
- <skip />
- <!-- no translation found for cancel (6442560571259935130) -->
- <skip />
- <!-- no translation found for yes (5362982303337969312) -->
- <skip />
- <!-- no translation found for no (5141531044935541497) -->
- <skip />
- <!-- no translation found for dialog_alert_title (2049658708609043103) -->
- <skip />
- <!-- no translation found for loading (7933681260296021180) -->
- <skip />
- <!-- no translation found for capital_on (1544682755514494298) -->
- <skip />
- <!-- no translation found for capital_off (6815870386972805832) -->
- <skip />
- <!-- no translation found for whichApplication (4533185947064773386) -->
- <skip />
- <!-- no translation found for whichApplicationNamed (8260158865936942783) -->
- <skip />
- <!-- no translation found for whichViewApplication (3272778576700572102) -->
- <skip />
- <!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
- <skip />
- <!-- no translation found for whichEditApplication (144727838241402655) -->
- <skip />
- <!-- no translation found for whichEditApplicationNamed (1775815530156447790) -->
- <skip />
- <!-- no translation found for whichSendApplication (6902512414057341668) -->
- <skip />
- <!-- no translation found for whichSendApplicationNamed (2799370240005424391) -->
- <skip />
- <!-- no translation found for whichHomeApplication (4307587691506919691) -->
- <skip />
- <!-- no translation found for whichHomeApplicationNamed (4493438593214760979) -->
- <skip />
- <!-- no translation found for alwaysUse (4583018368000610438) -->
- <skip />
- <!-- no translation found for use_a_different_app (8134926230585710243) -->
- <skip />
- <!-- no translation found for clearDefaultHintMsg (3252584689512077257) -->
- <skip />
- <!-- no translation found for chooseActivity (7486876147751803333) -->
- <skip />
- <!-- no translation found for chooseUsbActivity (6894748416073583509) -->
- <skip />
- <!-- no translation found for noApplications (2991814273936504689) -->
- <skip />
+ <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona za otisak prsta"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje postavki za sinhroniziranje"</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Omogućava aplikaciji čitanje postavki sinhroniziranja za račun. Naprimjer, ovim se može utvrditi da li je aplikacija People sinhronizirana sa računom."</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"uključivanje i isključivanje sinhroniziranja"</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Omogućava aplikaciji izmjenu postavki sinhroniziranja za račun. Naprimjer, ovim se može omogućiti sinhroniziranje aplikacije People sa računom."</string>
+ <string name="permlab_readSyncStats" msgid="7396577451360202448">"čitanje statistike sinhroniziranja"</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Omogućava aplikaciji čitanje statistike sinhroniziranja za račun, uključujući historiju događaja sinhroniziranja i količinu sinhroniziranih podataka."</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"čitanje sadržaja USB pohrane"</string>
+ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"čitanje sadržaja SD kartice"</string>
+ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Omogućava aplikaciji čitanje sadržaja USB pohrane."</string>
+ <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Omogućava aplikaciji čitanje sadržaja SD kartice."</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"mijenjanje ili brisanje sadržaja USB pohrane"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"mijenjanje ili brisanje sadržaja SD kartice"</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Dozvoljava pisanje na USB pohranu."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Dozvoljava aplikaciji pisanje na SD karticu."</string>
+ <string name="permlab_use_sip" msgid="2052499390128979920">"Uputi/primi SIP pozive"</string>
+ <string name="permdesc_use_sip" msgid="2297804849860225257">"Dozvoljava aplikaciji upućivanje i prijem SIP poziva."</string>
+ <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"registriraj nove telekom SMS veze"</string>
+ <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Dozvoljava aplikaciji da registrira nove telekom SIM veze."</string>
+ <string name="permlab_register_call_provider" msgid="108102120289029841">"registriraj nove telekom veze"</string>
+ <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Dozvoljava aplikaciji da registrira nove telekom veze."</string>
+ <string name="permlab_connection_manager" msgid="1116193254522105375">"upravljaj telekom vezama"</string>
+ <string name="permdesc_connection_manager" msgid="5925480810356483565">"Dozvoljava aplikacijama upravljanje telekom vezama."</string>
+ <string name="permlab_bind_incall_service" msgid="6773648341975287125">"vrši interakciju s ekranom tokom poziva"</string>
+ <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Dozvoljava aplikaciji da kontrolira kada i kako korisnik vidi ekran tokom poziva."</string>
+ <string name="permlab_bind_connection_service" msgid="3557341439297014940">"vrši interakciju s telefonskim uslugama"</string>
+ <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Dozvoljava aplikaciji interakciju s telefonskim uslugama za upućivanje/prijem poziva."</string>
+ <string name="permlab_control_incall_experience" msgid="9061024437607777619">"omogući opcije tokom poziva"</string>
+ <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Dozvoljava aplikaciji da omogući opcije tokom poziva."</string>
+ <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"čitanje historije korištenja mreže"</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Dozvoljava aplikaciji da pročita istoriju korištenja mreže za određene mreže i aplikacije."</string>
+ <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"upravljanje mrežnim pravilima"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Dozvoljava aplikaciji upravljanje mrežnim pravilima i određivanje pravila koja se odnose na aplikacije."</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena obračunavanja korištenja mreže"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Dozvoljava aplikaciji izmjenu načina na koji aplikacije koriste mreže. Nije namijenjeno za uobičajene aplikacije."</string>
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavještenjima"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućava aplikaciji preuzimanje, ispitivanje i brisanje obavještenja, uključujući i ona koja su objavile druge aplikacije."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"povezivanje sa uslugom za slušanje obavještenja"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Omogućava vlasniku povezivanje s interfejsom najvišeg nivoa u servisu za slušanje obavještenja. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"poveži sa servisom pružaoca uslova"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa u servisu pružaoca uslova. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"poveži sa servisom za čuvanje ekrana"</string>
+ <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa u servisu za čuvanje ekrana. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"pokretanje operaterove aplikacije za konfiguraciju"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Omogućava vlasniku pokretanje aplikacije za konfiguraciju koju je obezbijedio operater. Nije potrebno za normalne aplikacije."</string>
+ <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"slušanje informacija o stanju mreže"</string>
+ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Omogućava aplikaciji slušanje informacije o stanju mreže. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promijeni kalibraciju ulaznog uređaja"</string>
+ <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Dozvoljava aplikaciji kalibriranje parametara dodirnog ekrana. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"pristupi DRM certifikatima"</string>
+ <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Dozvoljava aplikaciji da obezbijedi i koristi DRM certifikate. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_handoverStatus" msgid="7820353257219300883">"prijem statusa prebacivanja preko Android prebacivanja"</string>
+ <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Dozvoljava aplikaciji prijem informacija o trenutnim prijenosima putem funkcije Android Beam"</string>
+ <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"ukloni DRM certifikate"</string>
+ <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Dozvoljava aplikaciji da ukloni DRM certifikate. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"poveži sa servisom za poruke operatera"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dozvoljava vlasniku povezivanje s interfejsom najvišeg nivoa u servisu za poruke operatera. Nije potrebno za obične aplikacije."</string>
+ <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"povezivanje na usluge operatera"</string>
+ <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Omogućava vlasniku povezivanje sa uslugama operatera. Obično nije potrebno za obične aplikacije."</string>
+ <string name="permlab_access_notification_policy" msgid="4247510821662059671">"pristup opciji Ne ometaj"</string>
+ <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Omogućava aplikaciji da čita i upisuje konfiguraciju opcije Ne ometaj."</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavljanje pravila za lozinke"</string>
+ <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolira dužinu i znakove koji su dozvoljeni u lozinkama za zaključavanje ekrana i PIN kodovima."</string>
+ <string name="policylab_watchLogin" msgid="914130646942199503">"Prati pokušaje otključavanja ekrana"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Prati broj pogrešno unijetih lozinki prilikom otključavanja ekrana i zaključava tablet ili briše sve podatke s njega ukoliko se previše puta unese pogrešna lozinka."</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Prati koliko puta je lozinka neispravno otkucana prilikom otključavanja ekrana i zaključaj TV ili izbriši sve podatke s TV-a ako se lozinka neispravno ukuca previše puta."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Prati broj pogrešno unesenih lozinki prilikom otključavanja ekrana i zaključava telefon ili briše sve podatke s telefona ukoliko se previše puta unese pogrešna lozinka."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Prati broj neispravnih lozinki koje su unijete za otključavanje ekrana te zaključava tablet ili briše sve podatke ovog korisnika ukoliko je unijeto previše neispravnih lozinki."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Prati broj neispravnih lozinki koje su unijete za otključavanje ekrana te zaključava TV ili briše sve podatke ovog korisnika ukoliko je unijeto previše neispravnih lozinki."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Prati broj neispravnih lozinki koje su unijete za otključavanje ekrana te zaključava telefon ili briše sve podatke ovog korisnika ukoliko je unijeto previše neispravnih lozinki."</string>
+ <string name="policylab_resetPassword" msgid="4934707632423915395">"Promijeni zaključavanje ekrana"</string>
+ <string name="policydesc_resetPassword" msgid="1278323891710619128">"Mijenja zaključavanje ekrana."</string>
+ <string name="policylab_forceLock" msgid="2274085384704248431">"Zaključava ekran"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrolira kako i kada se ekran zaključava."</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"Briše sve podatke"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Briše podatke s tableta bez upozorenja tako što ga vraća na fabričke postavke."</string>
+ <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Bez upozorenja obriši sve podatke s TV-a vraćanjem na fabričke postavke."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Briše podatke s telefona bez upozorenja vraćanjem telefona na fabričke postavke."</string>
+ <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Izbriši podatke korisnika"</string>
+ <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Bez upozorenja briše podatke ovog korisnika sa ovog tableta."</string>
+ <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Bez upozorenja briše podatke ovog korisnika sa ovog TV-a."</string>
+ <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Bez upozorenja briše podatke ovog korisnika sa ovog telefona."</string>
+ <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Postavlja globalni proksi uređaja"</string>
+ <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Postavlja globalni proksi uređaja koji će se koristiti dok su smjernice omogućene. Samo vlasnik uređaja može postaviti globalni proksi."</string>
+ <string name="policylab_expirePassword" msgid="5610055012328825874">"Postavi isteknuće lozinke za zaključavanje ekrana"</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"Mijenja koliko često se lozinka za zaključavanje ekrana, PIN ili obrazac moraju promijeniti."</string>
+ <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Podešava šifriranje pohrane"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Zahtijeva šifriranje pohranjenih podataka aplikacije."</string>
+ <string name="policylab_disableCamera" msgid="6395301023152297826">"Isključuje kamere"</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"Sprečava korištenje svih kamera uređaja."</string>
+ <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Onemog. neke funk. zak. ekrana"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Spriječava korištenje nekih funkcija za zaključavanje ekrana."</string>
+ <string-array name="phoneTypes">
+ <item msgid="8901098336658710359">"Kuća"</item>
+ <item msgid="869923650527136615">"Mobilni"</item>
+ <item msgid="7897544654242874543">"Poslovni"</item>
+ <item msgid="1103601433382158155">"Poslovni faks"</item>
+ <item msgid="1735177144948329370">"Kućni faks"</item>
+ <item msgid="603878674477207394">"Pejdžer"</item>
+ <item msgid="1650824275177931637">"Ostalo"</item>
+ <item msgid="9192514806975898961">"Dodatno"</item>
+ </string-array>
+ <string-array name="emailAddressTypes">
+ <item msgid="8073994352956129127">"Kućni"</item>
+ <item msgid="7084237356602625604">"Poslovni"</item>
+ <item msgid="1112044410659011023">"Ostali"</item>
+ <item msgid="2374913952870110618">"Dodatni"</item>
+ </string-array>
+ <string-array name="postalAddressTypes">
+ <item msgid="6880257626740047286">"Kuća"</item>
+ <item msgid="5629153956045109251">"Posao"</item>
+ <item msgid="4966604264500343469">"Ostalo"</item>
+ <item msgid="4932682847595299369">"Dodatno"</item>
+ </string-array>
+ <string-array name="imAddressTypes">
+ <item msgid="1738585194601476694">"Kućni"</item>
+ <item msgid="1359644565647383708">"Poslovni"</item>
+ <item msgid="7868549401053615677">"Ostali"</item>
+ <item msgid="3145118944639869809">"Dodatni"</item>
+ </string-array>
+ <string-array name="organizationTypes">
+ <item msgid="7546335612189115615">"Posao"</item>
+ <item msgid="4378074129049520373">"Ostalo"</item>
+ <item msgid="3455047468583965104">"Dodatno"</item>
+ </string-array>
+ <string-array name="imProtocols">
+ <item msgid="8595261363518459565">"AIM"</item>
+ <item msgid="7390473628275490700">"Windows Live"</item>
+ <item msgid="7882877134931458217">"Yahoo"</item>
+ <item msgid="5035376313200585242">"Skype"</item>
+ <item msgid="7532363178459444943">"QQ"</item>
+ <item msgid="3713441034299660749">"Google Talk"</item>
+ <item msgid="2506857312718630823">"ICQ"</item>
+ <item msgid="1648797903785279353">"Jabber"</item>
+ </string-array>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"Prilagođeno"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"Kuća"</string>
+ <string name="phoneTypeMobile" msgid="6501463557754751037">"Mobilni"</string>
+ <string name="phoneTypeWork" msgid="8863939667059911633">"Posao"</string>
+ <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Poslovni faks"</string>
+ <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Kućni faks"</string>
+ <string name="phoneTypePager" msgid="7582359955394921732">"Pejdžer"</string>
+ <string name="phoneTypeOther" msgid="1544425847868765990">"Ostalo"</string>
+ <string name="phoneTypeCallback" msgid="2712175203065678206">"Povratni poziv"</string>
+ <string name="phoneTypeCar" msgid="8738360689616716982">"Auto"</string>
+ <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Glavni broj kompanije"</string>
+ <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
+ <string name="phoneTypeMain" msgid="6766137010628326916">"Glavni"</string>
+ <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Drugi faks"</string>
+ <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
+ <string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
+ <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
+ <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Posao mobilni"</string>
+ <string name="phoneTypeWorkPager" msgid="649938731231157056">"Poslovni pejdžer"</string>
+ <string name="phoneTypeAssistant" msgid="5596772636128562884">"Pomoćnik"</string>
+ <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"Prilagođeno"</string>
+ <string name="eventTypeBirthday" msgid="2813379844211390740">"Rođendan"</string>
+ <string name="eventTypeAnniversary" msgid="3876779744518284000">"Godišnjica"</string>
+ <string name="eventTypeOther" msgid="7388178939010143077">"Ostalo"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"Prilagođeni"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"Kućni"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"Poslovni"</string>
+ <string name="emailTypeOther" msgid="2923008695272639549">"Ostali"</string>
+ <string name="emailTypeMobile" msgid="119919005321166205">"Mobilni"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"Prilagođeno"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"Kućna adresa"</string>
+ <string name="postalTypeWork" msgid="5268172772387694495">"Posao"</string>
+ <string name="postalTypeOther" msgid="2726111966623584341">"Ostalo"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"Prilagođeno"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"Kuća"</string>
+ <string name="imTypeWork" msgid="1371489290242433090">"Posao"</string>
+ <string name="imTypeOther" msgid="5377007495735915478">"Ostalo"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"Prilagođeno"</string>
+ <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
+ <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
+ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
+ <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
+ <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
+ <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
+ <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
+ <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
+ <string name="orgTypeWork" msgid="29268870505363872">"Posao"</string>
+ <string name="orgTypeOther" msgid="3951781131570124082">"Ostalo"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"Prilagođeno"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"Prilagođeno"</string>
+ <string name="relationTypeAssistant" msgid="6274334825195379076">"Pomoćnik"</string>
+ <string name="relationTypeBrother" msgid="8757913506784067713">"Brat"</string>
+ <string name="relationTypeChild" msgid="1890746277276881626">"Dijete"</string>
+ <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Domaći partner"</string>
+ <string name="relationTypeFather" msgid="5228034687082050725">"Otac"</string>
+ <string name="relationTypeFriend" msgid="7313106762483391262">"Prijatelj"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"Menadžer"</string>
+ <string name="relationTypeMother" msgid="4578571352962758304">"Majka"</string>
+ <string name="relationTypeParent" msgid="4755635567562925226">"Roditelj"</string>
+ <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
+ <string name="relationTypeReferredBy" msgid="101573059844135524">"Uputio(la)"</string>
+ <string name="relationTypeRelative" msgid="1799819930085610271">"Rođak"</string>
+ <string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
+ <string name="relationTypeSpouse" msgid="394136939428698117">"Bračni partner"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Prilagođeno"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Kuća"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Posao"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Ostalo"</string>
+ <string name="quick_contacts_not_available" msgid="746098007828579688">"Nije pronađena aplikacija za pregled ovog kontakta."</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite za unos lozinke"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite lozinku za otključavanje tipkovnice"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje tipkovnice"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Pogrešan PIN."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Za otključavanje telefona pritisnite dugme Meni, pa dugme 0."</string>
+ <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Broj za hitne slučajeve"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nema mreže"</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran zaključan."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pritisnite dugme Meni kako biste otključali uređaj ili obavili hitni poziv."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pritisnite dugme Meni za otključavanje uređaja."</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Nacrtajte uzorak za otključavanje"</string>
+ <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Hitni slučaj"</string>
+ <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Povratak na poziv"</string>
+ <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Ispravno!"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Pokušajte ponovo"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Pokušajte ponovo"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen maksimalni broj pokušaja otključavanja licem"</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nema SIM kartice"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nema SIM kartice u tabletu."</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Nema SIM kartice u TV-u."</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Nema SIM kartice u telefonu."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Umetnite SIM karticu."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM kartica nije umetnuta ili je uređaj ne može očitati. Umetnite SIM karticu."</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Neupotrebljiva SIM kartica."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaša SIM kartica je trajno onemogućena.\nKako biste dobili drugu SIM karticu, obratite se svom pružaocu bežičnih usluga."</string>
+ <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Prethodna numera"</string>
+ <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Sljedeća numera"</string>
+ <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pauziraj"</string>
+ <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Reproduciraj"</string>
+ <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Zaustavi"</string>
+ <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Premotaj"</string>
+ <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Ubrzaj"</string>
+ <string name="emergency_calls_only" msgid="6733978304386365407">"Samo hitni pozivi"</string>
+ <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Mreža zaključana"</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM kartica je zaključana PUK-om."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Pogledajte Priručnik za korištenje ili kontaktirajte odjel za brigu o kupcima."</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kartica je zaključana."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Otključavanje SIM kartice..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Pogrešno ste nacrtali svoj uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Pogrešno ste unijeli svoju lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Pogrešno ste unijeli svoj PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Pogrešno ste unijeli uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Možete pokušati još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta. Nakon toga ćete morati otključati tablet prijavom na svoj Google račun.\n\n Broj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_2">%3$d</xliff:g>"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Uzorak za otključavanje ste neispravno nacrtali <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, bit će zatraženo da TV otključate pomoću Google prijave.\n\n Pokušajte opet za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Pogrešno ste unijeli uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Možete pokušati još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta. Nakon toga ćete morati otključati telefon prijavom na svoj Google račun.\n\n Broj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_2">%3$d</xliff:g>"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Pogrešno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Možete pokušati još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta. Ukoliko ni tada ne uspijete otključati tablet, tablet će se vratiti na fabričke postavke i svi korisnički podaci bit će izgubljeni."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati TV. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, TV će biti vraćen na fabričke postavke i svi podaci korisnika bit će izgubljeni."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Pogrešno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Možete pokušati još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta. Ukoliko ni tada ne uspijete otključati telefon, telefon će se vratiti na fabričke postavke i svi korisnički podaci bit će izgubljeni."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Pogrešno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na fabričke postavke."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati TV. TV će sada biti vraćen na fabričke postavke."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Pogrešno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na fabričke postavke."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Broj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER">%d</xliff:g>"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zaboravili ste uzorak?"</string>
+ <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Otključavanje pomoću Google računa"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Previše puta ste pokušali otključati uređaj unosom uzorka"</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Kako biste otključali telefon, prijavite se na svoj Google račun."</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Korisničko ime (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Lozinka"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Prijava"</string>
+ <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Pogrešno korisničko ime ili lozinka."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zaboravili ste korisničko ime ili lozinku?\nPosjetite "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Provjera u toku..."</string>
+ <string name="lockscreen_unlock_label" msgid="737440483220667054">"Otključaj"</string>
+ <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Zvuk uključen"</string>
+ <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Isključi zvuk"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Uzorak započet"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Uzorak izbrisan"</string>
+ <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Ćelija dodana"</string>
+ <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"Ćelija <xliff:g id="CELL_INDEX">%1$s</xliff:g> je dodana"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Uzorak unesen"</string>
+ <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Oblast za unošenje obrasca."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d od %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodaj widget."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prazno"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oblast za otključavanje je proširena."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oblast za otključavanje je smanjena."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget za <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Biranje korisnika"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Upravljanje medijima"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Promjena rasporeda widgeta je počela."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Promjena rasporeda widgeta je završena."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> je izbrisan."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Proširi oblast za otključavanje."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Otključavanje pomoću klizača."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Otključavanje uzorkom."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Otključavanje licem."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje pinom."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje lozinkom."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Uzorak oblasti."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast za pomjeranje klizača."</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="granularity_label_character" msgid="7336470535385009523">"znak"</string>
+ <string name="granularity_label_word" msgid="7075570328374918660">"riječ"</string>
+ <string name="granularity_label_link" msgid="5815508880782488267">"link"</string>
+ <string name="granularity_label_line" msgid="5764267235026120888">"linija"</string>
+ <string name="factorytest_failed" msgid="5410270329114212041">"Fabrički test nije uspio"</string>
+ <string name="factorytest_not_system" msgid="4435201656767276723">"Akcija FACTORY_TEST podržana je samo za pakete instalirane u facsikli /system/app."</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"Nije pronađen paket koji omogućava akciju FACTORY_TEST."</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"Ponovno pokretanje"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"Stranica na \"<xliff:g id="TITLE">%s</xliff:g>\" kaže:"</string>
+ <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
+ <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potvrdite navigaciju"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Napusti ovu stranicu"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Ostani na ovoj stranici"</string>
+ <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n Da li ste sigurni da želite napustiti ovu stranicu?"</string>
+ <string name="save_password_label" msgid="6860261758665825069">"Potvrdite"</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"Savjet: Dodirnite ekran dva puta za uvećanje ili smanjenje prikaza."</string>
+ <string name="autofill_this_form" msgid="4616758841157816676">"Autofill"</string>
+ <string name="setup_autofill" msgid="7103495070180590814">"Podesite Autofill"</string>
+ <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
+ <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
+ <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Pokrajina"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Poštanski broj"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Država"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Poštanski broj"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Okrug"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Ostrvo"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Oblast"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Odsjek"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefektura"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Parohija"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Oblast"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
+ <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"čitanje internet oznaka i historije"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Omogućava aplikaciji čitanje historije URL-ova koje je preglednik posjetio, kao i svih oznaka preglednika. Napomena: ovu dozvolu ne mogu iskoristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"pisanje internet oznaka i historije"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Omogućava aplikaciji da izmijeni historiju ili oznake preglednika koji su pohranjeni na vašem tabletu. Ovim se aplikaciji može omogućiti da izbriše ili izmijeni podatke preglednika. Napomena: ovu dozvolu ne mogu koristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Dozvoljava aplikaciji izmjenu historije ili oznaka preglednika pohranjenih na TV-u. Ovim se aplikaciji može omogućiti brisanje ili izmjena podataka preglednika. Napomena: ovu dozvolu ne mogu iskoristiti preglednici trećih strana ili druge aplikacije koje imaju mogućnost pregleda interneta."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Omogućava aplikaciji da izmijeni historiju ili oznake preglednika koji su pohranjeni na vašem telefonu. Ovim se aplikaciji može omogućiti da izbriše ili izmijeni podatke preglednika. Napomena: ovu dozvolu ne mogu koristiti preglednika trećih strana ili druge aplikacije koje imaju mogućnost pregledanja interneta."</string>
+ <string name="permlab_setAlarm" msgid="1379294556362091814">"postavljanje alarma"</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"Dozvoljava aplikaciji postavljanje alarma u instaliranom budilniku. Moguće je da neki budilnici neće primijeniti ovu funkciju."</string>
+ <string name="permlab_addVoicemail" msgid="5525660026090959044">"dodavanje govorne pošte"</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Dozvoljava aplikaciji dodavanje poruka u vašu ulaznu govornu poštu."</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"izmjena geolokacijskih dozvola preglednika"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Dozvoljava aplikaciji mijenjanje geolokacijskih dozvola pretraživača. Zlonamjerne aplikacije mogu to iskoristiti i dozvoliti slanje informacija o lokaciji proizvoljnim web stranicama."</string>
+ <string name="save_password_message" msgid="767344687139195790">"Želite li da preglednik zapamti ovu lozinku?"</string>
+ <string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
+ <string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"Nikad"</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"Nemate dozvolu za otvaranje ove stranice."</string>
+ <string name="text_copied" msgid="4985729524670131385">"Tekst kopiran u međuspremnik."</string>
+ <string name="more_item_label" msgid="4650918923083320495">"Više"</string>
+ <string name="prepend_shortcut_label" msgid="2572214461676015642">"Meni+"</string>
+ <string name="menu_space_shortcut_label" msgid="2410328639272162537">"razmak"</string>
+ <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"potvrdi"</string>
+ <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"izbriši"</string>
+ <string name="search_go" msgid="8298016669822141719">"Traži"</string>
+ <string name="search_hint" msgid="1733947260773056054">"Pretraži..."</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"Traži"</string>
+ <string name="searchview_description_query" msgid="5911778593125355124">"Upit za pretragu"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"Obriši upit"</string>
+ <string name="searchview_description_submit" msgid="2688450133297983542">"Potvrditi upit"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"Glasovno pretraživanje"</string>
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Želite li omogućiti Istraživanje dodirom?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"Usluga <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogućiti Istraživanje dodirom. Kada je Istraživanje dodirom uključeno, možete čuti ili vidjeti opise onoga što vam je pod prstom ili praviti pokrete za interakciju sa tabletom."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Usluga <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogućiti Istraživanje dodirom. Kada je Istraživanje dodirom uključeno, možete čuti ili vidjeti opise onoga što vam je pod prstom ili praviti pokrete za interakciju sa telefonom."</string>
+ <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prije mjesec dana"</string>
+ <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prije više od mjesec dana"</string>
+ <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+ <item quantity="one">Prethodni <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
+ <item quantity="few">Prethodna <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
+ <item quantity="other">Prethodnih <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
+ </plurals>
+ <string name="last_month" msgid="3959346739979055432">"Prošli mjesec"</string>
+ <string name="older" msgid="5211975022815554840">"Starije"</string>
+ <string name="preposition_for_date" msgid="9093949757757445117">"datuma <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="preposition_for_time" msgid="5506831244263083793">"u <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="preposition_for_year" msgid="5040395640711867177">"godine <xliff:g id="YEAR">%s</xliff:g>"</string>
+ <string name="day" msgid="8144195776058119424">"dan"</string>
+ <string name="days" msgid="4774547661021344602">"dana"</string>
+ <string name="hour" msgid="2126771916426189481">"sat"</string>
+ <string name="hours" msgid="894424005266852993">"sati"</string>
+ <string name="minute" msgid="9148878657703769868">"minuta"</string>
+ <string name="minutes" msgid="5646001005827034509">"minute"</string>
+ <string name="second" msgid="3184235808021478">"sekunda"</string>
+ <string name="seconds" msgid="3161515347216589235">"sekunde"</string>
+ <string name="week" msgid="5617961537173061583">"sedmica"</string>
+ <string name="weeks" msgid="6509623834583944518">"sedmice"</string>
+ <string name="year" msgid="4001118221013892076">"godina"</string>
+ <string name="years" msgid="6881577717993213522">"godine"</string>
+ <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekunda</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+ </plurals>
+ <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+ </plurals>
+ <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sat</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sata</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sati</item>
+ </plurals>
+ <string name="VideoView_error_title" msgid="3534509135438353077">"Problem sa prikazom video sadržaja"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Prijenos ovog video sadržaja ne može se izvršiti na ovom uređaju."</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Greška prilikom reproduciranja video sadržaja."</string>
+ <string name="VideoView_error_button" msgid="2822238215100679592">"Uredu"</string>
+ <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon" msgid="7245353528818587908">"podne"</string>
+ <string name="Noon" msgid="3342127745230013127">"Podne"</string>
+ <string name="midnight" msgid="7166259508850457595">"ponoć"</string>
+ <string name="Midnight" msgid="5630806906897892201">"Ponoć"</string>
+ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Odaberi sve"</string>
+ <string name="cut" msgid="3092569408438626261">"Izreži"</string>
+ <string name="copy" msgid="2681946229533511987">"Kopirajte"</string>
+ <string name="paste" msgid="5629880836805036433">"Zalijepi"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Zalijepi kao neformatiran tekst"</string>
+ <string name="replace" msgid="5781686059063148930">"Zamijeniti..."</string>
+ <string name="delete" msgid="6098684844021697789">"Izbrišite"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"Kopirajte URL"</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"Odaberi tekst"</string>
+ <string name="undo" msgid="7905788502491742328">"Vrati"</string>
+ <string name="redo" msgid="7759464876566803888">"Ponovo uradi"</string>
+ <string name="textSelectionCABTitle" msgid="5236850394370820357">"Odabir teksta"</string>
+ <string name="addToDictionary" msgid="4352161534510057874">"Dodaj u rječnik"</string>
+ <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="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>
+ <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
+ <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili da zaustavite aplikaciju."</string>
+ <string name="ok" msgid="5970060430562524910">"Uredu"</string>
+ <string name="cancel" msgid="6442560571259935130">"Prekini"</string>
+ <string name="yes" msgid="5362982303337969312">"Uredu"</string>
+ <string name="no" msgid="5141531044935541497">"Prekini"</string>
+ <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
+ <string name="loading" msgid="7933681260296021180">"Učitavanje..."</string>
+ <string name="capital_on" msgid="1544682755514494298">"Uključeno"</string>
+ <string name="capital_off" msgid="6815870386972805832">"Isključeno"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"Izvrši akciju koristeći"</string>
+ <string name="whichApplicationNamed" msgid="8260158865936942783">"Dovršite akciju koristeći %1$s"</string>
+ <string name="whichViewApplication" msgid="3272778576700572102">"Otvori koristeći"</string>
+ <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvori koristeći %1$s"</string>
+ <string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
+ <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
+ <string name="whichSendApplication" msgid="6902512414057341668">"Podijeli koristeći"</string>
+ <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Podijeli koristeći %1$s"</string>
+ <string name="whichHomeApplication" msgid="4307587691506919691">"Odaberi glavnu aplikaciju"</string>
+ <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Koristi %1$s kao glavnu aplikaciju"</string>
+ <string name="alwaysUse" msgid="4583018368000610438">"Koristiti kao zadanu rezoluciju za ovu akciju."</string>
+ <string name="use_a_different_app" msgid="8134926230585710243">"Koristi drugu aplikaciju"</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Obrišite zadane opcije u meniju Postavke sistema &gt; Aplikacije &gt; Preuzete aplikacije."</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"Odaberite akciju"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"Odaberite aplikaciju za USB uređaj"</string>
+ <string name="noApplications" msgid="2991814273936504689">"Nijedna aplikacija ne može izvršiti ovu akciju."</string>
<string name="aerr_application" msgid="250320989337856518">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> je zaustavljena"</string>
- <string name="aerr_process" msgid="6201597323218674729">"Aplikacija <xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljena"</string>
+ <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljen"</string>
<string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se stalno zaustavlja"</string>
<string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> se stalno zaustavlja"</string>
<string name="aerr_restart" msgid="9001379185665886595">"Ponovo pokreni aplikaciju"</string>
<string name="aerr_reset" msgid="7645427603514220451">"Vrati aplikaciju na zadano i pokreni ponovo"</string>
<string name="aerr_report" msgid="5371800241488400617">"Pošalji povratne informacije"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Zanemari"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Isključiti zvuk dok se uređaj ponovo ne pokrene"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Sačekaj"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zatvori aplikaciju"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1709,1164 +930,658 @@
<string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ne reaguje"</string>
<string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> ne reaguje"</string>
<string name="anr_process" msgid="6156880875555921105">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> ne reaguje"</string>
- <!-- no translation found for force_close (8346072094521265605) -->
- <skip />
- <!-- no translation found for report (4060218260984795706) -->
- <skip />
- <!-- no translation found for wait (7147118217226317732) -->
- <skip />
- <!-- no translation found for webpage_unresponsive (3272758351138122503) -->
- <skip />
- <!-- no translation found for launch_warning_title (1547997780506713581) -->
- <skip />
- <!-- no translation found for launch_warning_replace (6202498949970281412) -->
- <skip />
- <!-- no translation found for launch_warning_original (188102023021668683) -->
- <skip />
- <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
- <skip />
- <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
- <skip />
- <!-- no translation found for screen_compat_mode_hint (1064524084543304459) -->
- <skip />
- <!-- no translation found for smv_application (3307209192155442829) -->
- <skip />
- <!-- no translation found for smv_process (5120397012047462446) -->
- <skip />
- <!-- no translation found for android_upgrading_title (1584192285441405746) -->
- <skip />
- <!-- no translation found for android_start_title (8418054686415318207) -->
- <skip />
- <!-- no translation found for android_upgrading_fstrim (8036718871534640010) -->
- <skip />
- <!-- no translation found for android_upgrading_apk (7904042682111526169) -->
- <skip />
- <!-- no translation found for android_preparing_apk (8162599310274079154) -->
- <skip />
- <!-- no translation found for android_upgrading_starting_apps (451464516346926713) -->
- <skip />
- <!-- no translation found for android_upgrading_complete (1405954754112999229) -->
- <skip />
- <!-- no translation found for heavy_weight_notification (9087063985776626166) -->
- <skip />
- <!-- no translation found for heavy_weight_notification_detail (1721681741617898865) -->
- <skip />
- <!-- no translation found for heavy_weight_switcher_title (7153167085403298169) -->
- <skip />
- <!-- no translation found for heavy_weight_switcher_text (7022631924534406403) -->
- <skip />
- <!-- no translation found for old_app_action (493129172238566282) -->
- <skip />
- <!-- no translation found for old_app_description (2082094275580358049) -->
- <skip />
- <!-- no translation found for new_app_action (5472756926945440706) -->
- <skip />
- <!-- no translation found for new_app_description (1932143598371537340) -->
- <skip />
- <!-- no translation found for dump_heap_notification (2618183274836056542) -->
- <skip />
- <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
- <skip />
- <!-- no translation found for dump_heap_title (5864292264307651673) -->
- <skip />
- <!-- no translation found for dump_heap_text (4809417337240334941) -->
- <skip />
- <!-- no translation found for sendText (5209874571959469142) -->
- <skip />
- <!-- no translation found for volume_ringtone (6885421406845734650) -->
- <skip />
- <!-- no translation found for volume_music (5421651157138628171) -->
- <skip />
- <!-- no translation found for volume_music_hint_playing_through_bluetooth (9165984379394601533) -->
- <skip />
- <!-- no translation found for volume_music_hint_silent_ringtone_selected (8310739960973156272) -->
- <skip />
- <!-- no translation found for volume_call (3941680041282788711) -->
- <skip />
- <!-- no translation found for volume_bluetooth_call (2002891926351151534) -->
- <skip />
- <!-- no translation found for volume_alarm (1985191616042689100) -->
- <skip />
- <!-- no translation found for volume_notification (2422265656744276715) -->
- <skip />
- <!-- no translation found for volume_unknown (1400219669770445902) -->
- <skip />
- <!-- no translation found for volume_icon_description_bluetooth (6538894177255964340) -->
- <skip />
- <!-- no translation found for volume_icon_description_ringer (3326003847006162496) -->
- <skip />
- <!-- no translation found for volume_icon_description_incall (8890073218154543397) -->
- <skip />
- <!-- no translation found for volume_icon_description_media (4217311719665194215) -->
- <skip />
- <!-- no translation found for volume_icon_description_notification (7044986546477282274) -->
- <skip />
- <!-- no translation found for ringtone_default (3789758980357696936) -->
- <skip />
- <!-- no translation found for ringtone_default_with_actual (8129563480895990372) -->
- <skip />
- <!-- no translation found for ringtone_silent (7937634392408977062) -->
- <skip />
- <!-- no translation found for ringtone_picker_title (3515143939175119094) -->
- <skip />
- <!-- no translation found for ringtone_unknown (5477919988701784788) -->
- <skip />
- <!-- no translation found for wifi_available (7900333017752027322) -->
- <!-- no translation found for wifi_available_detailed (1140699367193975606) -->
- <!-- no translation found for wifi_available_sign_in (9157196203958866662) -->
- <skip />
- <!-- no translation found for network_available_sign_in (1848877297365446605) -->
- <skip />
+ <string name="force_close" msgid="8346072094521265605">"Uredu"</string>
+ <string name="report" msgid="4060218260984795706">"Prijavi"</string>
+ <string name="wait" msgid="7147118217226317732">"Sačekaj"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Stranica ne reagira.\n\nŽelite li je zatvoriti?"</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"Aplikacija preusmjerena"</string>
+ <string name="launch_warning_replace" msgid="6202498949970281412">"Sada je pokrenuta aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="launch_warning_original" msgid="188102023021668683">"Izvorno je pokrenuta aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmjer"</string>
+ <string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvijek prikaži"</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite ovu opciju u meniju Postavke sistema &gt; Aplikacije &gt; Preuzete aplikacije."</string>
+ <string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string>
+ <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je vlastita StrictMode pravila."</string>
+ <string name="android_upgrading_title" msgid="1584192285441405746">"Nadogradnja sistema Android u toku..."</string>
+ <string name="android_start_title" msgid="8418054686415318207">"Android se pokreće..."</string>
+ <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimiziranje pohrane."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiziranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="android_preparing_apk" msgid="8162599310274079154">"Priprema se <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
+ <string name="android_upgrading_complete" msgid="1405954754112999229">"Pokretanje pri kraju."</string>
+ <string name="heavy_weight_notification" msgid="9087063985776626166">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Dodirnite kako biste otvorili aplikaciju"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite se prebaciti na drugu aplikaciju?"</string>
+ <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već je pokrenuta jedna aplikacija koju morate zaustaviti prije pokretanja nove."</string>
+ <string name="old_app_action" msgid="493129172238566282">"Vrati se na aplikaciju <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="old_app_description" msgid="2082094275580358049">"Ne pokretati novu aplikaciju."</string>
+ <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_description" msgid="1932143598371537340">"Zaustaviti staru aplikaciju bez spašavanja podataka."</string>
+ <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> premašuje ograničenje memorije"</string>
+ <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Snimak dinamičkog dijela memorije je napravljen; dodirnite za dijeljenje"</string>
+ <string name="dump_heap_title" msgid="5864292264307651673">"Želite li dijeliti snimak dinamičkog dijela memorije?"</string>
+ <string name="dump_heap_text" msgid="4809417337240334941">"Proces <xliff:g id="PROC">%1$s</xliff:g> je premašio ograničenje procesne memorije od <xliff:g id="SIZE">%2$s</xliff:g>. Snimak dinamičkog dijela memorije vam je dostupan i možete ga dijeliti sa njegovim programerom. Budite oprezni: ovaj snimak dinamičkog dijela memorije može sadržavati vaše lične podatke kojima aplikacija ima pristup."</string>
+ <string name="sendText" msgid="5209874571959469142">"Biranje akcije za tekst"</string>
+ <string name="volume_ringtone" msgid="6885421406845734650">"Jačina zvuka zvona"</string>
+ <string name="volume_music" msgid="5421651157138628171">"Jačina zvuka za medijske sadržaje"</string>
+ <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Medijski sadržaj se reproducira preko Bluetooth veze"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Postavljena nečujna melodija zvona"</string>
+ <string name="volume_call" msgid="3941680041282788711">"Jačina zvuka tokom poziva"</string>
+ <string name="volume_bluetooth_call" msgid="2002891926351151534">"Jačina zvuka tokom poziva preko Bluetooth veze"</string>
+ <string name="volume_alarm" msgid="1985191616042689100">"Jačina zvuka alarma"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"Jačina zvuka za obavještenja"</string>
+ <string name="volume_unknown" msgid="1400219669770445902">"Jačina zvuka"</string>
+ <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Jačina zvuka za Bluetooth vezu"</string>
+ <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Jačina zvuka melodije"</string>
+ <string name="volume_icon_description_incall" msgid="8890073218154543397">"Jačina zvuka tokom poziva"</string>
+ <string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka za medijske sadržaje"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka za obavještenja"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
+ <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Zadano zvono (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent" msgid="7937634392408977062">"Ne poduzimaj ništa"</string>
+ <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
+ <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznato zvono"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Wi-Fi mreže su dostupne</item>
+ <item quantity="few">Wi-Fi mreže su dostupne</item>
+ <item quantity="other">Wi-Fi mreže su dostupne</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
+ </plurals>
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1848877297365446605">"Prijavite se na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <!-- no translation found for wifi_no_internet (8451173622563841546) -->
- <skip />
- <!-- no translation found for wifi_no_internet_detailed (7593858887662270131) -->
- <skip />
- <!-- no translation found for wifi_watchdog_network_disabled (7904214231651546347) -->
- <skip />
- <!-- no translation found for wifi_watchdog_network_disabled_detailed (5548780776418332675) -->
- <skip />
- <!-- no translation found for wifi_connect_alert_title (8455846016001810172) -->
- <skip />
- <!-- no translation found for wifi_connect_alert_message (6451273376815958922) -->
- <skip />
- <!-- no translation found for wifi_connect_default_application (7143109390475484319) -->
- <skip />
- <!-- no translation found for wifi_p2p_dialog_title (97611782659324517) -->
- <skip />
- <!-- no translation found for wifi_p2p_turnon_message (2909250942299627244) -->
- <skip />
- <!-- no translation found for wifi_p2p_failed_message (3763669677935623084) -->
- <skip />
- <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
- <skip />
- <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
- <skip />
- <!-- no translation found for accept (1645267259272829559) -->
- <skip />
- <!-- no translation found for decline (2112225451706137894) -->
- <skip />
- <!-- no translation found for wifi_p2p_invitation_sent_title (1318975185112070734) -->
- <skip />
- <!-- no translation found for wifi_p2p_invitation_to_connect_title (4958803948658533637) -->
- <skip />
- <!-- no translation found for wifi_p2p_from_message (570389174731951769) -->
- <skip />
- <!-- no translation found for wifi_p2p_to_message (248968974522044099) -->
- <skip />
- <!-- no translation found for wifi_p2p_enter_pin_message (5920929550367828970) -->
- <skip />
- <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
- <skip />
- <!-- no translation found for wifi_p2p_frequency_conflict_message (8012981257742232475) -->
- <skip />
- <!-- no translation found for wifi_p2p_frequency_conflict_message (3087858235069421128) -->
- <skip />
- <!-- no translation found for wifi_p2p_frequency_conflict_message (7363907213787469151) -->
- <skip />
- <!-- no translation found for select_character (3365550120617701745) -->
- <skip />
- <!-- no translation found for sms_control_title (7296612781128917719) -->
- <skip />
- <!-- no translation found for sms_control_message (3867899169651496433) -->
- <skip />
- <!-- no translation found for sms_control_yes (3663725993855816807) -->
- <skip />
- <!-- no translation found for sms_control_no (625438561395534982) -->
- <skip />
- <!-- no translation found for sms_short_code_confirm_message (1645436466285310855) -->
- <skip />
- <!-- no translation found for sms_short_code_details (5873295990846059400) -->
- <skip />
- <!-- no translation found for sms_premium_short_code_details (7869234868023975) -->
- <skip />
- <!-- no translation found for sms_short_code_confirm_allow (4458878637111023413) -->
- <skip />
- <!-- no translation found for sms_short_code_confirm_deny (2927389840209170706) -->
- <skip />
- <!-- no translation found for sms_short_code_remember_choice (5289538592272218136) -->
- <skip />
- <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
- <skip />
- <!-- no translation found for sms_short_code_confirm_always_allow (3241181154869493368) -->
- <skip />
- <!-- no translation found for sms_short_code_confirm_never_allow (446992765774269673) -->
- <skip />
- <!-- no translation found for sim_removed_title (6227712319223226185) -->
- <skip />
- <!-- no translation found for sim_removed_message (5450336489923274918) -->
- <skip />
- <!-- no translation found for sim_done_button (827949989369963775) -->
- <skip />
- <!-- no translation found for sim_added_title (3719670512889674693) -->
- <skip />
- <!-- no translation found for sim_added_message (7797975656153714319) -->
- <skip />
- <!-- no translation found for sim_restart_button (4722407842815232347) -->
- <skip />
+ <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup Internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="7593858887662270131">"Dodirnite za opcije"</string>
+ <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na Wi-Fi mrežu"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
+ <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
+ <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s se želi povezati na Wi-Fi mrežu %2$s"</string>
+ <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni Wi-Fi Direct. To će isključiti Wi-Fi klijenta/pristupnu tačku."</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Greška u pokretanju opcije Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je uključen"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string>
+ <string name="accept" msgid="1645267259272829559">"Prihvati"</string>
+ <string name="decline" msgid="2112225451706137894">"Odbijte"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica poslana"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Poziv za povezivanje"</string>
+ <string name="wifi_p2p_from_message" msgid="570389174731951769">"Pošiljalac:"</string>
+ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Primalac:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Unesite potrebni PIN:"</string>
+ <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet će privremeno prekinuti Wi-Fi vezu dok bude povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"TV će privremeno prekinuti Wi-Fi vezu dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon će privremeno prekinuti Wi-Fi vezu dok bude povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="select_character" msgid="3365550120617701745">"Umetni karakter"</string>
+ <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje veliki broj SMS poruka. Da li želite dozvoliti ovoj aplikaciji da nastavi slanje poruka?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Dozvoli"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Odbij"</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; želi poslati poruku na adresu &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
+ <string name="sms_short_code_details" msgid="5873295990846059400">"Ovo "<b>"može uzrokovati troškove"</b>" na vašem računu za mobilne usluge."</string>
+ <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Ovo će uzrokovati troškove na vašem računu za mobilne usluge."</b></string>
+ <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Pošalji"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Otkaži"</string>
+ <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Zapamti moj izbor"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Ovo možete kasnije promijeniti u meniju Postavke &gt; Aplikacije"</string>
+ <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Uvijek dozvoli"</string>
+ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nikada ne dozvoli"</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"SIM kartica uklonjena"</string>
+ <string name="sim_removed_message" msgid="5450336489923274918">"Mobilna mreža neće biti dostupna dok ponovo ne pokrenete uređaj s umetnutom važećom SIM karticom."</string>
+ <string name="sim_done_button" msgid="827949989369963775">"Gotovo"</string>
+ <string name="sim_added_title" msgid="3719670512889674693">"SIM kartica dodana"</string>
+ <string name="sim_added_message" msgid="7797975656153714319">"Ponovo pokrenite uređaj da pristupite mobilnoj mreži."</string>
+ <string name="sim_restart_button" msgid="4722407842815232347">"Ponovo pokreni"</string>
<string name="carrier_app_dialog_message" msgid="7066156088266319533">"Da bi nova SIM kartica ispravno radila, morate instalirati i otvoriti aplikaciju svog operatera."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"PREUZMI APLIKACIJU"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NE SADA"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Nova SIM kartica je umetnuta"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Dodirnite da biste postavili"</string>
- <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
- <skip />
- <!-- no translation found for date_picker_dialog_title (5879450659453782278) -->
- <skip />
- <!-- no translation found for date_time_set (5777075614321087758) -->
- <skip />
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
- <!-- no translation found for perms_new_perm_prefix (8257740710754301407) -->
- <skip />
- <!-- no translation found for perms_description_app (5139836143293299417) -->
- <skip />
- <!-- no translation found for no_permissions (7283357728219338112) -->
- <skip />
- <!-- no translation found for perm_costs_money (4902470324142151116) -->
- <skip />
- <!-- no translation found for dlg_ok (7376953167039865701) -->
- <skip />
- <!-- no translation found for usb_charging_notification_title (4004114449249406402) -->
- <skip />
- <!-- no translation found for usb_mtp_notification_title (8396264943589760855) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1347328437083192112) -->
- <skip />
- <!-- no translation found for usb_midi_notification_title (4850904915889144654) -->
- <skip />
- <!-- no translation found for usb_accessory_notification_title (7848236974087653666) -->
- <skip />
- <!-- no translation found for usb_notification_message (7347368030849048437) -->
- <skip />
- <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
- <skip />
- <!-- no translation found for adb_active_notification_message (1016654627626476142) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_notification_title (3116061729914615290) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_notification_message (1310517845557771773) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_notification_accept (8203856129078669677) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_notification_decline (6337969352057443969) -->
- <skip />
- <!-- no translation found for remote_bugreport_progress_notification_title (2785600634417078622) -->
- <skip />
- <!-- no translation found for remote_bugreport_progress_notification_message_can_cancel (5743435483005099451) -->
- <skip />
- <!-- no translation found for select_input_method (8547250819326693584) -->
- <skip />
- <!-- no translation found for configure_input_methods (4769971288371946846) -->
- <skip />
- <!-- no translation found for show_ime (2506087537466597099) -->
- <skip />
- <!-- no translation found for hardware (194658061510127999) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
- <skip />
- <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
- <skip />
- <!-- no translation found for fast_scroll_alphabet (5433275485499039199) -->
- <skip />
- <!-- no translation found for fast_scroll_numeric_alphabet (4030170524595123610) -->
- <skip />
- <!-- no translation found for candidates_style (4333913089637062257) -->
- <skip />
- <!-- no translation found for ext_media_checking_notification_title (5734005953288045806) -->
- <skip />
- <!-- no translation found for ext_media_checking_notification_message (4747432538578886744) -->
- <skip />
- <!-- no translation found for ext_media_new_notification_message (7589986898808506239) -->
- <skip />
- <!-- no translation found for ext_media_ready_notification_message (4083398150380114462) -->
- <skip />
- <!-- no translation found for ext_media_unmountable_notification_title (8295123366236989588) -->
- <skip />
- <!-- no translation found for ext_media_unmountable_notification_message (1586311304430052169) -->
- <skip />
- <!-- no translation found for ext_media_unsupported_notification_title (3797642322958803257) -->
- <skip />
- <!-- no translation found for ext_media_unsupported_notification_message (8789610369456474891) -->
- <skip />
- <!-- no translation found for ext_media_badremoval_notification_title (3206248947375505416) -->
- <skip />
- <!-- no translation found for ext_media_badremoval_notification_message (380176703346946313) -->
- <skip />
- <!-- no translation found for ext_media_nomedia_notification_title (1704840188641749091) -->
- <skip />
- <!-- no translation found for ext_media_nomedia_notification_message (6471542972147056586) -->
- <skip />
- <!-- no translation found for ext_media_unmounting_notification_title (640674168454809372) -->
- <skip />
- <!-- no translation found for ext_media_unmounting_notification_message (4182843895023357756) -->
- <skip />
- <!-- no translation found for ext_media_init_action (7952885510091978278) -->
- <skip />
- <!-- no translation found for ext_media_unmount_action (1121883233103278199) -->
- <skip />
- <!-- no translation found for ext_media_browse_action (8322172381028546087) -->
- <skip />
- <!-- no translation found for ext_media_missing_title (620980315821543904) -->
- <skip />
- <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
- <skip />
- <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
- <skip />
- <!-- no translation found for ext_media_move_title (1022809140035962662) -->
- <skip />
- <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
- <skip />
- <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
- <skip />
- <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
- <skip />
- <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
- <skip />
- <!-- no translation found for ext_media_status_removed (6576172423185918739) -->
- <skip />
- <!-- no translation found for ext_media_status_unmounted (2551560878416417752) -->
- <skip />
- <!-- no translation found for ext_media_status_checking (6193921557423194949) -->
- <skip />
- <!-- no translation found for ext_media_status_mounted (7253821726503179202) -->
- <skip />
- <!-- no translation found for ext_media_status_mounted_ro (8020978752406021015) -->
- <skip />
- <!-- no translation found for ext_media_status_bad_removal (8395398567890329422) -->
- <skip />
- <!-- no translation found for ext_media_status_unmountable (805594039236667894) -->
- <skip />
- <!-- no translation found for ext_media_status_unsupported (4691436711745681828) -->
- <skip />
- <!-- no translation found for ext_media_status_ejecting (5463887263101234174) -->
- <skip />
- <!-- no translation found for ext_media_status_formatting (1085079556538644861) -->
- <skip />
- <!-- no translation found for ext_media_status_missing (5638633895221670766) -->
- <skip />
- <!-- no translation found for activity_list_empty (1675388330786841066) -->
- <skip />
- <!-- no translation found for permlab_route_media_output (6243022988998972085) -->
- <skip />
- <!-- no translation found for permdesc_route_media_output (4932818749547244346) -->
- <skip />
- <!-- no translation found for permlab_readInstallSessions (3713753067455750349) -->
- <skip />
- <!-- no translation found for permdesc_readInstallSessions (2049771699626019849) -->
- <skip />
- <!-- no translation found for permlab_requestInstallPackages (5782013576218172577) -->
- <skip />
- <!-- no translation found for permdesc_requestInstallPackages (5740101072486783082) -->
- <skip />
- <!-- no translation found for tutorial_double_tap_to_zoom_message_short (4070433208160063538) -->
- <skip />
- <!-- no translation found for gadget_host_error_inflating (4882004314906466162) -->
- <skip />
- <!-- no translation found for ime_action_go (8320845651737369027) -->
- <skip />
- <!-- no translation found for ime_action_search (658110271822807811) -->
- <skip />
- <!-- no translation found for ime_action_send (2316166556349314424) -->
- <skip />
- <!-- no translation found for ime_action_next (3138843904009813834) -->
- <skip />
- <!-- no translation found for ime_action_done (8971516117910934605) -->
- <skip />
- <!-- no translation found for ime_action_previous (1443550039250105948) -->
- <skip />
- <!-- no translation found for ime_action_default (2840921885558045721) -->
- <skip />
- <!-- no translation found for dial_number_using (5789176425167573586) -->
- <skip />
- <!-- no translation found for create_contact_using (4947405226788104538) -->
- <skip />
- <!-- no translation found for grant_credentials_permission_message_header (2106103817937859662) -->
- <skip />
- <!-- no translation found for grant_credentials_permission_message_footer (3125211343379376561) -->
- <skip />
- <!-- no translation found for grant_permissions_header_text (6874497408201826708) -->
- <skip />
- <!-- no translation found for allow (7225948811296386551) -->
- <skip />
- <!-- no translation found for deny (2081879885755434506) -->
- <skip />
- <!-- no translation found for permission_request_notification_title (6486759795926237907) -->
- <skip />
- <!-- no translation found for permission_request_notification_with_subtitle (8530393139639560189) -->
- <skip />
- <!-- no translation found for forward_intent_to_owner (1207197447013960896) -->
- <skip />
- <!-- no translation found for forward_intent_to_work (621480743856004612) -->
- <skip />
- <!-- no translation found for input_method_binding_label (1283557179944992649) -->
- <skip />
- <!-- no translation found for sync_binding_label (3687969138375092423) -->
- <skip />
- <!-- no translation found for accessibility_binding_label (4148120742096474641) -->
- <skip />
- <!-- no translation found for wallpaper_binding_label (1240087844304687662) -->
- <skip />
- <!-- no translation found for chooser_wallpaper (7873476199295190279) -->
- <skip />
- <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
- <skip />
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
- <!-- no translation found for notification_assistant_binding_label (909456055569102952) -->
- <skip />
- <!-- no translation found for vpn_title (19615213552042827) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
- <!-- no translation found for vpn_text (3011306607126450322) -->
- <skip />
- <!-- no translation found for vpn_text_long (6407351006249174473) -->
- <skip />
- <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
- <skip />
- <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
- <skip />
- <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
- <skip />
- <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
- <skip />
- <!-- no translation found for upload_file (2897957172366730416) -->
- <skip />
- <!-- no translation found for no_file_chosen (6363648562170759465) -->
- <skip />
- <!-- no translation found for reset (2448168080964209908) -->
- <skip />
- <!-- no translation found for submit (1602335572089911941) -->
- <skip />
- <!-- no translation found for car_mode_disable_notification_title (3164768212003864316) -->
- <skip />
- <!-- no translation found for car_mode_disable_notification_message (8035230537563503262) -->
- <skip />
- <!-- no translation found for tethered_notification_title (3146694234398202601) -->
- <skip />
- <!-- no translation found for tethered_notification_message (6857031760103062982) -->
- <skip />
- <!-- no translation found for back_button_label (2300470004503343439) -->
- <skip />
- <!-- no translation found for next_button_label (1080555104677992408) -->
- <skip />
- <!-- no translation found for skip_button_label (1275362299471631819) -->
- <skip />
- <!-- no translation found for no_matches (8129421908915840737) -->
- <skip />
- <!-- no translation found for find_on_page (1946799233822820384) -->
- <skip />
- <!-- no translation found for matches_found (1210884353962081884) -->
- <!-- no translation found for action_mode_done (7217581640461922289) -->
- <skip />
- <!-- no translation found for progress_erasing (4521573321524340058) -->
- <skip />
- <!-- no translation found for progress_erasing (6596988875507043042) -->
- <skip />
- <!-- no translation found for share (1778686618230011964) -->
- <skip />
- <!-- no translation found for find (4808270900322985960) -->
- <skip />
- <!-- no translation found for websearch (4337157977400211589) -->
- <skip />
- <!-- no translation found for find_next (5742124618942193978) -->
- <skip />
- <!-- no translation found for find_previous (2196723669388360506) -->
- <skip />
- <!-- no translation found for gpsNotifTicker (5622683912616496172) -->
- <skip />
- <!-- no translation found for gpsNotifTitle (5446858717157416839) -->
- <skip />
- <!-- no translation found for gpsNotifMessage (1374718023224000702) -->
- <skip />
- <!-- no translation found for gpsVerifYes (2346566072867213563) -->
- <skip />
- <!-- no translation found for gpsVerifNo (1146564937346454865) -->
- <skip />
- <!-- no translation found for sync_too_many_deletes (5296321850662746890) -->
- <skip />
- <!-- no translation found for sync_too_many_deletes_desc (496551671008694245) -->
- <skip />
- <!-- no translation found for sync_really_delete (2572600103122596243) -->
- <skip />
- <!-- no translation found for sync_undo_deletes (2941317360600338602) -->
- <skip />
- <!-- no translation found for sync_do_nothing (3743764740430821845) -->
- <skip />
- <!-- no translation found for choose_account_label (5655203089746423927) -->
- <skip />
- <!-- no translation found for add_account_label (2935267344849993553) -->
- <skip />
- <!-- no translation found for add_account_button_label (3611982894853435874) -->
- <skip />
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
- <!-- no translation found for number_picker_increment_scroll_mode (3073101067441638428) -->
- <skip />
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
- <!-- no translation found for time_picker_increment_set_pm_button (4147590696151230863) -->
- <skip />
- <!-- no translation found for time_picker_decrement_set_am_button (8302140353539486752) -->
- <skip />
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
- <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
- <skip />
- <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_alt (4856868820040051939) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_cancel (1203984017245783244) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_delete (3337914833206635744) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_done (1992571118466679775) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_mode_change (4547387741906537519) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_shift (2270748814315147690) -->
- <skip />
- <!-- no translation found for keyboardview_keycode_enter (2985864015076059467) -->
- <skip />
- <!-- no translation found for activitychooserview_choose_application (2125168057199941199) -->
- <skip />
- <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
- <skip />
- <!-- no translation found for shareactionprovider_share_with (806688056141131819) -->
- <skip />
- <!-- no translation found for shareactionprovider_share_with_application (5627411384638389738) -->
- <skip />
- <!-- no translation found for content_description_sliding_handle (415975056159262248) -->
- <skip />
- <!-- no translation found for description_target_unlock_tablet (3833195335629795055) -->
- <skip />
- <!-- no translation found for keyboard_headset_required_to_hear_password (7011927352267668657) -->
- <skip />
- <!-- no translation found for keyboard_password_character_no_headset (2859873770886153678) -->
- <skip />
- <!-- no translation found for action_bar_home_description (5293600496601490216) -->
- <skip />
- <!-- no translation found for action_bar_up_description (2237496562952152589) -->
- <skip />
- <!-- no translation found for action_menu_overflow_description (2295659037509008453) -->
- <skip />
- <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
- <skip />
- <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
- <skip />
- <!-- no translation found for storage_internal (4891916833657929263) -->
- <skip />
- <!-- no translation found for storage_sd_card (3282948861378286745) -->
- <skip />
- <!-- no translation found for storage_sd_card_label (6347111320774379257) -->
- <skip />
- <!-- no translation found for storage_usb_drive (6261899683292244209) -->
- <skip />
- <!-- no translation found for storage_usb_drive_label (4501418548927759953) -->
- <skip />
- <!-- no translation found for storage_usb (3017954059538517278) -->
- <skip />
- <!-- no translation found for extract_edit_menu_button (8940478730496610137) -->
- <skip />
- <!-- no translation found for data_usage_warning_title (1955638862122232342) -->
- <skip />
- <!-- no translation found for data_usage_warning_body (2814673551471969954) -->
- <skip />
- <!-- no translation found for data_usage_3g_limit_title (4361523876818447683) -->
- <skip />
- <!-- no translation found for data_usage_4g_limit_title (4609566827219442376) -->
- <skip />
- <!-- no translation found for data_usage_mobile_limit_title (557158376602636112) -->
- <skip />
- <!-- no translation found for data_usage_wifi_limit_title (5803363779034792676) -->
- <skip />
- <!-- no translation found for data_usage_limit_body (291731708279614081) -->
- <skip />
- <!-- no translation found for data_usage_3g_limit_snoozed_title (7026739121138005231) -->
- <skip />
- <!-- no translation found for data_usage_4g_limit_snoozed_title (1106562779311209039) -->
- <skip />
- <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
- <skip />
- <!-- no translation found for data_usage_wifi_limit_snoozed_title (8743856006384825974) -->
- <skip />
- <!-- no translation found for data_usage_limit_snoozed_body (7035490278298441767) -->
- <skip />
- <!-- no translation found for data_usage_restricted_title (5965157361036321914) -->
- <skip />
- <!-- no translation found for data_usage_restricted_body (6741521330997452990) -->
- <skip />
- <!-- no translation found for ssl_certificate (6510040486049237639) -->
- <skip />
- <!-- no translation found for ssl_certificate_is_valid (6825263250774569373) -->
- <skip />
- <!-- no translation found for issued_to (454239480274921032) -->
- <skip />
- <!-- no translation found for common_name (2233209299434172646) -->
- <skip />
- <!-- no translation found for org_name (6973561190762085236) -->
- <skip />
- <!-- no translation found for org_unit (7265981890422070383) -->
- <skip />
- <!-- no translation found for issued_by (2647584988057481566) -->
- <skip />
- <!-- no translation found for validity_period (8818886137545983110) -->
- <skip />
- <!-- no translation found for issued_on (5895017404361397232) -->
- <skip />
- <!-- no translation found for expires_on (3676242949915959821) -->
- <skip />
- <!-- no translation found for serial_number (758814067660862493) -->
- <skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (4292569383976636200) -->
- <skip />
- <!-- no translation found for activity_chooser_view_dialog_title_default (4710013864974040615) -->
- <skip />
- <!-- no translation found for share_action_provider_share_with (5247684435979149216) -->
- <skip />
- <!-- no translation found for sending (3245653681008218030) -->
- <skip />
- <!-- no translation found for launchBrowserDefault (2057951947297614725) -->
- <skip />
- <!-- no translation found for SetupCallDefault (5834948469253758575) -->
- <skip />
- <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
- <skip />
- <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
- <skip />
- <!-- no translation found for activity_resolver_work_profiles_support (185598180676883455) -->
- <skip />
- <!-- no translation found for default_audio_route_name (4617053898167127471) -->
- <skip />
- <!-- no translation found for default_audio_route_name (9158088547603019321) -->
- <skip />
- <!-- no translation found for default_audio_route_name (4239291273420140123) -->
- <skip />
- <!-- no translation found for default_audio_route_name_headphones (8119971843803439110) -->
- <skip />
- <!-- no translation found for default_audio_route_name_dock_speakers (6240602982276591864) -->
- <skip />
- <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
- <skip />
- <!-- no translation found for default_audio_route_category_name (3722811174003886946) -->
- <skip />
- <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
- <skip />
- <!-- no translation found for wireless_display_route_description (9070346425023979651) -->
- <skip />
- <!-- no translation found for media_route_button_content_description (591703006349356016) -->
- <skip />
- <!-- no translation found for media_route_chooser_title (1751618554539087622) -->
- <skip />
- <!-- no translation found for media_route_chooser_title_for_remote_display (3395541745872017583) -->
- <skip />
- <!-- no translation found for media_route_chooser_searching (4776236202610828706) -->
- <skip />
- <!-- no translation found for media_route_chooser_extended_settings (87015534236701604) -->
- <skip />
- <!-- no translation found for media_route_controller_disconnect (8966120286374158649) -->
- <skip />
- <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
- <skip />
- <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
- <skip />
- <!-- no translation found for media_route_status_available (6983258067194649391) -->
- <skip />
- <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
- <skip />
- <!-- no translation found for media_route_status_in_use (4533786031090198063) -->
- <skip />
- <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
- <skip />
- <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
- <skip />
- <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
- <skip />
- <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
- <skip />
- <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
- <skip />
- <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
- <skip />
- <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
- <skip />
- <!-- no translation found for kg_wrong_password (2333281762128113157) -->
- <skip />
- <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
- <skip />
- <!-- no translation found for kg_too_many_failed_attempts_countdown (6358110221603297548) -->
- <skip />
- <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
- <skip />
- <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
- <skip />
- <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
- <skip />
- <!-- no translation found for kg_password_instructions (5753646556186936819) -->
- <skip />
- <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
- <skip />
- <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
- <skip />
- <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
- <skip />
- <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
- <skip />
- <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
- <skip />
- <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
- <skip />
- <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
- <skip />
- <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
- <skip />
- <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
- <skip />
- <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
- <skip />
- <!-- no translation found for kg_login_instructions (1100551261265506448) -->
- <skip />
- <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
- <skip />
- <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
- <skip />
- <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
- <skip />
- <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
- <skip />
- <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
- <skip />
- <!-- no translation found for kg_login_checking_password (1052685197710252395) -->
- <skip />
- <!-- no translation found for kg_too_many_failed_pin_attempts_dialog_message (8276745642049502550) -->
- <skip />
- <!-- no translation found for kg_too_many_failed_password_attempts_dialog_message (7813713389422226531) -->
- <skip />
- <!-- no translation found for kg_too_many_failed_pattern_attempts_dialog_message (74089475965050805) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_almost_at_wipe (1575557200627128949) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_almost_at_wipe (5621231220154419413) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_almost_at_wipe (4051015943038199910) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_now_wiping (2072996269148483637) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_now_wiping (4987878286750741463) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_now_wiping (4817627474419471518) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_almost_at_login (3253575572118914370) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_almost_at_login (4224651132862313471) -->
- <skip />
- <!-- no translation found for kg_failed_attempts_almost_at_login (1437638152015574839) -->
- <skip />
- <!-- no translation found for kg_text_message_separator (4160700433287233771) -->
- <skip />
- <!-- no translation found for kg_reordering_delete_drop_target_text (7899202978204438708) -->
- <skip />
- <!-- no translation found for safe_media_volume_warning (2276318909314492312) -->
- <skip />
- <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
- <skip />
- <!-- no translation found for accessibility_enabled (1381972048564547685) -->
- <skip />
- <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
- <skip />
- <!-- no translation found for user_switched (3768006783166984410) -->
- <skip />
- <!-- no translation found for user_switching_message (2871009331809089783) -->
- <skip />
- <!-- no translation found for user_logging_out_message (8939524935808875155) -->
- <skip />
- <!-- no translation found for owner_name (2716755460376028154) -->
- <!-- no translation found for owner_name (3879126011135546571) -->
- <skip />
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for error_message_change_not_allowed (1347282344200417578) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
- <!-- no translation found for revoke (5404479185228271586) -->
- <skip />
- <!-- no translation found for mediasize_iso_a0 (1994474252931294172) -->
- <skip />
- <!-- no translation found for mediasize_iso_a1 (3333060421529791786) -->
- <skip />
- <!-- no translation found for mediasize_iso_a2 (3097535991925798280) -->
- <skip />
- <!-- no translation found for mediasize_iso_a3 (3023213259314236123) -->
- <skip />
- <!-- no translation found for mediasize_iso_a4 (231745325296873764) -->
- <skip />
- <!-- no translation found for mediasize_iso_a5 (3484327407340865411) -->
- <skip />
- <!-- no translation found for mediasize_iso_a6 (4861908487129577530) -->
- <skip />
- <!-- no translation found for mediasize_iso_a7 (5890208588072936130) -->
- <skip />
- <!-- no translation found for mediasize_iso_a8 (4319425041085816612) -->
- <skip />
- <!-- no translation found for mediasize_iso_a9 (4882220529506432008) -->
- <skip />
- <!-- no translation found for mediasize_iso_a10 (2382866026365359391) -->
- <skip />
- <!-- no translation found for mediasize_iso_b0 (3651827147402009675) -->
- <skip />
- <!-- no translation found for mediasize_iso_b1 (6072859628278739957) -->
- <skip />
- <!-- no translation found for mediasize_iso_b2 (1348731852150380378) -->
- <skip />
- <!-- no translation found for mediasize_iso_b3 (2612510181259261379) -->
- <skip />
- <!-- no translation found for mediasize_iso_b4 (695151378838115434) -->
- <skip />
- <!-- no translation found for mediasize_iso_b5 (4863754285582212487) -->
- <skip />
- <!-- no translation found for mediasize_iso_b6 (5305816292139647241) -->
- <skip />
- <!-- no translation found for mediasize_iso_b7 (531673542602786624) -->
- <skip />
- <!-- no translation found for mediasize_iso_b8 (9164474595708850034) -->
- <skip />
- <!-- no translation found for mediasize_iso_b9 (282102976764774160) -->
- <skip />
- <!-- no translation found for mediasize_iso_b10 (4517141714407898976) -->
- <skip />
- <!-- no translation found for mediasize_iso_c0 (3103521357901591100) -->
- <skip />
- <!-- no translation found for mediasize_iso_c1 (1231954105985048595) -->
- <skip />
- <!-- no translation found for mediasize_iso_c2 (927702816980087462) -->
- <skip />
- <!-- no translation found for mediasize_iso_c3 (835154173518304159) -->
- <skip />
- <!-- no translation found for mediasize_iso_c4 (5095951985108194011) -->
- <skip />
- <!-- no translation found for mediasize_iso_c5 (1985397450332305739) -->
- <skip />
- <!-- no translation found for mediasize_iso_c6 (8147421924174693013) -->
- <skip />
- <!-- no translation found for mediasize_iso_c7 (8993994925276122950) -->
- <skip />
- <!-- no translation found for mediasize_iso_c8 (6871178104139598957) -->
- <skip />
- <!-- no translation found for mediasize_iso_c9 (7983532635227561362) -->
- <skip />
- <!-- no translation found for mediasize_iso_c10 (5040764293406765584) -->
- <skip />
- <!-- no translation found for mediasize_na_letter (2841414839888344296) -->
- <skip />
- <!-- no translation found for mediasize_na_gvrnmt_letter (5295836838862962809) -->
- <skip />
- <!-- no translation found for mediasize_na_legal (8621364037680465666) -->
- <skip />
- <!-- no translation found for mediasize_na_junior_legal (3309324162155085904) -->
- <skip />
- <!-- no translation found for mediasize_na_ledger (5567030340509075333) -->
- <skip />
- <!-- no translation found for mediasize_na_tabloid (4571735038501661757) -->
- <skip />
- <!-- no translation found for mediasize_na_index_3x5 (5182901917818625126) -->
- <skip />
- <!-- no translation found for mediasize_na_index_4x6 (7687620625422312396) -->
- <skip />
- <!-- no translation found for mediasize_na_index_5x8 (8834215284646872800) -->
- <skip />
- <!-- no translation found for mediasize_na_monarch (213639906956550754) -->
- <skip />
- <!-- no translation found for mediasize_na_quarto (835778493593023223) -->
- <skip />
- <!-- no translation found for mediasize_na_foolscap (1573911237983677138) -->
- <skip />
- <!-- no translation found for mediasize_chinese_roc_8k (3626855847189438896) -->
- <skip />
- <!-- no translation found for mediasize_chinese_roc_16k (9182191577022943355) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_1 (4793232644980170500) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_2 (5404109730975720670) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_3 (1335092253339363526) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_4 (9167997800486569834) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_5 (845875168823541497) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_6 (3220325667692648789) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_7 (1776792138507038527) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_8 (1417176642687456692) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_9 (4785983473123798365) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_10 (7847982299391851899) -->
- <skip />
- <!-- no translation found for mediasize_chinese_prc_16k (262793383539980677) -->
- <skip />
- <!-- no translation found for mediasize_chinese_om_pa_kai (5256815579447959814) -->
- <skip />
- <!-- no translation found for mediasize_chinese_om_dai_pa_kai (7336412963441354407) -->
- <skip />
- <!-- no translation found for mediasize_chinese_om_jurro_ku_kai (6324465444100490742) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b10 (1787262845627694376) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b9 (3336035783663287470) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b8 (6195398299104345731) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b7 (1674621886902828884) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b6 (4170576286062657435) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b5 (4899297958100032533) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b4 (4213158129126666847) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b3 (8513715307410310696) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b2 (4777690211897131190) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b1 (4608142385457034603) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_b0 (7587108366572243991) -->
- <skip />
- <!-- no translation found for mediasize_japanese_jis_exec (5244075432263649068) -->
- <skip />
- <!-- no translation found for mediasize_japanese_chou4 (4941652015032631361) -->
- <skip />
- <!-- no translation found for mediasize_japanese_chou3 (6387319169263957010) -->
- <skip />
- <!-- no translation found for mediasize_japanese_chou2 (1299112025415343982) -->
- <skip />
- <!-- no translation found for mediasize_japanese_hagaki (8070115620644254565) -->
- <skip />
- <!-- no translation found for mediasize_japanese_oufuku (6049065587307896564) -->
- <skip />
- <!-- no translation found for mediasize_japanese_kahu (6872696027560065173) -->
- <skip />
- <!-- no translation found for mediasize_japanese_kaku2 (2359077233775455405) -->
- <skip />
- <!-- no translation found for mediasize_japanese_you4 (2091777168747058008) -->
- <skip />
- <!-- no translation found for mediasize_unknown_portrait (3088043641616409762) -->
- <skip />
- <!-- no translation found for mediasize_unknown_landscape (4876995327029361552) -->
- <skip />
- <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
- <skip />
- <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
- <skip />
- <!-- no translation found for reason_unknown (6048913880184628119) -->
- <skip />
- <!-- no translation found for reason_service_unavailable (7824008732243903268) -->
- <skip />
- <!-- no translation found for print_service_installed_title (2246317169444081628) -->
- <skip />
- <!-- no translation found for print_service_installed_message (5897362931070459152) -->
- <skip />
- <!-- no translation found for restr_pin_enter_admin_pin (783643731895143970) -->
- <skip />
- <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
- <skip />
- <!-- no translation found for restr_pin_incorrect (8571512003955077924) -->
- <skip />
- <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
- <skip />
- <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
- <skip />
- <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
- <skip />
- <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
- <skip />
- <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
- <skip />
- <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
- <skip />
- <!-- no translation found for restr_pin_countdown (9061246974881224688) -->
- <!-- no translation found for restr_pin_try_later (973144472490532377) -->
- <skip />
- <!-- no translation found for immersive_cling_title (8394201622932303336) -->
- <skip />
- <!-- no translation found for immersive_cling_description (3482371193207536040) -->
- <skip />
- <!-- no translation found for immersive_cling_positive (5016839404568297683) -->
- <skip />
- <!-- no translation found for done_label (2093726099505892398) -->
- <skip />
- <!-- no translation found for hour_picker_description (6698199186859736512) -->
- <skip />
- <!-- no translation found for minute_picker_description (8606010966873791190) -->
- <skip />
- <!-- no translation found for select_hours (6043079511766008245) -->
- <skip />
- <!-- no translation found for select_minutes (3974345615920336087) -->
- <skip />
- <!-- no translation found for select_day (7774759604701773332) -->
- <skip />
- <!-- no translation found for select_year (7952052866994196170) -->
- <skip />
- <!-- no translation found for deleted_key (7659477886625566590) -->
- <skip />
- <!-- no translation found for managed_profile_label_badge (2355652472854327647) -->
- <skip />
- <!-- no translation found for lock_to_app_toast (7570091317001980053) -->
- <skip />
- <!-- no translation found for lock_to_app_toast_accessible (8239120109365070664) -->
- <skip />
- <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
- <skip />
- <!-- no translation found for lock_to_app_start (6643342070839862795) -->
- <skip />
- <!-- no translation found for lock_to_app_exit (8598219838213787430) -->
- <skip />
- <!-- no translation found for lock_to_app_unlock_pin (2552556656504331634) -->
- <skip />
- <!-- no translation found for lock_to_app_unlock_pattern (4182192144797225137) -->
- <skip />
- <!-- no translation found for lock_to_app_unlock_password (6380979775916974414) -->
- <skip />
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veličina aplikacije nije promjenjiva, pomičite je s dva prsta."</string>
+ <string name="time_picker_dialog_title" msgid="8349362623068819295">"Postavljanje vremena"</string>
+ <string name="date_picker_dialog_title" msgid="5879450659453782278">"Postavljanje datuma"</string>
+ <string name="date_time_set" msgid="5777075614321087758">"Postaviti"</string>
+ <string name="date_time_done" msgid="2507683751759308828">"Završeno"</string>
+ <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NOVO: "</font></string>
+ <string name="perms_description_app" msgid="5139836143293299417">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> omogućava."</string>
+ <string name="no_permissions" msgid="7283357728219338112">"Nisu potrebne dozvole"</string>
+ <string name="perm_costs_money" msgid="4902470324142151116">"ovo se možda dodatno plaća"</string>
+ <string name="dlg_ok" msgid="7376953167039865701">"Uredu"</string>
+ <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+ <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos fajlova"</string>
+ <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos slika"</string>
+ <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
+ <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Uspostavljena veza sa USB pohranom"</string>
+ <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"Uređaj za USB otklanjanje grešaka povezan"</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili USB otklanjanje grešaka."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Vaš IT administrator je zatražio izvještaj o grešci kako bi pomogao riješiti problem na ovom uređaju. To može uzrokovati dijeljenje aplikacija i podataka te privremeno usporiti vaš uređaj."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Vaš IT administrator je zatražio izvještaj o grešci kako bi pomogao u rješavanju problema ovog uređaja. Aplikacije i podaci se mogu dijeliti."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"To može privremeno usporiti vaš uređaj"</string>
+ <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
+ <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBACI"</string>
+ <string name="select_input_method" msgid="8547250819326693584">"Promijeni tastaturu"</string>
+ <string name="configure_input_methods" msgid="4769971288371946846">"Odaberite tastature"</string>
+ <string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
+ <string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tastaturu"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite raspored tastature"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir rasporeda tastature."</string>
+ <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
+ <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema se <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Provjera grešaka"</string>
+ <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
+ <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Za prebacivanje slika i medijskih fajlova"</string>
+ <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen"</string>
+ <string name="ext_media_unmountable_notification_message" msgid="1586311304430052169">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen. Dodirnite da ga popravite."</string>
+ <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"Uređaj <xliff:g id="NAME">%s</xliff:g> nije podržan"</string>
+ <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"Ovaj uređaj ne podržava uređaj <xliff:g id="NAME">%s</xliff:g>. Dodirnite da ga postavite u podržanom formatu."</string>
+ <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Neočekivano uklonjen uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Isključite uređaj <xliff:g id="NAME">%s</xliff:g> prije uklanjanja da izbjegnete gubitak podataka"</string>
+ <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"Uređaj <xliff:g id="NAME">%s</xliff:g> je uklonjen"</string>
+ <string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"Uređaj <xliff:g id="NAME">%s</xliff:g> je uklonjen, umetnite novi"</string>
+ <string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"Još uvijek se izbacuje <xliff:g id="NAME">%s</xliff:g>…"</string>
+ <string name="ext_media_unmounting_notification_message" msgid="4182843895023357756">"Ne uklanjajte"</string>
+ <string name="ext_media_init_action" msgid="7952885510091978278">"Postavi"</string>
+ <string name="ext_media_unmount_action" msgid="1121883233103278199">"Izbaci"</string>
+ <string name="ext_media_browse_action" msgid="8322172381028546087">"Istraži"</string>
+ <string name="ext_media_missing_title" msgid="620980315821543904">"<xliff:g id="NAME">%s</xliff:g> nedostaje"</string>
+ <string name="ext_media_missing_message" msgid="5761133583368750174">"Ponovo umetnite ovaj uređaj"</string>
+ <string name="ext_media_move_specific_title" msgid="1471100343872375842">"Premješta se <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_move_title" msgid="1022809140035962662">"Premještanje podataka"</string>
+ <string name="ext_media_move_success_title" msgid="8575300932957954671">"Premještanje je završeno"</string>
+ <string name="ext_media_move_success_message" msgid="4199002148206265426">"Podaci su premješteni na uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_move_failure_title" msgid="7613189040358789908">"Podaci se ne mogu premjestiti"</string>
+ <string name="ext_media_move_failure_message" msgid="1978096440816403360">"Podaci su ostali na prvobitnoj lokaciji"</string>
+ <string name="ext_media_status_removed" msgid="6576172423185918739">"Uređaj je uklonjen"</string>
+ <string name="ext_media_status_unmounted" msgid="2551560878416417752">"Uređaj je izbačen"</string>
+ <string name="ext_media_status_checking" msgid="6193921557423194949">"Provjerava se..."</string>
+ <string name="ext_media_status_mounted" msgid="7253821726503179202">"Uređaj je spreman"</string>
+ <string name="ext_media_status_mounted_ro" msgid="8020978752406021015">"Samo za čitanje"</string>
+ <string name="ext_media_status_bad_removal" msgid="8395398567890329422">"Uređaj je uklonjen na nebezbjedan način"</string>
+ <string name="ext_media_status_unmountable" msgid="805594039236667894">"Uređaj je oštećen"</string>
+ <string name="ext_media_status_unsupported" msgid="4691436711745681828">"Uređaj nije podržan"</string>
+ <string name="ext_media_status_ejecting" msgid="5463887263101234174">"Izbacuje se..."</string>
+ <string name="ext_media_status_formatting" msgid="1085079556538644861">"Formatira se..."</string>
+ <string name="ext_media_status_missing" msgid="5638633895221670766">"Uređaj nije ubačen"</string>
+ <string name="activity_list_empty" msgid="1675388330786841066">"Nije pronađena nijedna odgovarajuća aktivnost."</string>
+ <string name="permlab_route_media_output" msgid="6243022988998972085">"usmjeravanje izlaza za medijske fajlove"</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"Omogućava aplikaciji usmjeravanje izlaza sa medija na druge vanjske uređaje."</string>
+ <string name="permlab_readInstallSessions" msgid="3713753067455750349">"čitanje sesija instaliranja"</string>
+ <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="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput za kontrolu uvećavanja"</string>
+ <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Dodavanje vidžeta nije uspjelo."</string>
+ <string name="ime_action_go" msgid="8320845651737369027">"Počni"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"Traži"</string>
+ <string name="ime_action_send" msgid="2316166556349314424">"Poslati"</string>
+ <string name="ime_action_next" msgid="3138843904009813834">"Naprijed"</string>
+ <string name="ime_action_done" msgid="8971516117910934605">"Gotovo"</string>
+ <string name="ime_action_previous" msgid="1443550039250105948">"Naz."</string>
+ <string name="ime_action_default" msgid="2840921885558045721">"Izvrši"</string>
+ <string name="dial_number_using" msgid="5789176425167573586">"Biraj\nbroj <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using" msgid="4947405226788104538">"Napraviti kontakt\nkoristeći broj <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Sljedeće aplikacije zahtijevaju dozvolu za pristup vašem računu, sada i u budućnosti."</string>
+ <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Želite li dozvoliti taj zahtjev?"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zahtjev za pristup"</string>
+ <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
+ <string name="deny" msgid="2081879885755434506">"Odbijte"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"Upućen zahtjev za dozvolu"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Upućen zahtjev za dozvolu\nza račun <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+ <string name="forward_intent_to_owner" msgid="1207197447013960896">"Aplikaciju koristite van poslovnog profila"</string>
+ <string name="forward_intent_to_work" msgid="621480743856004612">"Aplikaciju koristite u poslovnom profilu"</string>
+ <string name="input_method_binding_label" msgid="1283557179944992649">"Način unosa"</string>
+ <string name="sync_binding_label" msgid="3687969138375092423">"Sinhrona"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"Pristupačnost"</string>
+ <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"Promijenite pozadinsku sliku"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"Usluga za praćenje obavještenja"</string>
+ <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pružalac uslova"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obavještenja"</string>
+ <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
+ <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
+ <string name="vpn_text_long" msgid="6407351006249174473">"Uspostavljena veza sa <xliff:g id="SESSION">%s</xliff:g>. Dodirnite za upravljanje mrežom."</string>
+ <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje na uvijek aktivni VPN…"</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan na uvijek aktivni VPN"</string>
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška u povezivanju na uvijek aktivni VPN"</string>
+ <string name="vpn_lockdown_config" msgid="6415899150671537970">"Dodirnite da konfigurirate"</string>
+ <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string>
+ <string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string>
+ <string name="submit" msgid="1602335572089911941">"Potvrdi"</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Način rada u autu omogućen"</string>
+ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Dodirnite kako biste izašli iz načina rada u autu."</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Uređaj dijeli vezu ili djeluje kao pristupna tačka"</string>
+ <string name="tethered_notification_message" msgid="6857031760103062982">"Dodirnite za postavljanje."</string>
+ <string name="back_button_label" msgid="2300470004503343439">"Nazad"</string>
+ <string name="next_button_label" msgid="1080555104677992408">"Naprijed"</string>
+ <string name="skip_button_label" msgid="1275362299471631819">"Preskoči"</string>
+ <string name="no_matches" msgid="8129421908915840737">"Nema podudaranja"</string>
+ <string name="find_on_page" msgid="1946799233822820384">"Pronađi na stranici"</string>
+ <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+ <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+ <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+ <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+ </plurals>
+ <string name="action_mode_done" msgid="7217581640461922289">"Gotovo"</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Brisanje USB pohrane..."</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"Brisanje SD kartice..."</string>
+ <string name="share" msgid="1778686618230011964">"Podijelite"</string>
+ <string name="find" msgid="4808270900322985960">"Pronađi"</string>
+ <string name="websearch" msgid="4337157977400211589">"Internet pretraga"</string>
+ <string name="find_next" msgid="5742124618942193978">"Nađi sljedeći"</string>
+ <string name="find_previous" msgid="2196723669388360506">"Nađi prethodni"</string>
+ <string name="gpsNotifTicker" msgid="5622683912616496172">"Korisnik <xliff:g id="NAME">%s</xliff:g> je poslao zahtjev za utvrđivanje lokacije"</string>
+ <string name="gpsNotifTitle" msgid="5446858717157416839">"Zahtjev za utvrđivanje lokacije"</string>
+ <string name="gpsNotifMessage" msgid="1374718023224000702">"Zahtjev uputio <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
+ <string name="gpsVerifYes" msgid="2346566072867213563">"Da"</string>
+ <string name="gpsVerifNo" msgid="1146564937346454865">"Ne"</string>
+ <string name="sync_too_many_deletes" msgid="5296321850662746890">"Granica za brisanje prekoračena"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Izbrisano je <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> stavki za <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, račun <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Šta želite uraditi?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"Obriši stavke"</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"Poništiti brisanje"</string>
+ <string name="sync_do_nothing" msgid="3743764740430821845">"Ne radi ništa za sada"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"Odaberite račun"</string>
+ <string name="add_account_label" msgid="2935267344849993553">"Dodajte račun"</string>
+ <string name="add_account_button_label" msgid="3611982894853435874">"Dodajte račun"</string>
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Povećaj"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Smanji"</string>
+ <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Dodirnite <xliff:g id="VALUE">%s</xliff:g> i držite."</string>
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Kliznite gore da povećate i dolje da smanjite."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Povećaj minute"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Smanji minute"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Povećaj sate"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Smanji sate"</string>
+ <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Postavi za poslijepodne (PM)"</string>
+ <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Postavi za prijepodne (AM)"</string>
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Povećaj mjesece"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Smanji mjesece"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Povećaj dane"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Smanji dane"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povećaj godine"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Smanji godine"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prethodni mjesec"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Sljedeći mjesec"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Prekini"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotovo"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Promjena načina rada"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Potvrdi"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Odaberite aplikaciju"</string>
+ <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Aplikacija <xliff:g id="APPLICATION_NAME">%s</xliff:g> se ne može pokrenuti."</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"Podijeliti sa"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Podijeli koristeći aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"Klizni regulator. Dodirnite &amp; držite."</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Prevucite za otključavanje ekrana."</string>
+ <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Priključite slušalice kako biste čuli dugmad prilikom kucanja lozinke."</string>
+ <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Tačka."</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Vratite se na početnu stranicu"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navigirajte prema gore"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Više opcija"</string>
+ <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
+ <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
+ <string name="storage_internal" msgid="4891916833657929263">"Interna pohrana"</string>
+ <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
+ <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartica"</string>
+ <string name="storage_usb_drive" msgid="6261899683292244209">"USB disk"</string>
+ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
+ <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
+ <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje za prijenos podataka"</string>
+ <string name="data_usage_warning_body" msgid="2814673551471969954">"Podaci o korištenju i postavke"</string>
+ <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string>
+ <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string>
+ <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Dostignut limit mob. podataka"</string>
+ <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Dostignut limit Wi-Fi podataka"</string>
+ <string name="data_usage_limit_body" msgid="291731708279614081">"Podaci pauz. za ostatak ciklusa"</string>
+ <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Premašeni 2G-3G podaci"</string>
+ <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Premašeni 4G podaci"</string>
+ <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Limit mob. podataka prekoračen"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Premašeno Wi-Fi ograničenje"</string>
+ <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> preko navedenog ograničenja."</string>
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"Pozadinski podaci su ograničeni"</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Dodirnuti za uklanjanje ogran."</string>
+ <string name="ssl_certificate" msgid="6510040486049237639">"Sigurnosni certifikat"</string>
+ <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Ovaj certifikat je važeći."</string>
+ <string name="issued_to" msgid="454239480274921032">"Primalac:"</string>
+ <string name="common_name" msgid="2233209299434172646">"Ime domene:"</string>
+ <string name="org_name" msgid="6973561190762085236">"Organizacija:"</string>
+ <string name="org_unit" msgid="7265981890422070383">"Organizaciona jedinica:"</string>
+ <string name="issued_by" msgid="2647584988057481566">"Izdao:"</string>
+ <string name="validity_period" msgid="8818886137545983110">"Valjanost:"</string>
+ <string name="issued_on" msgid="5895017404361397232">"Datum izdavanja:"</string>
+ <string name="expires_on" msgid="3676242949915959821">"Ističe:"</string>
+ <string name="serial_number" msgid="758814067660862493">"Serijski broj:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Otisci prstiju:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 otisak prsta:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 otisak prsta:"</string>
+ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Vidi sve"</string>
+ <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Odaberite aktivnost"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"Podijeliti sa"</string>
+ <string name="sending" msgid="3245653681008218030">"Slanje..."</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"Pokretanje preglednika?"</string>
+ <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo ovaj put"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
+ <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
+ <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
+ <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
+ <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slušalice"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici priključne stanice"</string>
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
+ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
+ <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
+ <string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string>
+ <string name="media_route_button_content_description" msgid="591703006349356016">"Prebacuj"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Poveži na uređaj"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prebaci ekran na uređaj"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Traženje uređajā…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Postavke"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Prekini vezu"</string>
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Skeniranje…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Povezivanje…"</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Dostupno"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Nije dostupno"</string>
+ <string name="media_route_status_in_use" msgid="4533786031090198063">"U upotrebi"</string>
+ <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ugrađeni ekran"</string>
+ <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI ekran"</string>
+ <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Nadsloj #<xliff:g id="ID">%1$d</xliff:g>"</string>
+ <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+ <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", osigurano"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste uzorak?"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan uzorak"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Broj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER">%1$d</xliff:g>."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte obrazac"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN za SIM"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Unesite lozinku"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM je sada onemogućen. Unesite PUK kôd da nastavite. Obratite se operateru za detalje."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Unesite željeni PIN kôd"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrdi željeni PIN kôd"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Pogrešan PIN kôd."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji sadrži od 4 do 8 brojeva."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK kôd bi trebao imati 8 brojeva."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi se ne poklapaju"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja otključavanja pomoću uzorka"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Da otključate, prijavite se sa svojim Google računom."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Korisničko ime (adresa e-pošte)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Lozinka"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Pogrešno korisničko ime ili lozinka."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili lozinku?\nPosjetite "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Provjeravanje računa…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Pogrešno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Pogrešno ste unijeli lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Pogrešno ste nacrtali uzorak <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nBroj sekundi do sljedećeg pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Pokušali ste otključati tablet na pogrešan način <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će biti vraćen na fabričke postavke i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati TV. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, TV će biti vraćen na fabričke postavke i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Pokušali ste otključati telefon na pogrešan način <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će biti vraćen na fabričke postavke i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Pokušali ste otključati tablet na pogrešan način <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na fabričke postavke."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati TV. TV će sada biti vraćen na fabričke postavke."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Pokušali ste otključati telefon na pogrešan način <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na fabričke postavke."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate tablet pomoću e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Uzorak za otključavanje ste pogrešno nacrtali <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, bit će zatraženo da TV otključate pomoću računa e-pošte.\n\n Pokušajte opet za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <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="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>
+ <string name="owner_name" msgid="2716755460376028154">"Vlasnik"</string>
+ <string name="error_message_title" msgid="4510373083082500195">"Greška"</string>
+ <string name="error_message_change_not_allowed" msgid="1347282344200417578">"Promjenu ne dopušta vaš administrator"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena aplikacija koja će upravljati ovom akcijom."</string>
+ <string name="revoke" msgid="5404479185228271586">"Opozovi"</string>
+ <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
+ <string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
+ <string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
+ <string name="mediasize_iso_a3" msgid="3023213259314236123">"ISO A3"</string>
+ <string name="mediasize_iso_a4" msgid="231745325296873764">"ISO A4"</string>
+ <string name="mediasize_iso_a5" msgid="3484327407340865411">"ISO A5"</string>
+ <string name="mediasize_iso_a6" msgid="4861908487129577530">"ISO A6"</string>
+ <string name="mediasize_iso_a7" msgid="5890208588072936130">"ISO A7"</string>
+ <string name="mediasize_iso_a8" msgid="4319425041085816612">"ISO A8"</string>
+ <string name="mediasize_iso_a9" msgid="4882220529506432008">"ISO A9"</string>
+ <string name="mediasize_iso_a10" msgid="2382866026365359391">"ISO A10"</string>
+ <string name="mediasize_iso_b0" msgid="3651827147402009675">"ISO B0"</string>
+ <string name="mediasize_iso_b1" msgid="6072859628278739957">"ISO B1"</string>
+ <string name="mediasize_iso_b2" msgid="1348731852150380378">"ISO B2"</string>
+ <string name="mediasize_iso_b3" msgid="2612510181259261379">"ISO B3"</string>
+ <string name="mediasize_iso_b4" msgid="695151378838115434">"ISO B4"</string>
+ <string name="mediasize_iso_b5" msgid="4863754285582212487">"ISO B5"</string>
+ <string name="mediasize_iso_b6" msgid="5305816292139647241">"ISO B6"</string>
+ <string name="mediasize_iso_b7" msgid="531673542602786624">"ISO B7"</string>
+ <string name="mediasize_iso_b8" msgid="9164474595708850034">"ISO B8"</string>
+ <string name="mediasize_iso_b9" msgid="282102976764774160">"ISO B9"</string>
+ <string name="mediasize_iso_b10" msgid="4517141714407898976">"ISO B10"</string>
+ <string name="mediasize_iso_c0" msgid="3103521357901591100">"ISO C0"</string>
+ <string name="mediasize_iso_c1" msgid="1231954105985048595">"ISO C1"</string>
+ <string name="mediasize_iso_c2" msgid="927702816980087462">"ISO C2"</string>
+ <string name="mediasize_iso_c3" msgid="835154173518304159">"ISO C3"</string>
+ <string name="mediasize_iso_c4" msgid="5095951985108194011">"ISO C4"</string>
+ <string name="mediasize_iso_c5" msgid="1985397450332305739">"ISO C5"</string>
+ <string name="mediasize_iso_c6" msgid="8147421924174693013">"ISO C6"</string>
+ <string name="mediasize_iso_c7" msgid="8993994925276122950">"ISO C7"</string>
+ <string name="mediasize_iso_c8" msgid="6871178104139598957">"ISO C8"</string>
+ <string name="mediasize_iso_c9" msgid="7983532635227561362">"ISO C9"</string>
+ <string name="mediasize_iso_c10" msgid="5040764293406765584">"ISO C10"</string>
+ <string name="mediasize_na_letter" msgid="2841414839888344296">"Letter"</string>
+ <string name="mediasize_na_gvrnmt_letter" msgid="5295836838862962809">"Government Letter"</string>
+ <string name="mediasize_na_legal" msgid="8621364037680465666">"Legal"</string>
+ <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"Junior Legal"</string>
+ <string name="mediasize_na_ledger" msgid="5567030340509075333">"Ledger"</string>
+ <string name="mediasize_na_tabloid" msgid="4571735038501661757">"Tabloid"</string>
+ <string name="mediasize_na_index_3x5" msgid="5182901917818625126">"Index Card 3x5"</string>
+ <string name="mediasize_na_index_4x6" msgid="7687620625422312396">"Index Card 4x6"</string>
+ <string name="mediasize_na_index_5x8" msgid="8834215284646872800">"Index Card 5x8"</string>
+ <string name="mediasize_na_monarch" msgid="213639906956550754">"Monarch"</string>
+ <string name="mediasize_na_quarto" msgid="835778493593023223">"Quarto"</string>
+ <string name="mediasize_na_foolscap" msgid="1573911237983677138">"Foolscap"</string>
+ <string name="mediasize_chinese_roc_8k" msgid="3626855847189438896">"ROC 8K"</string>
+ <string name="mediasize_chinese_roc_16k" msgid="9182191577022943355">"ROC 16K"</string>
+ <string name="mediasize_chinese_prc_1" msgid="4793232644980170500">"PRC 1"</string>
+ <string name="mediasize_chinese_prc_2" msgid="5404109730975720670">"PRC 2"</string>
+ <string name="mediasize_chinese_prc_3" msgid="1335092253339363526">"PRC 3"</string>
+ <string name="mediasize_chinese_prc_4" msgid="9167997800486569834">"PRC 4"</string>
+ <string name="mediasize_chinese_prc_5" msgid="845875168823541497">"PRC 5"</string>
+ <string name="mediasize_chinese_prc_6" msgid="3220325667692648789">"PRC 6"</string>
+ <string name="mediasize_chinese_prc_7" msgid="1776792138507038527">"PRC 7"</string>
+ <string name="mediasize_chinese_prc_8" msgid="1417176642687456692">"PRC 8"</string>
+ <string name="mediasize_chinese_prc_9" msgid="4785983473123798365">"PRC 9"</string>
+ <string name="mediasize_chinese_prc_10" msgid="7847982299391851899">"PRC 10"</string>
+ <string name="mediasize_chinese_prc_16k" msgid="262793383539980677">"PRC 16K"</string>
+ <string name="mediasize_chinese_om_pa_kai" msgid="5256815579447959814">"Pa Kai"</string>
+ <string name="mediasize_chinese_om_dai_pa_kai" msgid="7336412963441354407">"Dai Pa Kai"</string>
+ <string name="mediasize_chinese_om_jurro_ku_kai" msgid="6324465444100490742">"Jurro Ku Kai"</string>
+ <string name="mediasize_japanese_jis_b10" msgid="1787262845627694376">"JIS B10"</string>
+ <string name="mediasize_japanese_jis_b9" msgid="3336035783663287470">"JIS B9"</string>
+ <string name="mediasize_japanese_jis_b8" msgid="6195398299104345731">"JIS B8"</string>
+ <string name="mediasize_japanese_jis_b7" msgid="1674621886902828884">"JIS B7"</string>
+ <string name="mediasize_japanese_jis_b6" msgid="4170576286062657435">"JIS B6"</string>
+ <string name="mediasize_japanese_jis_b5" msgid="4899297958100032533">"JIS B5"</string>
+ <string name="mediasize_japanese_jis_b4" msgid="4213158129126666847">"JIS B4"</string>
+ <string name="mediasize_japanese_jis_b3" msgid="8513715307410310696">"JIS B3"</string>
+ <string name="mediasize_japanese_jis_b2" msgid="4777690211897131190">"JIS B2"</string>
+ <string name="mediasize_japanese_jis_b1" msgid="4608142385457034603">"JIS B1"</string>
+ <string name="mediasize_japanese_jis_b0" msgid="7587108366572243991">"JIS B0"</string>
+ <string name="mediasize_japanese_jis_exec" msgid="5244075432263649068">"JIS Exec"</string>
+ <string name="mediasize_japanese_chou4" msgid="4941652015032631361">"Chou4"</string>
+ <string name="mediasize_japanese_chou3" msgid="6387319169263957010">"Chou3"</string>
+ <string name="mediasize_japanese_chou2" msgid="1299112025415343982">"Chou2"</string>
+ <string name="mediasize_japanese_hagaki" msgid="8070115620644254565">"Hagaki"</string>
+ <string name="mediasize_japanese_oufuku" msgid="6049065587307896564">"Oufuku"</string>
+ <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
+ <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
+ <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
+ <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Neodređeni uspravni format"</string>
+ <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Neodređeni vodoravni format"</string>
+ <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Otkazano"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Greška pri pisanju sadržaja"</string>
+ <string name="reason_unknown" msgid="6048913880184628119">"nepoznat"</string>
+ <string name="reason_service_unavailable" msgid="7824008732243903268">"Usluga štampanja nije omogućena."</string>
+ <string name="print_service_installed_title" msgid="2246317169444081628">"Usluga <xliff:g id="NAME">%s</xliff:g> je instalirana"</string>
+ <string name="print_service_installed_message" msgid="5897362931070459152">"Dodirnite da omogućite"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Unesite administratorski PIN"</string>
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Unesite PIN"</string>
+ <string name="restr_pin_incorrect" msgid="8571512003955077924">"Netačno"</string>
+ <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Trenutni PIN"</string>
+ <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
+ <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrdi novi PIN"</string>
+ <string name="restr_pin_create_pin" msgid="8017600000263450337">"Kreiraj PIN za izmjenu ograničenja"</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora imati najmanje 4 cifre."</string>
+ <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+ <item quantity="one">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
+ <item quantity="few">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+ <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+ </plurals>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije."</string>
+ <string name="immersive_cling_title" msgid="8394201622932303336">"Prikazuje se cijeli ekran"</string>
+ <string name="immersive_cling_description" msgid="3482371193207536040">"Da izađete, prevucite nadolje odozgo."</string>
+ <string name="immersive_cling_positive" msgid="5016839404568297683">"Jasno mi je"</string>
+ <string name="done_label" msgid="2093726099505892398">"Završeno"</string>
+ <string name="hour_picker_description" msgid="6698199186859736512">"Kružni klizač za odabir sata"</string>
+ <string name="minute_picker_description" msgid="8606010966873791190">"Kružni klizač za minute"</string>
+ <string name="select_hours" msgid="6043079511766008245">"Odaberite sat"</string>
+ <string name="select_minutes" msgid="3974345615920336087">"Odaberite minute"</string>
+ <string name="select_day" msgid="7774759604701773332">"Odaberite mjesec i dan"</string>
+ <string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
+ <string name="deleted_key" msgid="7659477886625566590">"Broj <xliff:g id="KEY">%1$s</xliff:g> je izbrisan"</string>
+ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="lock_to_app_toast" msgid="7570091317001980053">"Da otkačite ovaj ekran, istovremeno dodirnite i držite Nazad i Pregled."</string>
+ <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da otkačite ovaj ekran, dodirnite i držite Pregled."</string>
+ <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je prikačena. Na ovom uređaju nije dozvoljeno otkačivanje."</string>
+ <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
+ <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran je otkačen"</string>
+ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN prije nego se otkači"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži uzorak za otključavanje prije nego se otkači"</string>
+ <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži lozinku prije nego se otkači"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće raditi na podijeljenom ekranu"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava dijeljenje ekrana."</string>
- <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
- <skip />
- <!-- no translation found for package_updated_device_owner (8856631322440187071) -->
- <skip />
- <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
- <skip />
- <!-- no translation found for battery_saver_description (1960431123816253034) -->
- <skip />
- <!-- no translation found for zen_mode_duration_minutes_summary (4367877408072000848) -->
- <!-- no translation found for zen_mode_duration_minutes_summary_short (6830154222366042597) -->
- <!-- no translation found for zen_mode_duration_hours_summary (8152974162096743862) -->
- <!-- no translation found for zen_mode_duration_hours_summary_short (4787552595253082371) -->
- <!-- no translation found for zen_mode_duration_minutes (5127407202506485571) -->
- <!-- no translation found for zen_mode_duration_minutes_short (2199350154433426128) -->
- <!-- no translation found for zen_mode_duration_hours (3938821308277433854) -->
- <!-- no translation found for zen_mode_duration_hours_short (6748277774662434217) -->
- <!-- no translation found for zen_mode_until (7336308492289875088) -->
- <skip />
- <!-- no translation found for zen_mode_alarm (9128205721301330797) -->
- <skip />
- <!-- no translation found for zen_mode_forever (7420011936770086993) -->
- <skip />
- <!-- no translation found for zen_mode_forever_dnd (3792132696572189081) -->
- <skip />
- <!-- no translation found for zen_mode_rule_name_combination (191109939968076477) -->
- <skip />
- <!-- no translation found for toolbar_collapse_description (2821479483960330739) -->
- <skip />
- <!-- no translation found for zen_mode_feature_name (5254089399895895004) -->
- <skip />
- <!-- no translation found for zen_mode_downtime_feature_name (2626974636779860146) -->
- <skip />
- <!-- no translation found for zen_mode_default_weeknights_name (3081318299464998143) -->
- <skip />
- <!-- no translation found for zen_mode_default_weekends_name (2786495801019345244) -->
- <skip />
- <!-- no translation found for zen_mode_default_events_name (8158334939013085363) -->
- <skip />
- <!-- no translation found for muted_by (6147073845094180001) -->
- <skip />
- <!-- no translation found for system_error_wipe_data (6608165524785354962) -->
- <skip />
- <!-- no translation found for system_error_manufacturer (8086872414744210668) -->
- <skip />
- <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
- <skip />
- <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
- <skip />
- <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
- <skip />
- <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
- <skip />
- <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
- <skip />
- <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
- <skip />
- <!-- no translation found for notification_work_profile_content_description (4600554564103770764) -->
- <skip />
- <!-- no translation found for usb_midi_peripheral_name (7221113987741003817) -->
- <skip />
- <!-- no translation found for usb_midi_peripheral_manufacturer_name (7176526170008970168) -->
- <skip />
- <!-- no translation found for usb_midi_peripheral_product_name (4971827859165280403) -->
- <skip />
- <!-- no translation found for floating_toolbar_open_overflow_description (4797287862999444631) -->
- <skip />
- <!-- no translation found for floating_toolbar_close_overflow_description (559796923090723804) -->
- <skip />
- <!-- no translation found for maximize_button_text (7543285286182446254) -->
- <skip />
- <!-- no translation found for close_button_text (3937902162644062866) -->
- <skip />
- <!-- no translation found for selected_count (7187339492915744615) -->
- <!-- no translation found for default_notification_topic_label (227586145791870829) -->
- <skip />
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao administrator"</string>
+ <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
+ <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se trajanje baterije produžilo, opcija za štednju baterije minimizira rad uređaja i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu biti ažurirane dok ih ne otvorite.\n\nŠtednja baterije se automatski isključi prilikom punjenja uređaja."</string>
+ <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+ <item quantity="one">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">%1$d minute (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="6830154222366042597">
+ <item quantity="one">%1$d min (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">%1$d min (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">%1$d min (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+ <item quantity="one">%1$d sat (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">%1$d sata (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">%1$d sati (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="4787552595253082371">
+ <item quantity="one">%1$d sat (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">%1$d sata (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">%1$d sati (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+ <item quantity="one">%d minuta</item>
+ <item quantity="few">%d minute</item>
+ <item quantity="other">%d minuta</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2199350154433426128">
+ <item quantity="one">%d min</item>
+ <item quantity="few">%d min</item>
+ <item quantity="other">%d min</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+ <item quantity="one">%d sat</item>
+ <item quantity="few">%d sata</item>
+ <item quantity="other">%d sati</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_short" formatted="false" msgid="6748277774662434217">
+ <item quantity="one">%d sat</item>
+ <item quantity="few">%d sata</item>
+ <item quantity="other">%d sati</item>
+ </plurals>
+ <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sljedeći alarm)"</string>
+ <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ovo ne isključite"</string>
+ <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dok ne isključite opciju Ne ometaj"</string>
+ <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
+ <string name="toolbar_collapse_description" msgid="2821479483960330739">"Skupi"</string>
+ <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ne ometaj"</string>
+ <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Odmor"</string>
+ <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Radni dan uveče"</string>
+ <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Vikend"</string>
+ <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Događaj"</string>
+ <string name="muted_by" msgid="6147073845094180001">"Ton isključila aplikacija <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+ <string name="system_error_wipe_data" msgid="6608165524785354962">"Postoji problem u vašem uređaju i može biti nestabilan dok ga ne vratite na fabričke postavke."</string>
+ <string name="system_error_manufacturer" msgid="8086872414744210668">"Postoji problem u vašem uređaju. Za više detalja obratite se proizvođaču."</string>
+ <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD zahtjev je izmijenjen u DIAL zahtjev."</string>
+ <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD zahtjev je izmijenjen u SS zahtjev."</string>
+ <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD zahtjev je izmijenjen u novi USSD zahtjev."</string>
+ <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtjev je izmijenjen u DIAL zahtjev."</string>
+ <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtjev je izmijenjen u USSD zahtjev."</string>
+ <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtjev je izmijenjen u novi SS zahtjev."</string>
+ <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil za posao"</string>
+ <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB ulaz za periferijske uređaje"</string>
+ <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+ <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB ulaz za periferijske uređaje"</string>
+ <string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"Još opcija"</string>
+ <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Zatvori preklopni meni"</string>
+ <string name="maximize_button_text" msgid="7543285286182446254">"Povećaj maksimalno"</string>
+ <string name="close_button_text" msgid="3937902162644062866">"Zatvori"</string>
+ <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> stavka je odabrana</item>
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> stavki je odabrano</item>
+ </plurals>
+ <string name="importance_from_user" msgid="7318955817386549931">"Vi određujete značaj ovih obavještenja."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ovo je značajno zbog osoba koje su uključene."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za nalog <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Da li dozvoljavate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (Korisnik sa ovim nalogom već postoji)?"</string>
- <!-- no translation found for language_selection_title (7181332986330337171) -->
- <skip />
- <!-- no translation found for country_selection_title (2954859441620215513) -->
- <skip />
- <!-- no translation found for search_language_hint (7042102592055108574) -->
- <skip />
- <!-- no translation found for language_picker_section_suggested (8414489646861640885) -->
- <skip />
- <!-- no translation found for language_picker_section_all (3097279199511617537) -->
- <skip />
- <!-- no translation found for locale_search_menu (2560710726687249178) -->
- <skip />
- <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način je ISKLJUČEN"</string>
- <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućava radnom profilu da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dodaj jezik"</string>
+ <string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
+ <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte naziv jezika"</string>
+ <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
+ <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
+ <string name="locale_search_menu" msgid="2560710726687249178">"Pretraga"</string>
+ <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string>
+ <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Uključi"</string>
<string name="suspended_package_title" msgid="3408150347778524435">"%1$s – onemogućeno"</string>
<string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio administrator (%1$s). Obratite mu se za više informacija."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nove poruke"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorite SMS aplikaciju da biste pregledali poruke"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Neke funkcije možda neće biti dostupne"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Dodirnite da biste nastavili"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil korisnika je zaključan"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Neke funkcije mogu biti ograničene"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Dodirnite da biste otključali"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Podaci korisnika su zaključani"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Radni profil je zaključan"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Dodirnite da biste otključali radni profil"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Povezan na uređaj <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dodirnite za prikaz fajlova"</string>
<string name="pin_target" msgid="3052256031352291362">"Zakači"</string>
<string name="unpin_target" msgid="3556545602439143442">"Otkači"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fe7dbc7c3911..9bd8014f3a0b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El valor predeterminat de l\'identificador de l\'emissor és no restringit. Següent trucada: no restringit"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"No s\'ha proveït el servei."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"No pots canviar la configuració de l\'identificador de l\'emissor."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Accés restringit canviat"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"El servei de dades està bloquejat."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servei d\'emergència està bloquejat."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"El servei de veu està bloquejat."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Restableix i reinicia l\'aplicació"</string>
<string name="aerr_report" msgid="5371800241488400617">"Envia suggeriments"</string>
<string name="aerr_close" msgid="2991640326563991340">"Tanca"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Silencia"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Silencia fins que es reiniciï el dispositiu"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Espera"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Tanca l\'aplicació"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Toca per desactivar la depuració USB"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vols compartir l\'informe d\'errors amb l\'administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"El teu administrador de TI ha sol·licitat un informe d\'errors per tal de resoldre problemes"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"L\'administrador de TI ha sol·licitat un informe d\'errors per resoldre els problemes d\'aquest dispositiu. És possible que es comparteixin aplicacions i dades, i que el dispositiu funcioni més a poc a poc durant una estona."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"El teu administrador de TI ha sol·licitat un informe d\'errors per resoldre els problemes d\'aquest dispositiu. És possible que es comparteixin aplicacions i dades."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"És possible que el dispositiu funcioni més a poc a poc durant una estona"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTA"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REBUTJA"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"S\'està creant l\'informe d\'errors…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toca per cancel·lar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Tria els teclats"</string>
<string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sol·licita el codi PIN per anul·lar"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sol·licita el patró de desbloqueig per anul·lar"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demana la contrasenya per anul·lar"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No es pot canviar la mida de l\'aplicació. Desplaça-la amb dos dits."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'aplicació no admet la pantalla dividida."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"L\'administrador ho ha instal·lat"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"L\'administrador l\'ha actualitzat"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">Seleccionats: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Seleccionats: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Altres"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Tu has definit la importància d\'aquestes notificacions."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Has definit la importància d\'aquestes notificacions."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Aquest missatge és important per les persones implicades."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferència d\'idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Afegeix un idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferència de regió"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerits"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"L\'administrador de l\'empresa %1$s ha desactivat el paquet. Contacta-hi per obtenir-ne més informació."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Tens missatges nous"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Obre l\'aplicació de SMS per veure\'ls"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Hi pot haver funcions no disponibles"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Toca per continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil d\'usuari bloquejat"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Algunes funcions es limitaran"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Toca per desbloquejar"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Dades d\'usuari bloquejades"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil professional bloquejat"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Toca per desbloquejar el perfil"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"S\'ha connectat a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca per veure els fitxers"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixa"</string>
<string name="unpin_target" msgid="3556545602439143442">"No fixis"</string>
<string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0b6d668d2486..facf36893f78 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Služba není zřízena."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Nastavení identifikace volajícího nesmíte měnit."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Omezený přístup byl změněn."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datová služba je zablokována."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Tísňová linka je zablokována."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Hlasová služba je zablokována."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Obnovit a restartovat aplikaci"</string>
<string name="aerr_report" msgid="5371800241488400617">"Odeslat zpětnou vazbu"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zavřít"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorovat"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorovat do restartu zařízení"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Počkat"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zavřít aplikaci"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Dotykem zakážete ladění USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Sdílet zprávu o chybě s administrátorem?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit. Mohou být sdíleny aplikace a data a zařízení se může dočasně zpomalit."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit. Aplikace a data mohou být sdílena."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Zařízení se může dočasně zpomalit"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PŘIJMOUT"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMÍTNOUT"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Vytváření zprávy o chybě…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Klepnutím zrušíte"</string>
<string name="select_input_method" msgid="8547250819326693584">"Změna klávesnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vybrat klávesnici"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o PIN"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Před uvolněním požádat o bezpečnostní gesto"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Před uvolněním požádat o heslo"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Velikost aplikace nelze změnit. Zobrazení můžete posouvat dvěma prsty."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Nainstalováno administrátorem"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizováno administrátorem"</string>
@@ -1575,12 +1575,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> položek</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> položka</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Různé"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Důležitost oznámení určujete vy."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Důležitost oznámení určujete vy."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferovaný jazyk"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Přidat jazyk"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferovaná oblast"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Zakázáno administrátorem zařízení %1$s. Chcete-li získat další informace, kontaktujte jej."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Máte nové zprávy"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Zobrazíte je v aplikaci pro SMS"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Některé funkce nemusí být k dispozici"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Pokračujte klepnutím"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Uživatelský profil je uzamčen"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funkce mohou být omezeny"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Klepnutím je odemknete"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Uživatelská data jsou uzamčena"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Pracovní profil je uzamčen"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Klepnutím jej odemknete"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Připojeno k zařízení <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Klepnutím zobrazíte soubory"</string>
<string name="pin_target" msgid="3052256031352291362">"Připnout"</string>
<string name="unpin_target" msgid="3556545602439143442">"Odepnout"</string>
<string name="app_info" msgid="6856026610594615344">"Informace o aplikaci"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4a3780ca84eb..a0a3f8f0c97a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjenesten leveres ikke!"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Du kan ikke ændre indstillingen for opkalds-id\'et."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begrænset adgang ændret"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datatjenesten er blokeret."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjenesten er blokeret."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Stemmetjenesten er blokeret."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Nulstil og genstart appen"</string>
<string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Luk"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorer"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorer, indtil enheden genstarter"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Vent"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Luk app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Tryk for at deaktivere USB-fejlretning."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vil du dele fejlrapporten med administratoren?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen på enheden. Apps og data deles muligvis, og din enhed kan midlertidigt blive langsommere."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen på enheden. Apps og data deles muligvis."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dette kan midlertidigt gøre enheden langsommere"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTÉR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AFVIS"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Opretter fejlrapport…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tryk for at annullere"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skift tastatur"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vælg tastaturer"</string>
<string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bed om oplåsningsmønster ved deaktivering"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bed om adgangskode inden frigørelse"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Appens størrelse kan ikke ændres. Gennemgå den ved at rulle med to fingre."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i delt skærm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke delt skærm."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installeret af din administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Opdateret af administrator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>valgt</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Du angiver, hvor vigtige disse underretninger er."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse underretninger er."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Sprogindstilling"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Tilføj et sprog"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Områdeindstilling"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Angiv sprogets navn"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslået"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Deaktiveret af %1$s administrator. Kontakt vedkommende for at få flere oplysninger."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nye beskeder"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Åbn sms-appen for at se beskeden"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Nogle funktioner er muligvis ikke tilgængelige"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Tryk for at fortsætte"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Brugerprofilen er låst"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Nogle funktioner er begrænsede"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tryk for at låse op"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Brugerdataene er låst"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Arbejdsprofilen er låst"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tryk for at låse profilen op"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Tilsluttet <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tryk for at se filer"</string>
<string name="pin_target" msgid="3052256031352291362">"Fastgør"</string>
<string name="unpin_target" msgid="3556545602439143442">"Frigør"</string>
<string name="app_info" msgid="6856026610594615344">"Oplysninger om appen"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f04521fc7265..8406a70cbfb5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Dienst nicht eingerichtet."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Du kannst die Einstellung für die Anrufer-ID nicht ändern."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Eingeschränkter Zugriff geändert"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Daten-Dienst ist gesperrt."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Notruf ist gesperrt."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Sprachdienst ist gesperrt."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"App zurücksetzen und neu starten"</string>
<string name="aerr_report" msgid="5371800241488400617">"Feedback geben"</string>
<string name="aerr_close" msgid="2991640326563991340">"Schließen"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorieren"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Bis zum Neustart des Geräts ausblenden"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Warten"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"App schließen"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Für weitere Optionen tippen"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren berühren"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Fehlerbericht mit Administrator teilen?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung angefordert."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung dieses Geräts angefordert. Apps und Daten werden unter Umständen geteilt und dein Gerät wird möglicherweise vorübergehend langsamer."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung dieses Geräts angefordert. Apps und Daten werden unter Umständen geteilt."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dadurch wird dein Gerät möglicherweise vorübergehend langsamer"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKZEPTIEREN"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ABLEHNEN"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Fehlerbericht wird aufgerufen…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Zum Abbrechen tippen"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatur ändern"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Tastatur auswählen"</string>
<string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vor dem Beenden nach Entsperrungsmuster fragen"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vor dem Beenden nach Passwort fragen"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Die Größe der App kann nicht angepasst werden. Scrolle sie mit zwei Fingern."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Die App funktioniert unter Umständen bei geteiltem Bildschirm nicht."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Von deinem Administrator installiert"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Von deinem Administrator aktualisiert"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ausgewählt</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Sonstige"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Du legst die Wichtigkeit dieser Benachrichtigungen fest."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Du hast die Wichtigkeit dieser Benachrichtigungen festgelegt."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt? Dieses Konto wird jedoch bereits von einem anderen Nutzer verwendet."</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Spracheinstellung"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Sprache hinzufügen"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Region auswählen"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Vorschläge"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Durch den Administrator von %1$s deaktiviert. Setze dich für weitere Informationen mit ihm in Verbindung."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Du hast neue Nachrichten"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Zum Ansehen SMS-App öffnen"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Einige Funktionen sind evtl. nicht verfügbar"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Zum Fortfahren tippen"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Nutzerprofil gesperrt"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Einige Funktionen sind evtl. eingeschränkt"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Zum Entsperren tippen"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Nutzerdaten gesperrt"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Arbeitsprofil gesperrt"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Zum Entsperren des Arbeitsprofils tippen"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Verbunden mit <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Zum Ansehen der Dateien tippen"</string>
<string name="pin_target" msgid="3052256031352291362">"Markieren"</string>
<string name="unpin_target" msgid="3556545602439143442">"Markierung entfernen"</string>
<string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index c557c7350c3f..f5192b7a6600 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"μη περιορισμένη\". Επόμενη κλήση: Μη περιορισμένη"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Η υπηρεσία δεν προβλέπεται."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Δεν μπορείτε να αλλάξετε τη ρύθμιση του αναγνωριστικού καλούντος."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Η περιορισμένη πρόσβαση άλλαξε"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Η υπηρεσία δεδομένων είναι αποκλεισμένη."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Η υπηρεσία έκτακτης ανάγκης είναι αποκλεισμένη."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Η υπηρεσία φωνής έχει αποκλειστεί."</string>
@@ -163,7 +162,7 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ο αποθηκευτικός χώρος του tablet είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
<string name="low_memory" product="watch" msgid="4415914910770005166">"Ο αποθηκευτικός χώρος παρακολούθησης είναι πλήρης! Διαγράψτε μερικά αρχεία για να απελευθερώσετε χώρο."</string>
- <string name="low_memory" product="tv" msgid="516619861191025923">"Ο χώρος αποθήκευσης της τηλεόρασης είναι πλήρης. Διαγράψτε ορισμένα αρχεία, για να ελευθερώσετε χώρο."</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"Ο αποθηκευτικός χώρος της τηλεόρασης είναι πλήρης. Διαγράψτε ορισμένα αρχεία, για να ελευθερώσετε χώρο."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Από ένα άγνωστο τρίτο μέρος"</string>
@@ -311,7 +310,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του tablet."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Επιτρέπει στην εφαρμογή να καθιστά τμήματά της μόνιμα στη μνήμη. Αυτό μπορεί να περιορίσει τη μνήμη που διατίθεται σε άλλες εφαρμογές, επιβραδύνοντας τη λειτουργία της τηλεόρασης."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του τηλεφώνου."</string>
- <string name="permlab_getPackageSize" msgid="7472921768357981986">"μέτρηση χώρου αποθήκευσης εφαρμογής"</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"μέτρηση αποθηκευτικού χώρου εφαρμογής"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Επιτρέπει στην εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"τροποποίηση ρυθμίσεων συστήματος"</string>
<string name="permdesc_writeSettings" msgid="7775723441558907181">"Επιτρέπει στην εφαρμογή την τροποποίηση των δεδομένων των ρυθμίσεων του συστήματος. Τυχόν κακόβουλες εφαρμογές ενδέχεται να καταστρέψουν τη διαμόρφωση του συστήματός σας."</string>
@@ -880,9 +879,9 @@
<string name="deleteText" msgid="6979668428458199034">"Διαγραφή"</string>
<string name="inputMethod" msgid="1653630062304567879">"Μέθοδος εισόδου"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Ενέργειες κειμένου"</string>
- <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο χώρος αποθήκευσης εξαντλείται"</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>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Δεν υπάρχει αρκετός αποθηκευτικός χώρος για το σύστημα. Βεβαιωθείτε ότι διαθέτετε 250 MB ελεύθερου χώρου και κάντε επανεκκίνηση."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"Αγγίξτε για περισσότερες πληροφορίες ή για να διακόψετε την εκτέλεση της εφαρμογής."</string>
<string name="ok" msgid="5970060430562524910">"OK"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Επαναφορά και επανεκκίνηση εφαρμογής"</string>
<string name="aerr_report" msgid="5371800241488400617">"Αποστολή σχολίων"</string>
<string name="aerr_close" msgid="2991640326563991340">"Κλείσιμο"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Σίγαση"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Σίγαση μέχρι την επανεκκίνηση της συσκευής"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Αναμονή"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Κλείσιμο εφαρμογής"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Αγγίξτε για περισσότερες επιλογές."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Απεν. του εντοπ. σφαλμάτων USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Να κοινοποιηθεί η αναφορά σφάλματος στο διαχειριστή;"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Ο διαχειριστής σας IT ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Κοινή χρήση αναφοράς σφάλματος;"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Κοινή χρήση αναφοράς σφάλματος…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Ο διαχειριστής σας IT ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος αυτής της συσκευής. Ενδέχεται να γίνει κοινή χρήση των εφαρμογών και να επιβραδυνθεί προσωρινά τη λειτουργία της συσκευής σας."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Ο διαχειριστής σας IT ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος αυτής της συσκευής. Ενδέχεται να γίνει κοινή χρήση των εφαρμογών και των δεδομένων."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Αυτή η διαδικασία ενδέχεται να επιβραδύνει προσωρινά τη λειτουργία της συσκευής σας"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ΑΠΟΔΟΧΗ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ΑΠΟΡΡΙΨΗ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Λήψη αναφοράς σφάλματος…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Αγγίξτε για ακύρωση"</string>
<string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Επιλογή πληκτρολογίων"</string>
<string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
@@ -1165,7 +1165,7 @@
<item quantity="one">1 αντιστοιχία</item>
</plurals>
<string name="action_mode_done" msgid="7217581640461922289">"Τέλος"</string>
- <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Διαγραφή χώρου αποθήκευσης USB..."</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Διαγραφή αποθηκευτικού χώρου USB..."</string>
<string name="progress_erasing" product="default" msgid="6596988875507043042">"Διαγραφή κάρτας SD..."</string>
<string name="share" msgid="1778686618230011964">"Κοινή χρ."</string>
<string name="find" msgid="4808270900322985960">"Εύρεση"</string>
@@ -1223,12 +1223,12 @@
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Περισσότερες επιλογές"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="4891916833657929263">"Εσωτερικός χώρος αποθήκευσης"</string>
+ <string name="storage_internal" msgid="4891916833657929263">"Εσωτερικός αποθηκευτικός χώρος"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"Κάρτα SD"</string>
<string name="storage_sd_card_label" msgid="6347111320774379257">"Κάρτα SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"Μονάδα USB"</string>
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
- <string name="storage_usb" msgid="3017954059538517278">"Χώρος αποθήκευσης USB"</string>
+ <string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Επεξεργασία"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"Προειδοποίηση χρήσης δεδομένων"</string>
<string name="data_usage_warning_body" msgid="2814673551471969954">"Αγγίξτε για προβολή χρήσης/ρυθμ."</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Να γίνεται ερώτηση για το μοτίβο ξεκλειδώματος, πριν από το ξεκαρφίτσωμα"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Να γίνεται ερώτηση για τον κωδικό πρόσβασης, πριν από το ξεκαρφίτσωμα"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Το μέγεθος της εφαρμογής δεν είναι προσαρμόσιμο. Σύρετε προς τα κάτω με δύο δάχτυλα."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Δεν είναι δυνατή η λειτουργία της εφαρμογής με διαχωρισμό οθόνης."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Εγκαταστάθηκε από το διαχειριστή σας"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ενημερώθηκε από το διαχειριστή σας"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">Επιλέχτηκαν <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Επιλέχτηκε <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Διάφορα"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Να επιτραπεί στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με το λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Να επιτραπεί στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με το λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν το λογαριασμό);"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Προτίμηση γλώσσας"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Προσθήκη γλώσσας"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Προτίμηση περιοχής"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Προτεινόμενες"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Απενεργοποιήθηκε από το διαχειριστή της συσκευής %1$s. Επικοινωνήστε με το διαχειριστή για να μάθετε περισσότερα."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Έχετε νέα μηνύματα"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Άνοιγμα της εφαρμογής SMS για προβολή"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Ενδεχόμενο μη διαθέσιμων λειτουργιών"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Αγγίξτε για συνέχεια"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Το προφίλ χρήστη κλειδώθηκε"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Μερ. λειτ. ίσως είναι περιορ."</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Πατήστε για ξεκλείδωμα"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Τα δεδομένα χρήστη κλειδώθηκαν"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Το προφίλ εργασίας κλειδώθηκε"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Πατήστε για ξεκλ. προφίλ εργ."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Συνδέθηκε με το <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Πατήστε για να δείτε τα αρχεία"</string>
<string name="pin_target" msgid="3052256031352291362">"Καρφίτσωμα"</string>
<string name="unpin_target" msgid="3556545602439143442">"Ξεκαρφίτσωμα"</string>
<string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a0a5493af1cf..7fdf1c15e5f3 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"You can\'t change the caller ID setting."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Restricted access changed"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Data service is blocked."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Emergency service is blocked."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Voice service is blocked."</string>
@@ -915,9 +914,9 @@
<string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> keeps stopping"</string>
<string name="aerr_restart" msgid="9001379185665886595">"Restart app"</string>
<string name="aerr_reset" msgid="7645427603514220451">"Reset and restart app"</string>
- <string name="aerr_report" msgid="5371800241488400617">"Sending feedback"</string>
+ <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Close"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Mute"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Mute until device restarts"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Wait"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Close app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Share bug report with admin?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Your IT admin requested a bug report to help troubleshoot"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"This may temporarily slow down your device"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Taking bug report…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touch to cancel"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"App is not resizeable, scroll it with two fingers."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App does not support split-screen."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installed by your administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Disabled by %1$s administrator. Contact them to find out more."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"You have new messages"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Open SMS app to view"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Some functions might not be available"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Touch to continue"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"User profile locked"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Some functionality may be limited"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tap to unlock"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"User data locked"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Work profile locked"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tap to unlock work profile"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connected to <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tap to view files"</string>
<string name="pin_target" msgid="3052256031352291362">"Pin"</string>
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a0a5493af1cf..7fdf1c15e5f3 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"You can\'t change the caller ID setting."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Restricted access changed"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Data service is blocked."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Emergency service is blocked."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Voice service is blocked."</string>
@@ -915,9 +914,9 @@
<string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> keeps stopping"</string>
<string name="aerr_restart" msgid="9001379185665886595">"Restart app"</string>
<string name="aerr_reset" msgid="7645427603514220451">"Reset and restart app"</string>
- <string name="aerr_report" msgid="5371800241488400617">"Sending feedback"</string>
+ <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Close"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Mute"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Mute until device restarts"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Wait"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Close app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Share bug report with admin?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Your IT admin requested a bug report to help troubleshoot"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"This may temporarily slow down your device"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Taking bug report…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touch to cancel"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"App is not resizeable, scroll it with two fingers."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App does not support split-screen."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installed by your administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Disabled by %1$s administrator. Contact them to find out more."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"You have new messages"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Open SMS app to view"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Some functions might not be available"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Touch to continue"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"User profile locked"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Some functionality may be limited"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tap to unlock"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"User data locked"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Work profile locked"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tap to unlock work profile"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connected to <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tap to view files"</string>
<string name="pin_target" msgid="3052256031352291362">"Pin"</string>
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index a0a5493af1cf..7fdf1c15e5f3 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"You can\'t change the caller ID setting."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Restricted access changed"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Data service is blocked."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Emergency service is blocked."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Voice service is blocked."</string>
@@ -915,9 +914,9 @@
<string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> keeps stopping"</string>
<string name="aerr_restart" msgid="9001379185665886595">"Restart app"</string>
<string name="aerr_reset" msgid="7645427603514220451">"Reset and restart app"</string>
- <string name="aerr_report" msgid="5371800241488400617">"Sending feedback"</string>
+ <string name="aerr_report" msgid="5371800241488400617">"Send feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Close"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Mute"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Mute until device restarts"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Wait"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Close app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touch for more options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Touch to disable USB debugging."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Share bug report with admin?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Your IT admin requested a bug report to help troubleshoot"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"This may temporarily slow down your device"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Taking bug report…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touch to cancel"</string>
<string name="select_input_method" msgid="8547250819326693584">"Change keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choose keyboards"</string>
<string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"App is not resizeable, scroll it with two fingers."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App does not support split-screen."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installed by your administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Disabled by %1$s administrator. Contact them to find out more."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"You have new messages"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Open SMS app to view"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Some functions might not be available"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Touch to continue"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"User profile locked"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Some functionality may be limited"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tap to unlock"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"User data locked"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Work profile locked"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tap to unlock work profile"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connected to <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tap to view files"</string>
<string name="pin_target" msgid="3052256031352291362">"Pin"</string>
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f07745bb4bff..b101ded64de3 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Servicio no suministrado."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"No puedes cambiar la configuración del identificador de llamadas."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Se ha cambiado el acceso restringido"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencias está bloqueado."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"El servicio de voz está bloqueado."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Restablecer y reiniciar la app"</string>
<string name="aerr_report" msgid="5371800241488400617">"Enviar comentarios"</string>
<string name="aerr_close" msgid="2991640326563991340">"Cerrar"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Silenciar"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Silenciar hasta que se reinicie el dispositivo"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Cerrar app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -971,8 +970,8 @@
<string name="volume_icon_description_incall" msgid="8890073218154543397">"Volumen de la llamada"</string>
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen de los medios"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificación"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Tono de llamada predeterminado"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
+ <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
<string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca 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="1016654627626476142">"Toca para desactivar la depuración por USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"¿Quieres compartir el informe de errores con el administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"El administrador de TI solicitó un informe de errores para ayudar a solucionar el problema"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"El administrador de TI solicitó un informe de errores para ayudar a solucionar los problemas de este dispositivo. Es posible que se compartan apps y datos, y que el dispositivo se ralentice temporalmente."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"El administrador de TI solicitó un informe de errores para ayudar a solucionar los problemas de este dispositivo. Es posible que se compartan apps y datos."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Es posible que tu dispositivo se ralentice temporalmente"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Realizando un informe de errores…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toca para cancelar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar el teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para quitar fijación"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para quitar fijación"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No se puede modificar el tamaño de la app. Desplázala con dos dedos."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Es posible que la app no funcione en el modo de pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"La app no es compatible con la función de pantalla dividida."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Lo instaló el administrador."</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por el administrador"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementos seleccionados</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Estableciste la importancia de estas notificaciones."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Estableciste la importancia de estas notificaciones."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Es importante debido a las personas involucradas."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Agregar un idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferencia de región"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"El administrador de %1$s lo inhabilitó. Comunícate con él para obtener más información."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Tienes mensajes nuevos"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Abrir app de SMS para ver el mensaje"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Funciones no disponibles"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Tocar para continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil de usuario bloqueado"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funciones limitadas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Presiona para desbloquear"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Datos del usuario bloqueados"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabajo bloqueado"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Presiona para desbloquear"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Presiona para ver archivos"</string>
<string name="pin_target" msgid="3052256031352291362">"Fijar"</string>
<string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
<string name="app_info" msgid="6856026610594615344">"Información de la app"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 518b1574244c..6b2c0f8bce4b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"El servicio no se suministra."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"No puedes modificar el ID de emisor."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"El acceso restringido se ha modificado."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencia está bloqueado."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"El servicio de voz está bloqueado."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Restablecer y reiniciar aplicación"</string>
<string name="aerr_report" msgid="5371800241488400617">"Enviar sugerencias"</string>
<string name="aerr_close" msgid="2991640326563991340">"Cerrar"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Silenciar"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Silenciar hasta que se reinicie el dispositivo"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Cerrar aplicación"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para obtener más opciones"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para inhabilitarla"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"¿Compartir informe de errores con el administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas de este dispositivo. Es posible que se compartan las aplicaciones y los datos. Puede que el dispositivo funcione más lento de forma temporal."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas de este dispositivo. Es posible que se compartan las aplicaciones y los datos."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Puede que el dispositivo funcione más lento de forma temporal"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Creando informe de errores…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toca para cancelar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Elegir teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para desactivar"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para desactivar"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para desactivar"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No se puede cambiar el tamaño de la aplicación, desplázala con dos dedos."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Es posible que la aplicación no funcione con la pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"La aplicación no admite la pantalla dividida."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado por tu administrador"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seleccionados</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Tú determinas la importancia de estas notificaciones."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Tú determinas la importancia de estas notificaciones."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Esto es importante por los usuarios implicados."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g> (ya existe un usuario con esta cuenta)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Añade un idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferencia de región"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1559,12 +1558,15 @@
<skip />
<string name="new_sms_notification_title" msgid="8442817549127555977">"Tienes mensajes nuevos"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Abre la aplicación de SMS para ver el mensaje"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Algunas funciones no disponibles"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Toca para continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil de usuario bloqueado"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Algunas funciones limitadas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Toca para desbloquear"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Datos de usuario bloqueados"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabajo bloqueado"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Toca para desbloquear"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca para ver archivos"</string>
<string name="pin_target" msgid="3052256031352291362">"Fijar"</string>
<string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
<string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index bb48bd74b0d3..0236d2c84c53 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Helistaja ID pole vaikimisi piiratud. Järgmine kõne: pole piiratud"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Teenus pole ette valmistatud."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Helistaja ID seadet ei saa muuta."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Piiratud juurdepääs muutunud"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Andmesideteenus on blokeeritud."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hädaabiteenus on blokeeritud."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Häälteenus on blokeeritud."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Lähtesta ja taaskäivita rakendus"</string>
<string name="aerr_report" msgid="5371800241488400617">"Saada tagasiside"</string>
<string name="aerr_close" msgid="2991640326563991340">"Sule"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Vaigista"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Vaigista, kuni seade taaskäivitatakse"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Oota"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Sule rakendus"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Puudutage rohkemate valikute kuvamiseks."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Puudutage USB-silumise keelamiseks."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Kas jagada veaaruannet administraatoriga?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-administraator taotles veaaruannet, mis aitaks vigu otsida"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT-administraator taotles veaaruannet, mis aitaks seadmes vigu otsida. Rakendusi ja andmeid võidakse jagada ja see võib ajutiselt teie seadet aeglustada."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT-administraator taotles veaaruannet, mis aitaks seadmes vigu otsida. Rakendusi ja andmeid võidakse jagada."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"See võib ajutiselt teie seadet aeglustada"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"NÕUSTU"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KEELDU"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Veaaruande võtmine …"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Puudutage tühistamiseks"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatuuri muutmine"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vali klaviatuurid"</string>
<string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Enne vabastamist küsi avamismustrit"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Enne vabastamist küsi parooli"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Rakenduse suurust ei saa muuta. Kerige kahe sõrmega."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Rakendus ei toeta jagatud ekraani."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installis teie administraator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Värskendas administraator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> on valitud</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Mitmesugust"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Teie määrasite nende märguannete tähtsuse."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Teie määrasite nende märguannete tähtsuse."</string>
<string name="importance_from_person" msgid="9160133597262938296">"See on tähtis osalevate inimeste tõttu."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Keele-eelistus"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Keele lisamine"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Piirkonnaeelistus"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Soovitatud"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Keelas seadme %1$s administraator. Lisateabe saamiseks võtke temaga ühendust."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Teile on uusi sõnumeid"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Avage vaatamiseks SMS-rakendus"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Mõni funktsioon pole võib-olla saadaval"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Puudutage jätkamiseks"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Kasutajaprofiil on lukustatud"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funktsioon võib olla piiratud"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Avamiseks puudutage"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Kasutaja andmed on lukustatud"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Tööprofiil on lukustatud"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Puudut. tööprofiili avamiseks"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Ühendatud seadmega <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Failide vaatamiseks puudutage"</string>
<string name="pin_target" msgid="3052256031352291362">"Kinnita"</string>
<string name="unpin_target" msgid="3556545602439143442">"Vabasta"</string>
<string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index a595603f4775..67776e737109 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenik gabe"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Zerbitzua ez da hornitu."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Ezin duzu deien identifikazio-zerbitzuaren ezarpena aldatu."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Sarbide murriztua aldatu da"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datu-zerbitzua blokeatuta dago."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Larrialdi-zerbitzua blokeatuta dago."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Ahots-zerbitzua blokeatuta dago."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Berrezarri eta berrabiarazi aplikazioa"</string>
<string name="aerr_report" msgid="5371800241488400617">"Bidali iritzia"</string>
<string name="aerr_close" msgid="2991640326563991340">"Itxi"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ezkutatu"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ezkutatu gailua berrabiarazi arte"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Itxaron"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Itxi aplikazioa"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Ukitu aukera gehiago ikusteko."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB arazketa desgaitzeko, ukitu hau."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Partekatu nahi duzu administratzailearekin akatsen txostena?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IKT administratzaileak akatsen txostena eskatu du arazoa konpontzen laguntzeko"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea, eta agian motelago ibiliko da gailua aldi batez."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Agian motelago ibiliko da gailua aldi batez"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ONARTU"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"BAZTERTU"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Akatsen txostena sortzen…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Ukitu bertan behera uzteko"</string>
<string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Aukeratu teklatuak"</string>
<string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ezin da aldatu aplikazioaren tamaina. Erabili bi hatz aplikazioan gora eta behera egiteko."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila banatua"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Administratzaileak instalatu du"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> hautatuta</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Askotarikoak"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Zuk ezarri zenuen jakinarazpen hauen garrantzia."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Zuk ezarri duzu jakinarazpen hauen garrantzia."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu? (Badago kontu hori duen erabiltzaile bat)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Hizkuntza-hobespena"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza bat"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Lurralde-hobespena"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Desgaitu egin du %1$s gailuaren administratzaileak. Informazio gehiago lortu nahi baduzu, jarri harekin harremanetan."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Mezu berriak dituzu"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Mezuak ikusteko, ireki SMS mezuen aplikazioa"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Baliteke funtzio batzuk ez egotea"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Ukitu jarraitzeko"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Blokeatuta dago profila"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funtzioak mugatuta egon litezke"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Sakatu desblokeatzeko"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Blokeatuta daude datuak"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Blokeatuta dago laneko profila"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Sakatu profila desblokeatzeko"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> zerbitzura konektatuta"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Sakatu fitxategiak ikusteko"</string>
<string name="pin_target" msgid="3052256031352291362">"Ainguratu"</string>
<string name="unpin_target" msgid="3556545602439143442">"Kendu aingura"</string>
<string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 14b87e874349..feae1cada19f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"پیش‌فرض شناسه تماس گیرنده روی غیر محدود است. تماس بعدی: بدون محدودیت"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"سرویس دارای مجوز نیست."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"‏شما می‎توانید تنظیم شناسه تماس گیرنده را تغییر دهید."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"دسترسی محدود تغییر یافت"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"سرویس داده مسدود است."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"سرویس اضطراری مسدود است."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"سرویس صوتی مسدود شده است."</string>
@@ -890,7 +889,7 @@
<string name="yes" msgid="5362982303337969312">"تأیید"</string>
<string name="no" msgid="5141531044935541497">"لغو"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"توجه"</string>
- <string name="loading" msgid="7933681260296021180">"در حال بارگیری..."</string>
+ <string name="loading" msgid="7933681260296021180">"در حال بارکردن…"</string>
<string name="capital_on" msgid="1544682755514494298">"روشن"</string>
<string name="capital_off" msgid="6815870386972805832">"خاموش"</string>
<string name="whichApplication" msgid="4533185947064773386">"تکمیل عملکرد با استفاده از"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"بازنشانی و راه‌اندازی مجدد برنامه"</string>
<string name="aerr_report" msgid="5371800241488400617">"ارسال بازخورد"</string>
<string name="aerr_close" msgid="2991640326563991340">"بستن"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"بی‌صدا کردن"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"صامت کردن تا وقتی دستگاه راه‌اندازی مجدد شود"</string>
<string name="aerr_wait" msgid="3199956902437040261">"انتظار"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"بستن برنامه"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"برای گزینه‌های بیشتر لمس کنید."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏اشکال‌زدایی USB متصل شد"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"‏غیرفعال‌کردن اشکال‌زدایی‌USB: با لمس آن."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"گزارش اشکال را با سرپرست سیستم به اشتراک می‌گذارید؟"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"سرپرست فناوری اطلاعات شما برای کمک به عیب‌یابی، گزارش اشکال درخواست کرد"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"درحال اشتراک‌گذاری گزارش اشکال…‏"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"سرپرست فناوری اطلاعات شما برای کمک به عیب‌یابی این دستگاه، درخواست گزارش اشکال کرده است. ممکن است برنامه‌ها و داده‌ها به اشتراک گذاشته شوند و سرعت دستگاهتان به‌طور موقت کاهش یابد."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"سرپرست فناوری اطلاعات شما برای کمک به عیب‌یابی این دستگاه، گزارش اشکال درخواست کرده است. ممکن است برنامه‌ها و داده‌ها به اشتراک گذاشته شوند."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ممکن است سرعت دستگاهتان به‌طور موقت کاهش یابد"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"پذیرفتن"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"نپذیرفتن"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"درحال گرفتن گزارش اشکال…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"برای لغو کردن لمس کنید"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغییر صفحه‌کلید"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"انتخاب صفحه‌کلیدها"</string>
<string name="show_ime" msgid="2506087537466597099">"وقتی صفحه‌کلید فیزیکی فعال است این ویرایشگر را روی صفحه نگه‌می‌دارد"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"درخواست الگوی باز کردن قفل قبل از برداشتن پین"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"درخواست گذرواژه قبل از برداشتن پین"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"اندازه برنامه قابل تغییر نیست، با دو انگشت آن را پیمایش کنید."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ممکن است برنامه با تقسیم صفحه کار نکند."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"برنامه از تقسیم صفحه پشتیبانی نمی‌کند."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"توسط سرپرستتان نصب شد"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"توسط سرپرست شما به‌روزرسانی شد"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
<item quantity="other">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقه"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
<string name="importance_from_person" msgid="9160133597262938296">"به دلیل افراد درگیر مهم است."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"به <xliff:g id="APP">%1$s</xliff:g> امکان داده شود کاربر جدیدی با <xliff:g id="ACCOUNT">%2$s</xliff:g> اضافه کند؟"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"به <xliff:g id="APP">%1$s</xliff:g> امکان داده شود کاربر جدیدی با <xliff:g id="ACCOUNT">%2$s</xliff:g> ایجاد کند (کاربری با این حساب از قبل وجود دارد)؟"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"اولویت‌های زبان"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"افزودن زبان"</string>
<string name="country_selection_title" msgid="2954859441620215513">"اولویت‌های منطقه"</string>
<string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"پیشنهادشده"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"‏سرپرست %1$s آن را غیرفعال کرده است. برای اطلاعات بیشتر با او تماس بگیرید."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"پیام‌های جدیدی دارید"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"برای مشاهده، برنامه پیامک را باز کنید"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"شاید برخی عملکردها دردسترس نباشند"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"برای ادامه لمس کنید"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"نمایه کاربر قفل است"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ممکن است برخی از عملکردها محدود باشند"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"برای باز کردن قفل، ضربه بزنید"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"داده‌های کاربر قفل هستند"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"نمایه کاری قفل است"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"برای باز کردن قفل ضربه بزنید"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"به <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> متصل شد"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"برای دیدن فایل‌ها، ضربه بزنید"</string>
<string name="pin_target" msgid="3052256031352291362">"پین کردن"</string>
<string name="unpin_target" msgid="3556545602439143442">"برداشتن پین"</string>
<string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c15c3dbded63..2f0a36148ff9 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Soittajan tunnukseksi muutetaan rajoittamaton. Seuraava puhelu: ei rajoitettu"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Palvelua ei tarjota."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Et voi muuttaa soittajan tunnuksen asetusta."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Rajoitettua oikeutta muutettu"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Tiedonsiirtopalvelu on estetty."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hätäpalvelu on estetty."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Äänipalvelu on estetty."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Nollaa sovellus ja käynnistä uudelleen"</string>
<string name="aerr_report" msgid="5371800241488400617">"Lähetä palautetta"</string>
<string name="aerr_close" msgid="2991640326563991340">"Sulje"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ohita"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Mykistä laitteen uudelleenkäynnistykseen asti"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Odota"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Sulje sovellus"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Lisää vaihtoehtoja koskettamalla"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sulje USB-vianetsintä koskettamalla."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Jaetaanko virheraportti järjestelmänvalvojalle?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-järjestelmänvalvojasi pyysi virheraporttia voidakseen auttaa vianetsinnässä."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa, ja laitteen toiminta voi hidastua väliaikaisesti."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Tämä voi hidastaa laitteen toimintaa väliaikaisesti."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"HYVÄKSY"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"HYLKÄÄ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Luodaan virheraporttia…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Peruuta koskettamalla"</string>
<string name="select_input_method" msgid="8547250819326693584">"Vaihda näppäimistö"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Valitse näppäimistöt"</string>
<string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN ennen irrotusta"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pyydä salasana ennen irrotusta"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Sovelluksen kokoa ei voi muuttaa. Vieritä näkymää kahdella sormella."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Sovellus ei ehkä toimi jaetulla näytöllä."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Sovellus ei tue jaetun näytön tilaa."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Järjestelmänvalvoja on asentanut paketin."</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Järjestelmänvalvojasi on päivittänyt paketin."</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valittu</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Muut"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Voit valita näiden ilmoitusten tärkeyden."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Voit valita näiden ilmoitusten tärkeyden."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Myönnetäänkö sovellukselle <xliff:g id="APP">%1$s</xliff:g> oikeus luoda käyttäjä tilille <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Myönnetäänkö sovellukselle <xliff:g id="APP">%1$s</xliff:g> oikeus luoda käyttäjä tilille <xliff:g id="ACCOUNT">%2$s</xliff:g> (tilillä on jo käyttäjä)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Kieliasetus"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Lisää kieli"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Alueasetus"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Ehdotukset"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Organisaation %1$s järjestelmänvalvojan käytöstä poistama. Kysy häneltä lisätietoja."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Sinulle on uusia viestejä"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Katso avaamalla tekstiviestisovellus."</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Osaa toiminnoista ei ehkä voi käyttää"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Jatka koskettamalla."</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Käyttäjäprofiili on lukittu."</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Toimintorajoitus mahdollinen"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Avaa napauttamalla."</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Käyttäjän tiedot on lukittu."</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Työprofiili on lukittu."</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Avaa profiili koskettamalla."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> yhdistetty"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Näytä tiedostot koskettamalla"</string>
<string name="pin_target" msgid="3052256031352291362">"Kiinnitä"</string>
<string name="unpin_target" msgid="3556545602439143442">"Irrota"</string>
<string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 3443d4d39ad5..4dce7e65ff6a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'accès limité a été modifié."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Le service de données est bloqué."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Le service d\'appel d\'urgence est bloqué."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Le service vocal est bloqué."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Réinitialiser et redémarrer l\'application"</string>
<string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
<string name="aerr_close" msgid="2991640326563991340">"Fermer"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Désactiver les notifications"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Désactiver jusqu\'au redémarrage de l\'appareil"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Attendre"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Fermer l\'application"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Appuyez pour désactiver le débogage USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Partager le rapport de bogue avec l\'administrateur?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à résoudre le problème"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées. Cela pourrait temporairement ralentir votre appareil."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Cela pourrait temporairement ralentir votre appareil."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Création d\'un rapport de bogue en cours..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touchez pour annuler"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choisir les claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Impossible de redimensionner l\'application. Faites-la défiler avec deux doigts."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installé par votre administrateur"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Vous définissez l\'importance de ces notifications."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur associé à ce compte existe déjà.)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Préférences linguistiques"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Ajouter une langue"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Préférences régionales"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Cette option a été désactivée par l\'administrateur de %1$s. Communiquez avec lui pour en savoir plus."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Vous avez de nouveaux messages"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Ouvrez l\'application de messagerie texte pour l\'afficher"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Certaines fonct. p-ê non dispo."</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Touchez pour continuer"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil d\'utilisateur verrouillé"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Certaines fonct. sont limitées"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Touchez pour déverrouiller"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Données utilisat. verrouillées"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil professionnel verrouillé"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Touch. pr déver. profil profess."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connecté à <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Touchez ici pour afficher les fichiers"</string>
<string name="pin_target" msgid="3052256031352291362">"Épingler"</string>
<string name="unpin_target" msgid="3556545602439143442">"Annuler l\'épinglage"</string>
<string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 662076dff4c7..c8ef7d0c5d63 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'accès limité a été modifié."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Le service de données est bloqué."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Le service d\'appel d\'urgence est bloqué."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Le service vocal est bloqué."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Réinitialiser et redémarrer l\'application"</string>
<string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
<string name="aerr_close" msgid="2991640326563991340">"Fermer"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorer"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorer jusqu\'au redémarrage de l\'appareil"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Attendre"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Fermer l\'application"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Appuyez pour afficher plus d\'options"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désact. débogage USB"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Partager le rapport de bug avec l\'administrateur ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème lié à cet appareil. Il est possible que des applications et des données soient partagées et que votre appareil ralentisse temporairement."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème lié à cet appareil. Il est possible que des applications et des données soient partagées."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ceci risque de ralentir temporairement votre appareil."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Création du rapport de bug…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Appuyer pour annuler"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Sélectionner des claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Il est impossible de redimensionner l\'application. Faites-la défiler avec deux doigts."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Application incompatible avec l\'écran partagé."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installé par votre administrateur"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Vous définissez l\'importance de ces notifications."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Préférences linguistiques"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Ajouter une langue"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Préférences régionales"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Recommandations"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Désactivé par l\'administrateur %1$s. Contactez-le pour en savoir plus."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Vous avez de nouveaux messages"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Ouvrir l\'application de SMS pour afficher le message"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Certaines fonctions potentiellement non dispos"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Appuyer pour continuer"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil utilisateur verrouillé"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Des fonctionnalités peuvent être limitées"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Appuyer pour déverrouiller"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Infos sur utilis. verrouillées"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil professionnel verrouillé"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"App. pour déver. profil profes."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connecté à <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Appuyez ici pour voir les fichiers."</string>
<string name="pin_target" msgid="3052256031352291362">"Épingler"</string>
<string name="unpin_target" msgid="3556545602439143442">"Retirer"</string>
<string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"− <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index f2e1850bfd0f..41c600de0225 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"De forma predeterminada, non se restrinxe o ID de chamada. Próxima chamada: non restrinxido."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Servizo non ofrecido."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Non podes cambiar a configuración do ID de chamada."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Modificouse o acceso restrinxido"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"O servizo de datos está bloqueado."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"O servizo de urxencia está bloqueado."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"O servizo de voz está bloqueado."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Restablecer e reiniciar aplicación"</string>
<string name="aerr_report" msgid="5371800241488400617">"Dános a túa opinión"</string>
<string name="aerr_close" msgid="2991640326563991340">"Pechar"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorar fallos ata que o dispositivo se reinicie"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Pechar aplicación"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Toca aquí para desactivala"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Queres compartir o informe de erros co administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar problemas"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar os problemas deste dispositivo. É posible que se compartan aplicacións e datos e que se reduza a velocidade do teu dispositivo temporalmente."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar os problemas deste dispositivo. É posible que se compartan aplicacións e datos."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Esta acción pode reducir a velocidade do teu dispositivo temporalmente"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ANULAR"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Creando informe de erros…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tocar para cancelar o informe de erros"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar un padrón de desbloqueo antes de soltar a pantalla"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar un contrasinal antes de soltar a pantalla"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Non se pode cambiar o tamaño da aplicación. Desprázate por ela con dous dedos."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Pode que a aplicación non funcione coa pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"A aplicación non é compatible coa función de pantalla dividida."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado polo administrador"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado polo administrador"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">Seleccionáronse <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ti defines a importancia destas notificacións."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ti defines a importancia destas notificacións."</string>
<string name="importance_from_person" msgid="9160133597262938296">"É importante polas persoas involucradas."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Engadir un idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferencia de rexión"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"O administrador de %1$s desactivou este paquete. Contacta con el para obter máis información."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Tes mensaxes novas"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Abre a aplicación de SMS para ver as mensaxes"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Quizais haxa funcións non dispoñibles"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Toca para continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Bloqueouse o perfil do usuario"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Pode haber funcións limitadas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Toca para desbloquear"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Datos do usuario bloqueados"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de traballo bloqueado"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Toca para desbloquear o perfil"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca para ver os ficheiros"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixar"</string>
<string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
<string name="app_info" msgid="6856026610594615344">"Información da aplicación"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index ec613b096b9b..0bda139a5486 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"કૉલર ID પ્રતિબંધિત નહીં પર ડિફોલ્ટ છે. આગલો કૉલ: પ્રતિબંધિત નહીં"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"સેવાની જોગવાઈ કરી નથી."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"તમે કૉલર ID સેટિંગ બદલી શકતાં નથી."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"પ્રતિબંધિત ઍક્સેસ બદલાઈ"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ડેટા સેવા અવરોધિત છે."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"કટોકટીની સેવા અવરોધિત છે."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"વૉઇસ સેવા અવરોધિત છે."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ફરીથી સેટ કરો અને ઍપ્લિકેશનને ફરીથી પ્રારંભ કરો"</string>
<string name="aerr_report" msgid="5371800241488400617">"પ્રતિસાદ મોકલો"</string>
<string name="aerr_close" msgid="2991640326563991340">"બંધ કરો"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"મ્યૂટ કરો"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ઉપકરણ પુનઃપ્રારંભ ન થાય ત્યાં સુધી મ્યૂટ કરો"</string>
<string name="aerr_wait" msgid="3199956902437040261">"રાહ જુઓ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ઍપ્લિકેશન બંધ કરો"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"વધુ વિકલ્પો માટે ટચ કરો."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ડીબગિંગ અક્ષમ કરવા માટે ટચ કરો."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"વ્યવસ્થાપક સાથે બગ રિપોર્ટ શેર કરીએ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"તમારા IT વ્યવસ્થાપક એ સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"બગ રિપોર્ટ શેર કરીએ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"બગ રિપોર્ટ શેર કરી રહ્યાં છે…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"તમારા IT વ્યવસ્થાપક એ આ ઉપકરણની સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે. ઍપ્લિકેશનો અને ડેટા શેર કરવામાં આવી શકે છે અને તમારા ઉપકરણને અસ્થાયી રૂપે ધીમું કરી શકે છે."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"તમારા IT વ્યવસ્થાપક એ આ ઉપકરણની સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે. ઍપ્લિકેશનો અને ડેટા શેર કરવામાં આવી શકે છે."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"આ અસ્થાયી રૂપે તમારા ઉપકરણને ધીમું કરી શકે છે"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"સ્વીકારો"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"નકારો"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"બગ રિપોર્ટ લઈ રહ્યાં છે…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"રદ કરવા માટે ટચ કરો"</string>
<string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"કીબોર્ડ્સ પસંદ કરો"</string>
<string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"અનપિન કરતાં પહેલાં PIN માટે પૂછો"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"અનપિન કરતા પહેલાં અનલૉક પેટર્ન માટે પૂછો"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"અનપિન કરતાં પહેલાં પાસવર્ડ માટે પૂછો"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ઍપ્લિકેશનનું કદ બદલવા યોગ્ય નથી, બે આંગળીઓ વડે તેને સ્ક્રોલ કરો."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"વિભાજિત-સ્ક્રીન સાથે ઍપ્લિકેશન કદાચ કામ ન કરે."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"તમારા વ્યવસ્થાપક દ્વારા ઇન્સ્ટોલ કરેલ"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ થયેલ"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"વિવિધ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
<string name="importance_from_person" msgid="9160133597262938296">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ને <xliff:g id="ACCOUNT">%2$s</xliff:g> સાથે એક નવા વપરાશકર્તાને બનાવવાની મંજૂરી આપીએ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> સાથે <xliff:g id="APP">%1$s</xliff:g> ને એક નવા વપરાશકર્તાને બનાવવાની મંજૂરી આપીએ (આ એકાઉન્ટ સાથેના એક વપરાશકર્તા પહેલાંથી અસ્તિત્વમાં છે)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ભાષા પસંદગી"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"એક ભાષા ઉમેરો"</string>
<string name="country_selection_title" msgid="2954859441620215513">"પ્રદેશ પસંદગી"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"સૂચવેલા"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ. વધુ જાણવા માટે તેમનો સંપર્ક કરો."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"તમારી પાસે નવા સંદેશા છે"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"જોવા માટે SMS ઍપ્લિકેશન ખોલો"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"કેટલાક કાર્યો કદાચ ઉપલબ્ધ ન હોય"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ચાલુ રાખવા માટે ટચ કરો"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"વપરાશકર્તા પ્રોફાઇલ લૉક કરી"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"કેટલીક કાર્યક્ષમતા મર્યાદિત હોઈ શકે છે"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"અનલૉક કરવા માટે ટૅપ કરો"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"વપરાશકર્તા ડેટા લૉક કર્યો"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"કાર્ય પ્રોફાઇલ લૉક કરી"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"કાર્ય પ્રોફાઇલ અનલૉક કરવા ટૅપ કરો"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> થી કનેક્ટ કરેલું છે"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ફાઇલો જોવા માટે ટૅપ કરો"</string>
<string name="pin_target" msgid="3052256031352291362">"પિન કરો"</string>
<string name="unpin_target" msgid="3556545602439143442">"અનપિન કરો"</string>
<string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4c944c3095b8..995c9c74100c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कॉलर ID प्रतिबंधित नहीं पर डिफ़ॉल्‍ट है. अगली कॉल: प्रतिबंधित नहीं"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवा प्रावधान की हुई नहीं है."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"आप कॉलर आईडी सेटिंग नहीं बदल सकते."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"प्रतिबंधित पहुंच बदली गई"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"डेटा सेवा अवरोधित है."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"आपातकालीन सेवा अवरोधित है."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"ध्‍वनि सेवा अवरोधित है."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ऐप रीसेट करें और पुन: प्रारंभ करें"</string>
<string name="aerr_report" msgid="5371800241488400617">"फ़ीडबैक भेजें"</string>
<string name="aerr_close" msgid="2991640326563991340">"बंद करें"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"म्यूट करें"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"डिवाइस पुन: प्रारंभ होने तक म्यूट करें"</string>
<string name="aerr_wait" msgid="3199956902437040261">"प्रतीक्षा करें"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ऐप बंद करें"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"और विकल्पों के लिए स्पर्श करें."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करना अक्षम करने के लिए स्‍पर्श करें."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"व्यवस्थापक के साथ बग रिपोर्ट साझा करें?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"समस्या निवारण में सहायता हेतु आपके आईटी व्यवस्थापक ने बग रिपोर्ट के लिए अनुरोध किया है"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"इस डिवाइस के समस्या निवारण में सहायता हेतु आपके आईटी व्यवस्थापक ने बग रिपोर्ट के लिए अनुरोध किया है. ऐप्स और डेटा को साझा किया जा सकता है और आपके डिवाइस की गति अस्थायी रूप से धीमी हो सकती है."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"आपके आईटी व्यवस्थापक ने इस डिवाइस के समस्या निवारण में सहायता के लिए एक बग रिपोर्ट का अनुरोध किया है. ऐप्स और डेटा साझा किए जा सकते हैं."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"इससे आपका डिवाइस अस्थायी रूप से धीमा हो सकता है"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करें"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार करें"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"रद्द करने के लिए स्पर्श करें"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड चुनें"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्‍क्रीन पर बनाए रखें"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करने से पहले पिन के लिए पूछें"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"अनपिन करने से पहले अनलॉक पैटर्न के लिए पूछें"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"अनपिन करने से पहले पासवर्ड के लिए पूछें"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ऐप का आकार बदला नहीं जा सकता है, इसे दो अंगुलियों से स्क्रॉल करें."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"हो सकता है कि ऐप्लिकेशन विभाजित स्क्रीन के साथ काम ना करे."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ऐप विभाजित स्‍क्रीन का समर्थन नहीं करता है."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"आपके नियंत्रक द्वारा इंस्‍टॉल किया गया"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"आपके नियंत्रक द्वारा अपडेट किया गया"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
<string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के द्वारा एक नया उपयोगकर्ता बनाने दें?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के द्वारा एक नया उपयोगकर्ता बनाने दें (इस खाते वाला एक उपयोगकर्ता पहले से मौजूद है) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"भाषा प्राथमिकता"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"भाषा जोड़ें"</string>
<string name="country_selection_title" msgid="2954859441620215513">"क्षेत्र प्राथमिकता"</string>
<string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाए गए"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s व्‍यवस्‍थापक द्वारा अक्षम किया गया. अधिक जानने के लिए उनसे संपर्क करें."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"आपके पास नए संदेश हैं"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"देखने के लिए SMS ऐप खोलें"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"संभवत: कुछ फंक्‍शन उपलब्‍ध न हों"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"जारी रखने के लिए स्‍पर्श करें"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"उपयोगकर्ता प्रोफ़ाइल लॉक है"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"कुछ कार्य क्षमताएं सीमित हो सकती हैं"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"अनलॉक करने के लिए टैप करें"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"उपयोगकर्ता डेटा लॉक किया गया"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"कार्य प्रोफ़ाइल लॉक है"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"कार्य प्रोफाइल अनलॉक करने हेतु टैप करें"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> से कनेक्ट किया गया"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फ़ाइलें देखने के लिए टैप करें"</string>
<string name="pin_target" msgid="3052256031352291362">"पिन करें"</string>
<string name="unpin_target" msgid="3556545602439143442">"अनपिन करें"</string>
<string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 855e1f7627ce..823181ddaafb 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -89,7 +89,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Zadana postavka ID-a pozivatelja nema ograničenje. Sljedeći poziv: Nije ograničen"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Usluga nije rezervirana."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete promijeniti postavku ID-a pozivatelja."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Promijenjen je ograničeni pristup"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Podatkovna usluga je blokirana."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hitna usluga je blokirana."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna usluga je blokirana."</string>
@@ -923,7 +922,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Vrati aplikaciju na zadano i pokreni ponovo"</string>
<string name="aerr_report" msgid="5371800241488400617">"Pošalji povratne informacije"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Zanemari"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Zanemari do ponovnog pokretanja uređaja"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Čekaj"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zatvori aplikaciju"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,12 +1060,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za uklanjanje pogrešaka USB-om"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da se onemogući otklanjanje pogrešaka USB-om."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Želite li podijeliti izvješće o programskoj pogrešci s administratorom?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Vaš IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema na uređaju. Moguće je da će se aplikacije i podaci dijeliti, što bi moglo privremeno usporiti uređaj."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema na uređaju. Moguće je da će se aplikacije i podaci dijeliti."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"To bi moglo privremeno usporiti uređaj"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Izrada izvješća o programskoj pogrešci…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Dodirnite da biste otkazali"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promjena tipkovnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Odaberi tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
@@ -1477,7 +1477,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži uzorak za otključavanje radi otkvačivanja"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži zaporku radi otkvačivanja"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veličina aplikacije ne može se mijenjati, pomičite je s dva prsta."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava podijeljeni zaslon."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurira vaš administrator"</string>
@@ -1556,12 +1556,11 @@
<item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> odabrane</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> odabranih</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Postavili ste važnost tih obavijesti."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Postavili ste važnost tih obavijesti."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Važno je zbog uključenih osoba."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Želite li dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Želite li dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s tim računom već postoji)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Postavke jezika"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dodavanje jezika"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Postavke regije"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
@@ -1574,12 +1573,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Onemogućio administrator (%1$s). Obratite mu se za više informacija."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nove poruke"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorite SMS aplikaciju da biste pregledali poruke"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Možda ima nedostupnih funkcija"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Dodirnite da biste nastavili"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Korisnički je profil zaključan"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funkcije mogu biti ograničene"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Dodirnite za otključavanje"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Korisnički podaci zaključani"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Radni je profil zaključan"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Dodirnite za otključavanje"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> – veza je uspostavljena"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dodirnite da biste pregledali datoteke"</string>
<string name="pin_target" msgid="3052256031352291362">"Prikvači"</string>
<string name="unpin_target" msgid="3556545602439143442">"Otkvači"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index bede9983eb12..015e13da4054 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"A hívóazonosító alapértelmezett értéke nem korlátozott. Következő hívás: nem korlátozott"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"A szolgáltatás nincs biztosítva."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Nem tudja módosítani a hívó fél azonosítója beállítást."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"A korlátozott hozzáférés módosítva"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Az adatszolgáltatás le van tiltva."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"A segélyszolgáltatás le van tiltva."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"A hangszolgáltatás letiltva."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Alkalmazás alaphelyzetbe állítása és újraindítása"</string>
<string name="aerr_report" msgid="5371800241488400617">"Visszajelzés küldése"</string>
<string name="aerr_close" msgid="2991640326563991340">"Bezárás"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Némítás"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Némítás az eszköz újraindulásáig"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Várakozás"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Alkalmazás bezárása"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Érintse meg a további lehetőségekhez."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Érintse meg az USB hibakeresés kikapcsolásához."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Megosztja a hibajelentést a rendszergazdával?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"A rendszergazda hibajelentést kért, hogy segíthessen a problémamegoldásban"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"A rendszergazda hibajelentést kért, hogy segíthessen az eszközzel kapcsolatos probléma megoldásában. Előfordulhat, hogy a rendszer megosztja az alkalmazásokat és adatokat, továbbá eszköze átmenetileg lelassulhat."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"A rendszergazda hibajelentést kért, hogy segíthessen az eszközzel kapcsolatos probléma megoldásában. Előfordulhat, hogy a rendszer megosztja az alkalmazásokat és adatokat."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Előfordulhat, hogy eszköze emiatt átmenetileg lelassul"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ELFOGADOM"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ELUTASÍTOM"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Hibajelentés készítése…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"A visszavonáshoz érintse meg"</string>
<string name="select_input_method" msgid="8547250819326693584">"Billentyűzet megváltoztatása"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Billentyűzetek kiválasztása"</string>
<string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-kód kérése a rögzítés feloldásához"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Feloldási minta kérése a rögzítés feloldásához"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Jelszó kérése a rögzítés feloldásához"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Az alkalmazást nem lehet átméretezni – két ujjal görgessen."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"A rendszergazda telepítette"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Frissítette a rendszergazda"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kiválasztva</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Vegyes"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ön állította be ezen értesítések fontossági szintjét."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ön állította be ezen értesítések fontossági szintjét."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ez az üzenet a résztvevők miatt fontos."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Nyelvi beállítás"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Nyelv hozzáadása"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Régió beállítása"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Javasolt"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"A(z) %1$s szervezet rendszergazdája letiltotta. További információért vegye fel vele a kapcsolatot."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Új üzenetei érkeztek"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"SMS-alkalmazás megnyitása a megtekintéshez"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Néhány funkció nem használható"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Érintse meg a folytatáshoz"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Felhasználói profil zárolva"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Egyes funkciók korlátozva lehetnek"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Koppintson a feloldáshoz"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Felhasználói adatok zárolva"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Munkahelyi profil zárolva"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"A feloldáshoz koppintson rá"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Csatlakoztatva a(z) <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> eszközhöz"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Koppintson ide a fájlok megtekintéséhez"</string>
<string name="pin_target" msgid="3052256031352291362">"Rögzítés"</string>
<string name="unpin_target" msgid="3556545602439143442">"Feloldás"</string>
<string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 3890ef8e480e..3a564911c3f9 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Զանգողի ID-ն լռելյայն չսահմանափակված է: Հաջորդ զանգը` չսահմանափակված"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Ծառայությունը չի տրամադրվում:"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Դուք չեք կարող փոխել զանգողի ID-ի կարգավորումները:"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Սահմանափակված մուտքը փոխված է"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Տվյալների ծառայությունն արգելափակված է:"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Արտակարգ իրավիճակի ծառայությունն արգելափակված է:"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Ձայնային ծառայությունը արգելափակված է:"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Վերակայել և վերագործարկել հավելվածը"</string>
<string name="aerr_report" msgid="5371800241488400617">"Ուղարկել կարծիք"</string>
<string name="aerr_close" msgid="2991640326563991340">"Փակել"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Անջատել ձայնը"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Անջատել ձայնը մինչև սարքի վերագործարկումը"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Սպասել"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Փակել հավելվածը"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Հպեք` USB կարգաբերումը կասեցնելու համար:"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ուղարկե՞լ վրիպակի զեկույց ադմինիստրատորին:"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Վրիպակի զեկույցի տրամադրում…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց: Կարող են տրամադրվել տեղեկություններ ձեր հավելվածների մասին և այլ տվյալներ, իսկ սարքի աշխատանքը կարող է ժամանակավորապես դանդաղել:"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց: Կարող են տրամադրվել տեղեկություններ ձեր հավելվածներնի մասին և այլ տվյալներ:"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Այդ ընթացքում ձեր սարքի աշխատանքը կարող է դանդաղել"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ԸՆԴՈՒՆԵԼ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ՄԵՐԺԵԼ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Վրիպակի զեկույցի ստեղծում…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Հպեք՝ չեղարկելու համար"</string>
<string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Ընտրել ստեղնաշար"</string>
<string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ապաամրացնելուց առաջ հարցնել ապակողպող նախշը"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ապաամրացնելուց առաջ հարցնել գաղտնաբառը"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Հավելվածի չափը հնարավոր չէ փոխել, ոլորեք այն երկու մատի օգնությամբ:"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում:"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Ադմինիստրատորը տեղադրել է այն"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ադմինիստրատորը թարմացրել է այն"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Զանազան"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
<string name="importance_from_person" msgid="9160133597262938296">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Թույլ տա՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտվող ստեղծել:"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Թույլ տա՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտվող ստեղծել (նման հաշվով Օգտվող արդեն գոյություն ունի):"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Նախընտրելի լեզու"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Ավելացնել լեզու"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Նախընտրելի տարածաշրջան"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Առաջարկներ"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Կասեցվել է %1$s ադմինիստրատորի կողմից: Ավելին իմանալու համար կապվեք նրա հետ:"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Դուք ունեք նոր հաղորդագրություններ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Դիտելու համար բացել SMS հավելվածը"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Հնարավոր է՝ որոշ գործառույթներ հասանելի չլինեն"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Հպեք՝ շարունակելու համար"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Օգտվողի պրոֆիլը կողպված է"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Որոշ գործառույթներ կարող են սահմանափակված լինել"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Հպեք՝ ապակողպելու համար"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Օգտվողի տվյալները կողպված են"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Աշխատանքային պրոֆիլը կողպված է"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Հպեք՝ այն ապակողպելու համար"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Միացված է <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-ին"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Հպեք՝ ֆայլերը տեսնելու համար"</string>
<string name="pin_target" msgid="3052256031352291362">"Ամրացնել"</string>
<string name="unpin_target" msgid="3556545602439143442">"Ապամրացնել"</string>
<string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4d4f45e1dd44..2391ef746693 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nomor penelepon default tidak dibatasi. Panggilan selanjutnya: Tidak dibatasi"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Layanan tidak diperlengkapi."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Anda tidak dapat mengubah setelan nomor penelepon."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Akses terbatas berubah"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Layanan data dicekal."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Layanan darurat dicekal."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Layanan suara dicekal."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Setel ulang dan mulai ulang aplikasi"</string>
<string name="aerr_report" msgid="5371800241488400617">"Kirim masukan"</string>
<string name="aerr_close" msgid="2991640326563991340">"Tutup"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Bisukan"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Bisukan hingga perangkat dimulai ulang"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Tunggu"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Tutup aplikasi"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk opsi lainnya."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk menonaktifkan debugging USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Bagikan laporan bug kepada admin?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Admin IT meminta laporan bug untuk membantu memecahkan masalah"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Admin IT meminta laporan bug untuk membantu memecahkan masalah perangkat ini. Aplikasi dan data mungkin dibagikan dan untuk sementara perangkat mungkin menjadi lambat."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Admin IT meminta laporan bug untuk membantu memecahkan masalah perangkat ini. Aplikasi dan data mungkin dibagikan."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Tindakan ini mungkin memperlambat perangkat untuk sementara"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SETUJU"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Mengambil laporan bug…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Sentuh untuk membatalkan"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ubah keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pilih keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Pertahankan di layar jika keyboard fisik masih aktif"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Meminta PIN sebelum melepas sematan"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Meminta pola pembukaan kunci sebelum melepas sematan"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Meminta sandi sebelum melepas sematan"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Aplikasi tidak dapat diubah ukurannya, gulir dengan dua jari."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App tidak mendukung layar terpisah."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Diperbarui oleh administrator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Lain-Lain"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Anda menyetel tingkat kepentingan notifikasi ini."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Anda menyetel nilai penting notifikasi ini."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ini penting karena orang-orang yang terlibat."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferensi bahasa"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Tambahkan bahasa"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferensi wilayah"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Disarankan"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Dinonaktifkan oleh administrator %1$s. Hubungi administrator untuk mempelajari lebih lanjut."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Ada pesan baru"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Buka aplikasi SMS untuk melihat"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Beberapa fungsi tidak ada"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Sentuh untuk melanjutkan"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil pengguna terkunci"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Beberapa fungsi mungkin terbatas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Ketuk untuk membuka kunci"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Data pengguna dikunci"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil kerja terkunci"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Ketuk untuk membuka kunci profil kerja"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Tersambung ke <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Ketuk untuk melihat file"</string>
<string name="pin_target" msgid="3052256031352291362">"Pasang pin"</string>
<string name="unpin_target" msgid="3556545602439143442">"Lepas pin"</string>
<string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 4ad48a943b0f..82465840d71b 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Númerabirting er sjálfgefið án takmarkana. Næsta símtal: Án takmarkana"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Þjónustu ekki útdeilt."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Þú getur ekki breytt stillingu númerabirtingar."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Takmörkuðum aðgangi breytt"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Lokað er fyrir gagnaþjónustu."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Lokað er fyrir neyðarþjónustu."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Lokað er fyrir raddþjónustu."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Endurstilla og endurræsa forritið"</string>
<string name="aerr_report" msgid="5371800241488400617">"Senda ábendingu"</string>
<string name="aerr_close" msgid="2991640326563991340">"Loka"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Þagga"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Þagga þangað til tæki er endurræst"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Bíða"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Loka forriti"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Snertu til að fá fleiri valkosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Snertu til að slökkva á USB-villuleit."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Deila villutilkynningu með kerfisstjóra?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit á þessu tæki. Forritum og gögnum verður hugsanlega deilt og mögulegt er að þetta hægi tímabundið á tækinu."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit á þessu tæki. Forritum og gögnum verður hugsanlega deilt."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Hugsanlega hægir þetta tímabundið á tækinu þínu"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SAMÞYKKJA"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"HAFNA"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Tekur við villutilkynningu…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Snertu til að hætta við"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skipta um lyklaborð"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Velja lyklaborð"</string>
<string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Biðja um opnunarmynstur til að losa"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Biðja um aðgangsorð til að losa"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ekki er hægt að breyta stærð forritsins; flettu upp og niður með tveimur fingrum."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Hugsanlega virkar forritið ekki ef skjánum er skipt upp."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Forritið styður ekki að skjánum sé skipt."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Uppsett af kerfisstjóra"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Uppfært af kerfisstjóranum"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> valið</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Ýmislegt"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Þú stilltir mikilvægi þessara tilkynninga."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Þú stilltir mikilvægi þessara tilkynninga."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Val tungumáls"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Bæta við tungumáli"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Svæðisval"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Tillögur"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Gert óvirkt af stjórnanda %1$s. Hafðu samband við hann til að fá frekari upplýsingar."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Þú ert með ný skilaboð"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Opnaðu SMS-forritið til að skoða"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Sumir eiginleikar e.t.v. ekki í boði"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Snertu til að halda áfram"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Notandaprófíll læstur"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Sum virkni kann að vera takmörkuð"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Ýttu til að opna"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Notendagögn læst"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Vinnusnið læst"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Ýttu til að opna vinnusnið"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Tengt við <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Ýttu til að skoða skrárnar"</string>
<string name="pin_target" msgid="3052256031352291362">"Festa"</string>
<string name="unpin_target" msgid="3556545602439143442">"Losa"</string>
<string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7cd29d7d2029..912f15495ee1 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Servizio non fornito."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Non è possibile modificare l\'impostazione ID chiamante."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Accesso limitato modificato"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Il servizio dati è bloccato."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Il servizio di emergenza è bloccato."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Il servizio vocale è bloccato."</string>
@@ -349,8 +348,8 @@
<string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul tablet, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Consente all\'app di aggiungere, rimuovere o modificare eventi che è possibile modificare sulla TV, inclusi quelli di amici o colleghi. L\'app potrebbe inviare messaggi apparentemente provenienti dai proprietari del calendario o modificare eventi all\'insaputa dei proprietari."</string>
<string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul telefono, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi provider di geolocalizz."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
<string name="permlab_accessFineLocation" msgid="251034415460950944">"accesso alla posizione esatta (basata su GPS e rete)"</string>
<string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"accesso alla posizione approssimativa (basata sulla rete)"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Reimposta e riavvia app"</string>
<string name="aerr_report" msgid="5371800241488400617">"Invia feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Chiudi"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Disattiva"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Disattiva fino al riavvio del dispositivo"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Attendi"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Chiudi app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tocca per visualizzare più opzioni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tocca per disattivare il debug USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Condividere la segnalazione di bug con l\'amministratore?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi di questo dispositivo. Potrebbero essere condivisi dati e app e il dispositivo potrebbe rallentare temporaneamente."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi di questo dispositivo. Potrebbero essere condivisi dati e app."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Il dispositivo potrebbe rallentare temporaneamente"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCETTO"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RIFIUTO"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Recupero della segnalazione di bug…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tocca per annullare"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Scegli tastiera"</string>
<string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN per lo sblocco"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Richiedi sequenza di sblocco prima di sbloccare"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Richiedi password prima di sbloccare"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Non è possibile ridimensionare l\'app: scorri con due dita."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"L\'app potrebbe non funzionare con lo schermo diviso."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'app non supporta la modalità Schermo diviso."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installato dall\'amministratore"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Aggiornato dall\'amministratore"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Vari"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Stabilisci tu l\'importanza di queste notifiche."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Stabilisci tu l\'importanza di queste notifiche."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Importante a causa delle persone coinvolte."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Esiste già un utente con questo account)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferenza lingua"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Aggiungi una lingua"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Area geografica preferita"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerite"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Disattivato dall\'amministratore di %1$s. Contattalo per ulteriori informazioni."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Hai nuovi messaggi"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Apri l\'app SMS per la visualizzazione"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Alcune funzioni potrebbero non essere disponibili"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Tocca per continuare"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profilo utente bloccato"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funzioni potenzial. limitate"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tocca per sbloccare"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Dati utente bloccati"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profilo di lavoro bloccato"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tocca per sbloc. prof. di lav."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connesso a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tocca per visualizzare i file"</string>
<string name="pin_target" msgid="3052256031352291362">"Blocca"</string>
<string name="unpin_target" msgid="3556545602439143442">"Sblocca"</string>
<string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8337b2e32a8b..c334a3ccd49d 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"זיהוי מתקשר עובר כברירת מחדל למצב לא מוגבל. השיחה הבאה: לא מוגבלת"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"השירות לא הוקצה."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"אינך יכול לשנות את הגדרת זיהוי המתקשר."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"גישה מוגבלת השתנתה"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"שירות הנתונים חסום."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"שירות חירום חסום."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"השירות הקולי חסום."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"אפס והפעל מחדש את האפליקציה"</string>
<string name="aerr_report" msgid="5371800241488400617">"שלח משוב"</string>
<string name="aerr_close" msgid="2991640326563991340">"סגור"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"השתק"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"השתק עד הפעלה מחדש של המכשיר"</string>
<string name="aerr_wait" msgid="3199956902437040261">"המתן"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"סגור את האפליקציה"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"גע להצגת עוד אפשרויות."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניפוי באגים של USB מחובר"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"‏גע כדי להשבית ניפוי באגים בהתקן ה-USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"האם לשתף את הדוח על הבאג עם מנהל המערכת?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"‏מנהל ה-IT ביקש דוח על באג כדי לסייע בפתרון בעיות"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"האם לשתף דוח על באג?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"שיתוף דוח על באג…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"‏מנהל ה-IT ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו. פעילות המכשיר עשויה להאט באופן זמני."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"‏מנהל ה-IT שלך ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"קצב הפעולה של המכשיר עשוי להיות איטי יותר באופן זמני כתוצאה מכך"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"אישור"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"דחייה"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"עיבוד דוח על באג..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"גע כדי לבטל"</string>
<string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"בחר מקלדות"</string>
<string name="show_ime" msgid="2506087537466597099">"השאר אותו במסך בזמן שהמקלדת הפיזית פעילה"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏בקש PIN לפני ביטול הצמדה"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"בקש קו ביטול נעילה לפני ביטול הצמדה"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"בקש סיסמה לפני ביטול הצמדה"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"אין אפשרות לשנות את גודל האפליקציה, גלול אותה בשתי אצבעות."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ייתכן שהיישום לא יפעל עם מסך מפוצל."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"האפליקציה אינה תומכת במסך מפוצל."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"הותקנה על ידי מנהל המערכת שלך"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"עודכן על ידי מנהל המערכת שלך"</string>
@@ -1575,12 +1575,11 @@
<item quantity="other">בחרת <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">בחרת <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"שונות"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"האם לאפשר ל-<xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש לחשבון <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"האם לאפשר ל-<xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש לחשבון <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"העדפת שפה"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"הוספת שפה"</string>
<string name="country_selection_title" msgid="2954859441620215513">"העדפת אזור"</string>
<string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"הצעות"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"‏הושבתה על ידי מנהל המערכת של %1$s. צור איתו קשר כדי לקבל מידע נוסף."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"יש לך הודעות חדשות"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"‏פתח את אפליקציית ה-SMS כדי להציג"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ייתכן שפונקציות מסוימות לא יהיו זמינות"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"גע כדי להמשיך"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"פרופיל המשתמש נעול"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ייתכן שחלק מהפונקציונליות תהיה מוגבלת"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"הקש כדי לבטל את הנעילה"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"נתוני משתמש נעולים"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"פרופיל העבודה נעול"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"הקש לביטול נעילת פרופיל העבודה"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"מחובר אל <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"הקש כדי להציג קבצים"</string>
<string name="pin_target" msgid="3052256031352291362">"הצמד"</string>
<string name="unpin_target" msgid="3556545602439143442">"בטל הצמדה"</string>
<string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 237d7797f73a..9ee8e0e58990 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"既定: 発信者番号通知、次の発信: 通知"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"提供可能なサービスがありません。"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"発信者番号の設定は変更できません。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"アクセス制限が変更されました"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"データサービスがブロックされています。"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"緊急サービスがブロックされています。"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"音声サービスがブロックされています。"</string>
@@ -918,7 +917,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"アプリをリセットして再起動"</string>
<string name="aerr_report" msgid="5371800241488400617">"フィードバックを送信"</string>
<string name="aerr_close" msgid="2991640326563991340">"閉じる"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"ミュート"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"端末が再起動するまでミュート"</string>
<string name="aerr_wait" msgid="3199956902437040261">"待機"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"アプリを閉じる"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1054,12 +1053,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"タップしてその他のオプションを表示"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効化"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"管理者とバグレポートを共有しますか?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT 管理者からトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"バグレポートを共有しますか?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"バグレポートの共有中…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT 管理者からこの端末のトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました。アプリやデータが共有され、端末の動作が一時的に遅くなる場合があります。"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT 管理者からこの端末のトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました。アプリやデータが共有されることがあります。"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"共有によって端末の動作が一時的に遅くなる場合があります"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"同意する"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"同意しない"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"バグレポートを取得しています…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"キャンセルするにはタップしてください"</string>
<string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string>
<string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
@@ -1468,7 +1468,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"オフライン再生を解除する前にパスワードの入力を求める"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"アプリのサイズは変更できません。2 本の指でスクロールしてください。"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"アプリは分割画面では動作しないことがあります。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"アプリで分割画面がサポートされていません。"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"管理者によってインストールされました"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"管理者によって更新されています"</string>
@@ -1538,12 +1538,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>件選択済み</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>件選択済み</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"その他"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"このような通知の重要度を設定します。"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"このような通知の重要度を設定します。"</string>
<string name="importance_from_person" msgid="9160133597262938296">"関係するユーザーのため、この設定は重要です。"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"言語設定"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"言語を追加"</string>
<string name="country_selection_title" msgid="2954859441620215513">"地域設定"</string>
<string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string>
@@ -1561,12 +1560,15 @@
<skip />
<string name="new_sms_notification_title" msgid="8442817549127555977">"新着メッセージがあります"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"表示するには SMS アプリを開きます"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"一部の機能が利用できない可能性"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"続行するにはタップしてください"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ユーザー プロフィールはロックされています"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"一部機能が制限されている可能性"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"ロック解除するにはタップします"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ユーザーデータはロック状態です"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"仕事用プロファイル: ロック"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"タップしてプロファイルをロック解除"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> に接続しました"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"タップしてファイルを表示"</string>
<string name="pin_target" msgid="3052256031352291362">"固定"</string>
<string name="unpin_target" msgid="3556545602439143442">"固定を解除"</string>
<string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index fc11729fcab0..8e4e3783e6ea 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ნაგულისხმებად დაყენებულია ნომრის დაფარვის გამორთვა. შემდეგი ზარი: არ არის დაფარული."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"სერვისი არ არის მიწოდებული."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"არ შეგიძლიათ აბონენტის ID პარამეტრების შეცვლა."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"წვდომის შეზღუდვები შეცვლილია"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ინტერნეტი დაბლოკილია."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"გადაუდებელი სამსახური დაბლოკილია."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"ხმოვანი მომსახურება დაბლოკილია."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"გადაყენება და აპის გადატვირთვა"</string>
<string name="aerr_report" msgid="5371800241488400617">"გამოხმაურება"</string>
<string name="aerr_close" msgid="2991640326563991340">"დახურვა"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"დადუმება"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"დადუმება მოწყობილობის გადატვირთვამდე"</string>
<string name="aerr_wait" msgid="3199956902437040261">"მოცდა"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"აპის დახურვა"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"შეეხეთ დამატებითი პარამეტრებისთვის."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"შეეხეთ, რათა შეწყვიტოთ USB-ის გამართვა."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"გსურთ ხარვეზის შესახებ ანგარიშის ადმინისტრატორთან გაზიარება?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"პრობლემის აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს."</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"გსურთ ხარვეზის შესახებ ანგარიშის გაზიარება?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გაზიარება…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ამ მოწყობილობის პრობლემების აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს, რა დროსაც შეიძლება გაზიარდეს აპები და მონაცემები, ხოლო თქვენი მოწყობილობა დროებით შენელდეს."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ამ მოწყობილობის პრობლემების აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს, რა დროსაც შეიძლება გაზიარდეს აპები და მონაცემები."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ამან შეიძლება დროებით შეანელოს თქვენი მოწყობილობა"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"მიღება"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"უარყოფა"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის შექმნა…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"შეეხეთ გასაუქმებლად"</string>
<string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"კლავიატურების არჩევა"</string>
<string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"აპის ზომა ვერ შეიცვლება. გადაადგილდით მასში ორი თითის მეშვეობით."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"თქვენი ადმინისტრატორის მიერ დაყენებული"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> შერჩეული</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> შერჩეული</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"სხვადასხვა"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრება თქვენ მიერ."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string>
<string name="importance_from_person" msgid="9160133597262938296">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს, <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს, <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ენის პარამეტრები"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ენის დამატება"</string>
<string name="country_selection_title" msgid="2954859441620215513">"რეგიონის პარამეტრები"</string>
<string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"რეკომენდებული"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"გათიშულია „%1$s“-ის ადმინისტრატორის მიერ. დაუკავშირდით მას მეტის გასაგებად."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"თქვენ ახალი შეტყობინებები გაქვთ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"სანახავად, გახსენით SMS აპი"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ზოგიერთი ფუნქცია შეიძლება მიუწვდომელი იყოს"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"შეეხეთ გასაგრძელებლად"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"მომხმარებლის პროფილი ჩაკეტილია"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ზოგიერთი ფუნქცია შეიძლება შეიზღუდოს"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"შეეხეთ განსაბლოკად"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"მომხმ.-ის მონაცემები ჩაკეტილია"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"სამსახურის პროფილი ჩაკეტილია"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"შეეხეთ პროფილის განსაბლოკად"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"დაკავშირებულია <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-თან"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"შეეხეთ ფაილების სანახავად"</string>
<string name="pin_target" msgid="3052256031352291362">"ჩამაგრება"</string>
<string name="unpin_target" msgid="3556545602439143442">"ჩამაგრების მოხსნა"</string>
<string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 7e6025d5de18..c14bc6829c7e 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Қоңырау шалушының жеке анықтағышы бастапқы бойынша шектелмеген. Келесі қоңырау: Шектелмеген"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Қызмет ұсынылмаған."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Қоңырау шалушы идентификаторы параметрін өзгерту мүмкін емес."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Шектелген қол жетімділік өзгертілген"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Дерекқор қызметі бөгелген."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Төтенше қызмет бөгелген."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Дауыс қызметі бөгелген."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Ысырып, қолданбаны қайта іске қосу"</string>
<string name="aerr_report" msgid="5371800241488400617">"Пікір жіберу"</string>
<string name="aerr_close" msgid="2991640326563991340">"Жабу"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Үнсіз"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Құрылғы қайта іске қосылғанша дыбысын өшіру"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Күту"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Қолданбаны жабу"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Қосымша параметрлер үшін түртіңіз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB жөндеу қосылған"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB жөндеуді өшіру үшін түртіңіз."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Қате туралы есепті әкімшімен бөлісу керек пе?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"АТ әкімшісі ақауларды жоюға көмектесу үшін қате туралы есепті сұрады"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Қате туралы есепті бөлісу керек пе?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Қате туралы есеп бөлісілуде…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"АТ әкімшісі осы құрылғы ақауларын жоюға көмектесу үшін қате туралы есепті сұрады. Қолданбалар және деректер бөлісілуі әрі құрылғының жұмысы уақытша баяулауы мүмкін."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"АТ әкімшісі осы құрылғы ақауларын жоюға көмектесу үшін қате туралы есепті сұрады. Қолданбалар және деректер бөлісілуі мүмкін."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Бұл құрылғы жұмысын уақытша баяулатуы мүмкін"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ҚАБЫЛДАУ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ҚАБЫЛДАМАУ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Қате туралы есеп құрылуда…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Бас тарту үшін түртіңіз"</string>
<string name="select_input_method" msgid="8547250819326693584">"Пернетақтаны өзгерту"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Пернетақталарды таңдау"</string>
<string name="show_ime" msgid="2506087537466597099">"Физикалық пернетақта белсенді кезде оны экранда ұстау"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Босату алдында бекітпесін ашу өрнегін сұрау"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Босату алдында құпия сөзді сұрау"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Қолданба өлшемін өзгерту мүмкін емес, оны екі саусақпен айналдырыңыз."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Қолданба бөлінген экранда жұмыс істемеуі мүмкін."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Қодланба бөлінген экранды қолдамайды."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Әкімші орнатқан"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Әкімші жаңартты"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> таңдалды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> таңдалды</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Әр түрлі"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Сіз осы хабарландырулардың маңыздылығын орнатасасыз."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Қатысты адамдарға байланысты бұл маңызды."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат ету керек пе?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасында жаңа пайдаланушы жасауға рұқсат ету керек пе (осы есептік жазбасы бар пайдаланушы әлдеқашан бар) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Тіл параметрі"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Тілді қосу"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Аймақ параметрі"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Ұсынылған"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s әкімшісі өшірген. Қосымша мәліметтер алу үшін оларға хабарласыңыз."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Сізде жаңа хабарлар бар"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Көру үшін SMS қолданбасын ашыңыз"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Кейбір функциялар қол жетімді болмауы мүмкін"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Жалғастыру үшін түртіңіз"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Пайдаланушы профилі құлыпталған"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Кейбір функциялар істемеуі мүмкін"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Құлыпты ашу үшін түртіңіз"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Пайдаланушы деректері құлыптаулы"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Жұмыс профилі құлыптаулы"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Жұмыс профилінің құлпын ашу үшін түртіңіз"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> қосылу орындалды"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлдарды көру үшін түртіңіз"</string>
<string name="pin_target" msgid="3052256031352291362">"PIN код"</string>
<string name="unpin_target" msgid="3556545602439143442">"Босату"</string>
<string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 0ca72a7b49d8..0becd326b06c 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"មិន​បាន​ដាក់កម្រិត​លំនាំដើម​លេខ​សម្គាល់​អ្នក​ហៅ។ ការ​ហៅ​បន្ទាប់៖ មិន​បាន​ដាក់​កម្រិត។"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"មិន​បាន​ផ្ដល់​សេវាកម្ម។"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"អ្នក​មិន​អាច​ប្ដូរ​ការ​កំណត់​លេខ​សម្គាល់​អ្នក​ហៅ​បានទេ។"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"បាន​ប្ដូរ​ការ​ចូល​ដំណើរការ​ដែល​បាន​ដាក់​​កម្រិត"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"បាន​ទប់ស្កាត់​សេវាកម្ម​ទិន្នន័យ។"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"បាន​ទប់ស្កាត់​សេវាកម្ម​ពេល​អាសន្ន។"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"សេវាកម្ម​សំឡេង​ត្រូវ​បាន​ទប់ស្កាត់។"</string>
@@ -919,7 +918,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"កំណត់ និងចាប់ផ្តើមកម្មវិធីឡើងវិញ"</string>
<string name="aerr_report" msgid="5371800241488400617">"ផ្ញើមតិ"</string>
<string name="aerr_close" msgid="2991640326563991340">"បិទ"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"បិទ"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"បិទរហូតដល់ឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="aerr_wait" msgid="3199956902437040261">"រង់ចាំ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"បិទកម្មវិធី"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1055,12 +1054,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ប៉ះដើម្បីបានជម្រើសថែមទៀត។"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"បាន​ភ្ជាប់​ការ​កែ​កំហុស​យូអេសប៊ី"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"ប៉ះ ដើម្បី​បិទ​ការ​កែ​កំហុស​យូអេសប៊ី។"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ចែករំលែករបាយការណ៍កំហុសជាមួយអ្នកគ្រប់គ្រងឬ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"អ្នកគ្រប់គ្រងព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីជួយដោះស្រាយបញ្ហា"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ចែករំលែករបាយការណ៍កំហុសឬ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"កំពុងចែករំលែករបាយកំហុស…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីដោះស្រាយកំហុសឧបករណ៍នេះ។ កម្មវិធី និងទិន្នន័យអាចនឹងត្រូវបានចែករំលែក ហើយឧបករណ៍របស់អ្នកអាចនឹងយឺតជាបណ្តោះអាសន្ន។"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីដោះស្រាយកំហុសឧបករណ៍នេះ។ កម្មវិធី និងទិន្នន័យអាចនឹងត្រូវបានចែករំលែក។"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"វាអាចនឹងធ្វើឲ្យឧបករណ៍របស់អ្នកយឺតជាបណ្តោះអាសន្ន។"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ព្រមទទួល"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"បដិសេធ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ទទួលយករបាយការណ៍កំហុស…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ប៉ះដើម្បីបោះបង់"</string>
<string name="select_input_method" msgid="8547250819326693584">"ប្ដូរ​ក្ដារចុច"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ជ្រើស​ក្ដារចុច"</string>
<string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
@@ -1469,7 +1469,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួរ​រក​កូដ PIN មុន​ពេល​ផ្ដាច់"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"សួរ​រក​លំនាំ​ដោះ​សោ​មុន​ពេល​ផ្ដាច់"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"សួរ​រក​ពាក្យ​សម្ងាត់​មុន​ពេល​ផ្ដាច់"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"កម្មវិធីមិនអាចផ្លាស់ប្តូរទំហំបានទេ សូមរមូរវាដោយប្រើម្រាមដៃពីរ។"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"កម្មវិធីអាចនឹងមិនដំណើរការនៅលើអេក្រង់បំបែកទេ"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"បានដំឡើងដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"បានធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
@@ -1539,12 +1539,11 @@
<item quantity="other">បានជ្រើស <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">បានជ្រើស <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"ផ្សេងៗ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
<string name="importance_from_person" msgid="9160133597262938296">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"អនុញ្ញាតឲ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ឬទេ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"អនុញ្ញាតឲ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (មានអ្នកប្រើសម្រាប់គណនីនេះរួចហើយ) ឬទេ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ចំណូល​ចិត្ត​ភាសា"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"បន្ថែមភាសា"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ចំណូលចិត្តតំបន់"</string>
<string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"បាន​ស្នើ"</string>
@@ -1557,12 +1556,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"បិទដំណើរការដោយអ្នកគ្រប់គ្រង %1$s។ សូមទាក់ទងពួកគេដើម្បីស្វែងយល់បន្ថែម។"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"អ្នកមានសារថ្មី"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"បើកកម្មវិធីសារ SMS ដើម្បីមើល"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"មុខងារមួយចំនួនមិនអាចប្រើបានទេ"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ប៉ះដើម្បីបន្ត"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ប្រវត្តិរូបអ្នកប្រើត្រូវបានចាក់សោ"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"លទ្ធភាពប្រើមុខងារមួយចំនួនអាចត្រូវបាកម្រិត"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"ប៉ះដើម្បីដោះសោ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ទិន្នន័យអ្នកប្រើជាប់សោ"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"ប្រវត្តិរូបការងារត្រូវជាប់សោ"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"ប៉ះដើម្បីដោះសោប្រវត្តិរូបការងារ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"បានភ្ជាប់ទៅ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ប៉ះដើម្បីមើលឯកសារ"</string>
<string name="pin_target" msgid="3052256031352291362">"ខ្ទាស់"</string>
<string name="unpin_target" msgid="3556545602439143442">"មិនខ្ទាស់"</string>
<string name="app_info" msgid="6856026610594615344">"ព័ត៌មាន​កម្មវិធី"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index d251f82a4a50..eeb156cdcd42 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ಕರೆಮಾಡುವವರ ID ಅನ್ನು ನಿರ್ಬಂಧಿಸದಿರುವಂತೆ ಡೀಫಾಲ್ಟ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದಿನ ಕರೆ: ನಿರ್ಬಂಧಿಸಲಾಗಿಲ್ಲ"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"ಸೇವೆಯನ್ನು ಪೂರೈಸಲಾಗಿಲ್ಲ."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"ನೀವು ಕಾಲರ್‌ ID ಸೆಟ್ಟಿಂಗ್‌ ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ನಿರ್ಬಂಧಿತ ಪ್ರವೇಶವನ್ನು ಬದಲಿಸಲಾಗಿದೆ"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ಡೇಟಾ ಸೇವೆಯನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"ತುರ್ತು ಸೇವೆಯನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"ಧ್ವನಿ ಸೇವೆಯನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ಅಪ್ಲಿಕೇಶನ್ ಮರುಹೊಂದಿಸಿ ಮತ್ತು ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
<string name="aerr_report" msgid="5371800241488400617">"ಪ್ರತಿಕ್ರಿಯೆ ಕಳುಹಿಸು"</string>
<string name="aerr_close" msgid="2991640326563991340">"ಮುಚ್ಚು"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"ಮ್ಯೂಟ್"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ಸಾಧನವು ಮರುಪ್ರಾರಂಭವಾಗುವವರೆಗೂ ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
<string name="aerr_wait" msgid="3199956902437040261">"ನಿರೀಕ್ಷಿಸು"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಮುಚ್ಚಿ"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ಡೀಬಗಿಂಗ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ದೋಷ ವರದಿಯನ್ನು ನಿರ್ವಾಹಕರ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳುವುದೇ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ಸಮಸ್ಯೆ ನಿವಾರಣೆಗೆ ಸಹಾಯ ಮಾಡಲು ದೋಷ ವರದಿಯನ್ನು ಮನವಿ ಮಾಡಿದ್ದಾರೆ"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚುವುದೇ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ಈ ಸಾಧನದ ಸಮಸ್ಯೆ ನಿವಾರಿಸುವುದಕ್ಕೆ ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಬಗ್‌ ವರದಿಯನ್ನು ವಿನಂತಿಸಿದ್ದಾರೆ. ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು ಹಾಗು ನಿಮ್ಮ ಸಾಧನವು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಧಾನಗೊಳ್ಳಬಹುದು."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ಈ ಸಾಧನದ ಸಮಸ್ಯೆ ನಿವಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಬಗ್ ವರದಿಯನ್ನು ವಿನಂತಿಸಿದ್ದಾರೆ. ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ಇದು ನಿಮ್ಮ ಸಾಧನವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಧಾನಗೊಳಿಸಬಹುದು"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ಸಮ್ಮತಿಸು"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ತಿರಸ್ಕರಿಸು"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ರದ್ದುಗೊಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ಕೀಬೋರ್ಡ್‌ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಿನ್‌ ಕೇಳು"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅನ್‌ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಕೇಳಿ"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್ ಕೇಳು"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ, ಅದನ್ನು ಎರಡು ಬೆರಳುಗಳಿಂದ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ವಿಭಜಿಸಿದ ಪರದೆಯಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಸ್ಥಾಪಿಸಲಾಗಿದೆ"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ನವೀಕರಿಸಲಾಗಿದೆ"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"ಇತರೆ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (ಈ ಖಾತೆಯ ಬಳಕೆದಾರರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದ್ದಾರೆ) ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ಭಾಷೆಯ ಪ್ರಾಶಸ್ತ್ಯ"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ಭಾಷೆ ಸೇರಿಸಿ"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸಲಹೆ ಮಾಡಿರುವುದು"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s ನಿರ್ವಾಹಕರಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಇನ್ನಷ್ಟು ತಿಳಿದುಕೊಳ್ಳಲು ಅವರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"ನೀವು ಹೊಸ ಸಂದೇಶಗಳನ್ನು ಹೊಂದಿರುವಿರಿ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"ವೀಕ್ಷಿಸಲು SMS ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ಕೆಲವು ಫಂಕ್ಷನ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲದಿರಬಹುದು"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ಮುಂದುವರಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ಬಳಕೆದಾರ ಪ್ರೊಫೈಲ್ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ಕೆಲವು ಕಾರ್ಯನಿರ್ವಹಣೆಗಳು ಸೀಮಿತವಾಗಿರಬಹುದು"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ಫೈಲ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
<string name="pin_target" msgid="3052256031352291362">"ಪಿನ್ ಮಾಡು"</string>
<string name="unpin_target" msgid="3556545602439143442">"ಅನ್‌ಪಿನ್"</string>
<string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index db8f5a6ee34b..349696285b49 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"서비스가 준비되지 않았습니다."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"발신자 번호 설정을 변경할 수 없습니다."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"제한된 액세스가 변경되었습니다."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"데이터 서비스가 차단되었습니다."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"긴급 서비스가 차단되었습니다."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"음성 서비스가 차단되었습니다."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"앱 재설정 및 다시 시작"</string>
<string name="aerr_report" msgid="5371800241488400617">"의견 보내기"</string>
<string name="aerr_close" msgid="2991640326563991340">"닫기"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"숨기기"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"기기가 다시 시작될 때까지 알림 끄기"</string>
<string name="aerr_wait" msgid="3199956902437040261">"대기"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"앱 닫기"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"더 많은 옵션을 확인하려면 터치하세요."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB 디버깅을 사용하지 않으려면 터치하세요."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"관리자와 버그 보고서를 공유하시겠습니까?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT 관리자가 문제해결을 위해 버그 보고서를 요청했습니다."</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"버그 보고서를 공유하시겠습니까?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"버그 신고서 공유 중..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT 관리자가 이 기기의 문제해결을 위해 버그 신고서를 요청했습니다. 앱과 데이터가 공유될 수 있으며 기기 속도가 일시적으로 느려질 수 있습니다."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT 관리자가 이 기기의 문제해결을 위해 버그 보고서를 요청했습니다. 앱과 데이터가 공유될 수 있습니다."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"이로 인해 일시적으로 기기 속도가 느려질 수 있습니다."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"수락"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"거절"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"버그 보고서 가져오는 중..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"취소하려면 터치하세요."</string>
<string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"키보드 선택"</string>
<string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"고정 해제 이전에 잠금해제 패턴 요청"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"고정 해제 이전에 비밀번호 요청"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"앱에서 크기 조절이 불가능합니다. 두 손가락을 사용해 스크롤하세요."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"앱이 화면 분할을 지원하지 않습니다."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"관리자가 설치함"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"관리자에 의해 업데이트됨"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개 선택됨</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"기타"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"이러한 알림의 중요도를 설정했습니다."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"이러한 알림의 중요도를 설정했습니다."</string>
<string name="importance_from_person" msgid="9160133597262938296">"관련된 사용자가 있으므로 중요합니다."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="ACCOUNT">%2$s</xliff:g>(으)로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="ACCOUNT">%2$s</xliff:g>(이 계정의 사용자가 이미 있음)(으)로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"언어 환경설정"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"언어 추가"</string>
<string name="country_selection_title" msgid="2954859441620215513">"지역 환경설정"</string>
<string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"추천"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s 관리자에 의해 사용 중지되었습니다. 자세히 알아보려면 관리자에게 문의하세요."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"새 메시지 있음"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"SMS 앱을 열고 확인"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"일부 기능을 사용할 수 없음"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"계속하려면 터치하세요."</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"사용자 프로필이 잠겨 있습니다."</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"일부 기능이 제한될 수 있습니다."</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"잠금 해제하려면 탭하세요."</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"사용자 데이터 잠김"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"직장 프로필 잠김"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"탭하여 직장 프로필 잠금 해제"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>에 연결됨"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"파일을 확인하려면 탭하세요."</string>
<string name="pin_target" msgid="3052256031352291362">"고정"</string>
<string name="unpin_target" msgid="3556545602439143442">"고정 해제"</string>
<string name="app_info" msgid="6856026610594615344">"앱 정보"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index d2d9ed1ff591..018e05454a80 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Номурду аныктоонун демейки абалы \"чектелбейт\" деп коюлган. Кийинки чалуу: Чектелбейт"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Кызмат камсыздалган эмес."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Чалуучунун далдаштырма дайындары жөндөөлөрүн өзгөртө албайсыз."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Чектелген мүмкүнчүлүк өзгөртүлдү"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Мобилдик Интернет бөгөттөлгөн."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Өзгөчө кырдаал кызматы бөгөттөлгөн."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Үн кызматы бөгөттөлгөн."</string>
@@ -918,7 +917,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Колдонмону баштапкы абалга келтирип, кайра жүргүзүү"</string>
<string name="aerr_report" msgid="5371800241488400617">"Жооп пикир жөнөтүү"</string>
<string name="aerr_close" msgid="2991640326563991340">"Жабуу"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Үнсүз"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Түзмөк өчүрүлүп-күйгүзүлгүчө үнүн өчүрүү"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Күтүү"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Колдонмону жабуу"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1054,12 +1053,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Көбүрөөк параметр үчүн тийип коюңуз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB мүчүлүштүктөрдү оңдоо туташтырылган"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB мүчүлүштүктөрдү жоюу мүмкүнчүлүгүн өчүрүү үчүн тийип коюңуз."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Администратор менен мүчүлүштүктөр тууралуу кабар бөлүшүлсүнбү?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Бул маалыматтын жардамы менен бузулган жерлерди аныктап, оңдоп берет."</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Мүчүлүштүк тууралуу баяндама бөлүшүлсүнбү?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Мүчүлүштүк тууралуу баяндама бөлүшүлүүдө…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Бул түзмөктүн бузулууларын аныктап оңдоо үчүн IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Колдонмолор менен дайындар бөлүшүлүп, түзмөгүңүз жайыраак иштеп калышы мүмкүн."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Бул түзмөктүн бузулууларын аныктап оңдоо үчүн IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Колдонмолор менен дайындар бөлүшүлүшү мүмкүн."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ушуну менен түзмөгүңүздүн ылдамдыгы убактылуу төмөндөйт"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"КАБЫЛ АЛУУ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ЧЕТКЕ КАГУУ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Жокко чыгаруу үчүн тийип коюңуз"</string>
<string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Баскычтопторду тандаңыз"</string>
<string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
@@ -1468,7 +1468,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Бошотуудан мурун кулпуну ачкан үлгү суралсын"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Бошотуудан мурун сырсөз суралсын"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Колдонмонун көлөмүн өзгөртүүгө болбойт, андыктан эки манжаңыз менен сыдырып караңыз."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Колдонмо бөлүнгөн экранда иштебей калышы мүмкүн."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Колдонмодо экран бөлүнбөйт."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Администраторуңуз тарабынан орнотулган"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string>
@@ -1538,12 +1538,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Калган-каткандар"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби (мындай каттоо эсеби бар колдонуучу мурунтан эле бар) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Тил жөндөөлөрү"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Тилди кошуңуз"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Чөлкөмдүк жөндөөлөр"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
@@ -1556,12 +1555,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s администратору тарабынан өчүрүлгөн. Көбүрөөк билүү үчүн администраторго кайрылыңыз."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Сизге жаңы билдирүүлөр келди"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Көрүү үчүн SMS колдонмосун ачыңыз"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Айрым функциялар иштбши мүмкн"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Улантуу үчүн тийип коюңуз"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Колдонуучнн профили кулпулнгн"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Айрым функциялар чектлши мүмкн"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Кулпусун ачуу үчүн таптаңыз"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Колдончнн дайындары кулпуланды"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Жумуш профили кулпуланган"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Таптап жумуш профилин ачыңыз"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> менен туташты"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлдарды көрүү үчүн таптап коюңуз"</string>
<string name="pin_target" msgid="3052256031352291362">"Кадоо"</string>
<string name="unpin_target" msgid="3556545602439143442">"Кадоодон алып коюу"</string>
<string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ldrtl-television/config.xml b/core/res/res/values-ldrtl-television/config.xml
new file mode 100644
index 000000000000..e237acc62746
--- /dev/null
+++ b/core/res/res/values-ldrtl-television/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 may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 TV products. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
+ <string translatable="false" name="config_defaultPictureInPictureBounds">"112 54 592 324"</string>
+
+</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index a52f9577539b..abe9b3f23c27 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ໝາຍເລກຜູ່ໂທ ໄດ້ຮັບການຕັ້ງຄ່າເລີ່ມຕົ້ນເປັນ ບໍ່ຖືກຈຳກັດ. ການໂທຄັ້ງຕໍ່ໄປ: ບໍ່ຖືກຈຳກັດ."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"ບໍ່ໄດ້ເປີດໃຊ້ບໍລິການ."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"ທ່ານບໍ່ສາມາດປ່ຽນແປງການຕັ້ງຄ່າ Caller ID"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ປ່ຽນການເຂົ້າເຖິງທີ່ຖືກຈຳກັດແລ້ວ"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ບໍລິການຂໍ້ມູນຖືກບລັອກ."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"ບໍລິການສຸກເສີນຖືກບລັອກ."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"ບໍລິການການໂທຖືກປິດກັ້ນໄວ້."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ຣີເຊັດ ແລະ ເລີ່ມແອັບໃໝ່"</string>
<string name="aerr_report" msgid="5371800241488400617">"ສົ່ງຄຳຕິຊົມ"</string>
<string name="aerr_close" msgid="2991640326563991340">"ປິດ"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"ປິດສຽງ"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ປິດສຽງຈົນກວ່າວ່າອຸປະກອນເລີ່ມໃໝ່"</string>
<string name="aerr_wait" msgid="3199956902437040261">"ລໍຖ້າ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ປິດແອັບ"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ສຳ​ພັດ​ສຳ​ລັບ​ທາງ​ເລືອກ​ເພີ່ມ​ເຕີມ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"ເຊື່ອມຕໍ່ການດີບັ໊ກຜ່ານ USB ແລ້ວ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"ແຕະເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ແບ່ງປັນລາຍງານຂໍ້ຜິດພາດກັບຜູ້ເບິ່ງແຍງລະບົບບໍ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍເອົາລາຍງານຂໍ້ຜິດພາດເພື່ອຊ່ວຍແກ້ໄຂບັນຫາ"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ແບ່ງປັນລາຍງານບັນຫາບໍ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ກຳລັງແບ່ງປັນລາຍງານບັນຫາ…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍລາຍງານຂໍ້ຜິດພາດເພື່ອຊ່ວຍແກ້ໄຂບັນຫາອຸປະກອນນີ້. ແອັບ ແລະ ຂໍ້ມູນອາດຖືກແບ່ງປັນ ແລະ ອຸປະກອນຂອງທ່ານອາດເຮັດວຽກຊ້າລົງຊົ່ວຄາວ."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍເອົາລາຍງານບັນຫາ ເພື່ອຊ່ວຍແກ້ໄຂບັນຫາໃຫ້ອຸປະກອນນີ້. ອາດຈະມີການແບ່ງປັນແອັບ ແລະ ຂໍ້ມູນນຳ."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ນີ້ອາດຈະເຮັດໃຫ້ອຸປະກອນຂອງທ່ານຊ້າລົງຊົ່ວຄາວ"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ຍອມຮັບ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ປະຕິເສດ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ກຳລັງເອົາລາຍງານຂໍ້ຜິດພາດ…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ແຕະເພື່ອຍົກເລີກ"</string>
<string name="select_input_method" msgid="8547250819326693584">"​ປ່ຽນ​ແປ້ນ​ພິມ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"​ເລືອກ​ແປ້ນ​ພິມ"</string>
<string name="show_ime" msgid="2506087537466597099">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"​ຖາມ​ຫາ PIN ກ່ອນ​ຍົກ​ເລີກ​ການປັກ​ໝຸດ"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"​ຖາມ​ຫາ​ຮູບ​ແບບ​ປົດ​ລັອກ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"​ຖາມ​ຫາ​ລະ​ຫັດ​ຜ່ານ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ບໍ່ສາມາດປັບຂະໜາດແອັບໄດ້, ໃຫ້ເລື່ອນມັນໂດຍໃຊ້ນິ້ວມືສອງນິ້ວ."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ຕິດ​ຕັ້ງ​ໃສ່​ແລ້ວ"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"ອັບ​ເດດ​ໂດຍ​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ແລ້ວ"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"ອື່ນໆ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ສຳລັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ບໍ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ສຳລັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> (ຜູ້ໃຊ້ສຳລັບບັນຊີນີ້ມີຢູ່ແລ້ວ) ບໍ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ການຕັ້ງຄ່າພາສາ"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ເພີ່ມພາສາ"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"ແນະນຳ"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"ຖືກປິດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ %1$s. ກະລຸນາຕິດຕໍ່ຫາພວກເຂົາເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"ທ່ານມີຂໍ້ຄວາມໃໝ່"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"ເປີດແອັບ SMS ເພື່ອເບິ່ງ"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ບາງຟັງຊັນອາດບໍ່ສາມາດໃຊ້ໄດ້"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ແຕະເພື່ອສືບຕໍ່"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ໂປຣໄຟລ໌ຜູ້ໃຊ້ຖືກລັອກໄວ້ແລ້ວ"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ບາງຄວາມສາມາດນຳໃຊ້ອາດຈະຖືກຈຳກັດ"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"ແຕະເພື່ອປົດລັອກ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ລັອກຂໍ້ມູນຜູ້ໃຊ້ແລ້ວ"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຖືກລັອກ"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"ແຕະເພື່ອປົດລັອກໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ແລ້ວ"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ແຕະເພື່ອເບິ່ງໄຟລ໌"</string>
<string name="pin_target" msgid="3052256031352291362">"ປັກໝຸດ"</string>
<string name="unpin_target" msgid="3556545602439143442">"ຖອນປັກໝຸດ"</string>
<string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e8759d790db6..8604e621aa8a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Skambintojo ID pagal numatytuosius nustatymus yra neapribotas. Kitas skambutis: neapribotas"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Paslauga neteikiama."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Negalima pakeisti skambinančiojo ID nustatymo."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Apribota prieiga pakeista"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Duomenų paslauga užblokuota."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Pagalbos paslauga užblokuota."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Balso paslauga užblokuota."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Nustatyti ir paleisti programą iš naujo"</string>
<string name="aerr_report" msgid="5371800241488400617">"Siųsti atsiliepimą"</string>
<string name="aerr_close" msgid="2991640326563991340">"Uždaryti"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Paslėpti"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignoruoti, kol įrenginys bus paleistas iš naujo"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Laukti"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Uždaryti programą"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Neleisti USB derinimo."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Bendrinti pranešimą apie riktą su administratoriumi?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis šiame įrenginyje. Programos bei duomenys gali būti bendrinami ir įrenginys gali laikinai lėčiau veikti."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis šiame įrenginyje. Programos ir duomenys gali būti bendrinami."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dėl to įrenginys gali laikinai lėčiau veikti"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SUTIKTI"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ATMESTI"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Pateikiamas pranešimas apie riktą…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Palieskite, kad atšauktumėte"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatūros keitimas"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pasirinkti klaviatūras"</string>
<string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Prašyti atrakinimo piešinio prieš atsegant"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Prašyti slaptažodžio prieš atsegant"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Programos dydis nekeičiamas, slinkite dviem pirštais."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Programa gali neveikti naudojant skaidytą ekraną."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Programoje nepalaikomas skaidytas ekranas."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Įdiegė administratorius"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atnaujino administratorius"</string>
@@ -1575,12 +1575,11 @@
<item quantity="many">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
<item quantity="other">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Įvairūs"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Galite nustatyti šių pranešimų svarbą."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Galite nustatyti šių pranešimų svarbą."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Kalbos nuostata"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Kalbos pridėjimas"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Regiono nuostata"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Išjungė %1$s administratorius. Kad sužinotumėte daugiau, susisiekite su juo."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Turite naujų pranešimų"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Atidaryti SMS programą, norint peržiūrėti"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Kelios funkc. gali būti nepas."</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Jei norite tęsti, palieskite"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Naudotojo profilis užrakintas"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Kai kurios funkcijos gali būti ribojamos"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Palieskite, kad atrakintumėte"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Naudotojo duomenys užrakinti"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Darbo profilis užrakintas"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Paliesk., kad atr. darbo prof."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Prisijungta prie „<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>“"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Palieskite, kad peržiūrėtumėte failus"</string>
<string name="pin_target" msgid="3052256031352291362">"Prisegti"</string>
<string name="unpin_target" msgid="3556545602439143442">"Atsegti"</string>
<string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"–<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 81028f59e35a..a572093bc890 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -89,7 +89,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Zvanītāja ID noklusējumi ir iestatīti uz Nav ierobežots. Nākamais zvans: nav ierobežots"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Pakalpojums netiek nodrošināts."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Zvanītāja ID iestatījumu nevar mainīt."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ierobežotā piekļuve ir mainīta"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datu pakalpojums ir bloķēts."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Ārkārtas pakalpojums ir bloķēts."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Balss pakalpojums ir bloķēts."</string>
@@ -923,7 +922,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Atiestatīt un restartēt lietotni"</string>
<string name="aerr_report" msgid="5371800241488400617">"Sūtīt atsauksmes"</string>
<string name="aerr_close" msgid="2991640326563991340">"Aizvērt"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Nerādīt"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Nerādīt, līdz ierīce tiks restartēta"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Gaidīt"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Aizvērt lietotni"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,12 +1060,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Citas opcijas"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Iespējot USB atkļūdošanu."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vai kopīgot kļūdas pārskatu ar administratoru?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu šajā ierīcē. Var tikt kopīgotas lietotnes un dati, un jūsu ierīces darbība var īslaicīgi palēnināties."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu šajā ierīcē. Var tikt kopīgotas lietotnes un dati."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Jūsu ierīces darbība var īslaicīgi palēnināties."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"APSTIPRINĀT"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"NORAIDĪT"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Notiek kļūdas pārskata izveide…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Pieskarieties, lai atceltu"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatūras maiņa"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izvēlēties tastatūru"</string>
<string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
@@ -1477,7 +1477,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prasīt PIN kodu pirms atspraušanas"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pirms atspraušanas pieprasīt grafisko atslēgu"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pirms atspraušanas pieprasīt paroli"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Lietotnes lielumu nevar mainīt. Ritiniet to ar diviem pirkstiem."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Iespējams, lietotnē nedarbosies ekrāna sadalīšana."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalēja jūsu administrators"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atjaunināja administrators"</string>
@@ -1556,12 +1556,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīts</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Dažādi"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Tas ir svarīgi iesaistīto personu dēļ."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Valodas preference"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Pievienot valodu"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Reģiona preference"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Ieteiktās"</string>
@@ -1574,12 +1573,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Atspējoja %1$s administrators. Lai uzzinātu vairāk, sazinieties ar administratoru."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Jums ir jaunas īsziņas."</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Lai skatītu, atveriet īsziņu lietotni."</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Dažas funkcijas var nebūt pieejamas"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Pieskarieties, lai turpinātu."</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Lietotāja profils ir bloķēts."</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Funkcijas var būt ierobežotas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Pieskarieties, lai atbloķētu."</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Lietotāja dati ir bloķēti."</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Darba profils ir bloķēts."</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Pieskarieties, lai atbloķētu."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Izveidots savienojums ar: <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Pieskarieties, lai skatītu failus."</string>
<string name="pin_target" msgid="3052256031352291362">"Piespraust"</string>
<string name="unpin_target" msgid="3556545602439143442">"Atspraust"</string>
<string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index d67d78d15aa6..a5a4ba7f4455 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Стандардно, повикувачот со овој ИД не е ограничен. Следен повик: не е ограничен"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Услугата не е предвидена."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Не може да го промените поставувањето за ИД на повикувач."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ограничениот пристап е изменет"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Услугата за податоци е блокирана."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Услугата за итни повици е блокирана."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Услугата за гласовно бирање е блокирана."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Ресетирај ја и рестартирај ја апликацијата"</string>
<string name="aerr_report" msgid="5371800241488400617">"Испрати повратни информации"</string>
<string name="aerr_close" msgid="2991640326563991340">"Затвори"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Исклучи звук"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Исклучи го звукот додека уредот не се рестартира"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Почекај"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Затвори ја апликацијата"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Допри за повеќе опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Да се сподели извештајот за грешки со администраторот?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Вашиот ИТ-администратор побара извештај за грешки за да помогне со отстранување на грешките"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели извештајот за грешки?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Се споделува извештај за грешки…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Администраторот за информатичка технологија побара извештај за грешки за да ви помогне во отстранувањето на грешките од уредот. Апликациите и податоците можеби ќе се споделат, а уредот можеби ќе биде привремено побавен при работата."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Вашиот администратор за информатичка технологија побара извештај за грешки за да помогне со отстранување на грешките на овој уред. Апликациите и податоците може да бидат споделени."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ова може привремено да го забави уредот"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИФАТИ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Се зема извештајот за грешки…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Допрете за да откажете"</string>
<string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Избери тастатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
@@ -1469,7 +1469,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за ПИН пред откачување"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Прашај за шема за отклучување пред откачување"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Прашај за лозинка пред откачување"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Не може да се промени големината на апликацијата, лизгајте ја со два прста."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Апликацијата можеби нема да работи во поделен екран."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Апликацијата не поддржува поделен екран."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Инсталирано од администраторот"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирано од администраторот"</string>
@@ -1539,12 +1539,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> е избрана</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ја поставивте важноста на известувањава."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ја поставивте важноста на известувањава."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ова е важно заради луѓето кои се вклучени."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Дозволувате ли <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Дозволувате ли <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g> (веќе постои корисник со оваа сметка)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Претпочитувања за јазик"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Додај јазик"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Претпочитувања за регион"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
@@ -1557,12 +1556,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Оневозможено од администраторот на %1$s. Контактирајте со него за да дознаете повеќе."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Имате нови пораки"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Отворете ја апликацијата за СМС за приказ"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Некои функции се недостапни"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Допрете за да продолжите"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Корисничкиот профил е заклучен"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Некои функции се ограничени"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Допрете за да отклучите"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Кориснички податоци, заклучени"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Работниот профил е заклучен"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Допрете за да го отклучите"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Поврзан на <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Допрете за да ги погледнете датотеките"</string>
<string name="pin_target" msgid="3052256031352291362">"Прикачете"</string>
<string name="unpin_target" msgid="3556545602439143442">"Откачете"</string>
<string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 43c232f96c1e..8a979300318f 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"നിയന്ത്രിക്കേണ്ടതല്ലാത്ത സ്ഥിര കോളർ ഐഡികൾ. അടുത്ത കോൾ: നിയന്ത്രിച്ചിട്ടില്ല"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"സേവനം വ്യവസ്ഥ ചെയ്‌തിട്ടില്ല."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"നിങ്ങൾക്ക് കോളർ ഐഡി ക്രമീകരണം മാറ്റാനാവില്ല."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"നിയന്ത്രിത ആക്സസ്സ് മാറ്റി"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ഡാറ്റ സേവനം തടഞ്ഞു."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"അടിയന്തര സേവനം തടഞ്ഞു."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"വോയ്‌സ് സേവനം തടഞ്ഞു."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ആപ്പ് പുനഃക്രമീകരിച്ച് പുനഃരാരംഭിക്കുക"</string>
<string name="aerr_report" msgid="5371800241488400617">"ഫീഡ്‌ബാക്ക് അയയ്‌ക്കുക"</string>
<string name="aerr_close" msgid="2991640326563991340">"അടയ്‌ക്കുക"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"മ്യൂട്ടുചെയ്യുക"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ഉപകരണം പുനഃരാരംഭിക്കുന്നത് വരെ മ്യൂട്ടുചെയ്യുക"</string>
<string name="aerr_wait" msgid="3199956902437040261">"കാത്തിരിക്കുക"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ആപ്പ് അടയ്‌ക്കുക"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"കൂടുതൽ ഓപ്‌ഷനുകൾക്ക് സ്‌പർശിക്കൂ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്‌റ്റുചെയ്‌തു"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ സ്‌പർശിക്കൂ."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"അഡ്‌മിനുമായി ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്‌മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നു…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ഈ ഉപകരണവുമായി ബന്ധപ്പെട്ട പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്‌മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു. ആപ്‌സും ഡാറ്റയും പങ്കിടപ്പെട്ടേക്കും, നിങ്ങളുടെ ഉപകരണത്തെ ഇത് താൽക്കാലികമായി മന്ദഗതിയിലാക്കിയേക്കാം."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ഈ ഉപകരണത്തിലെ പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്‌മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു. ആപ്‌സും ഡാറ്റയും പങ്കിടപ്പെട്ടേക്കും."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"നിങ്ങളുടെ ഉപകരണത്തെ ഇത് താൽക്കാലികമായി മന്ദഗതിയിലാക്കിയേക്കാം"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"അംഗീകരിക്കുക"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"നിരസിക്കുക"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നു…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"റദ്ദാക്കുന്നതിന് സ്പർശിക്കുക"</string>
<string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"കീബോർഡുകൾ തിരഞ്ഞെടുക്കുക"</string>
<string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
@@ -1220,7 +1220,7 @@
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"ഡോട്ട്."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"ഹോമിലേക്ക് നാവിഗേറ്റുചെയ്യുക"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"മുകളിലേക്ക് നാവിഗേറ്റുചെയ്യുക"</string>
- <string name="action_menu_overflow_description" msgid="2295659037509008453">"കൂടുതല്‍ ഓപ്‌ഷനുകള്‍"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"കൂടുതൽ‍ ഓപ്‌ഷനുകള്‍"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="4891916833657929263">"ആന്തരിക സ്റ്റോറേജ്"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ചെയ്യുംമുമ്പ് പിൻ ചോദിക്കൂ"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടുക"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പാസ്‌വേഡ് ആവശ്യപ്പെടുക"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ആപ്പിന്റെ വലുപ്പം ക്രമീകരിക്കാൻ കഴിയില്ല, രണ്ട് വിരലുകൾ ഉപയോഗിച്ച് അത് സ്ക്രോൾ ചെയ്യുക."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"സ്പ്ലിറ്റ്-സ്ക്രീനിനൊപ്പം ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർ ഇൻസ്റ്റാളുചെയ്‌തു"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർ അപ്‌ഡേറ്റുചെയ്‌തു"</string>
@@ -1529,7 +1529,7 @@
<string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB പെരിഫറൽ പോർട്ട്"</string>
<string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
<string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB പെരിഫറൽ പോർട്ട്"</string>
- <string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"കൂടുതല്‍ ഓപ്ഷനുകള്‍"</string>
+ <string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"കൂടുതൽ‍ ഓപ്ഷനുകള്‍"</string>
<string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"ഓവർഫ്ലോ അടയ്‌ക്കുക"</string>
<string name="maximize_button_text" msgid="7543285286182446254">"വലുതാക്കുക"</string>
<string name="close_button_text" msgid="3937902162644062866">"അടയ്‌ക്കുക"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"പലവക"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള്‍ ഇത് പ്രധാനപ്പെട്ടതാണ്‌."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയൊരു ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് (ഈ അക്കൗണ്ട് ഉപയോഗിച്ചുള്ള ഒരു ഉപയോക്താവ് ഇതിനകം തന്നെ നിലവിലുണ്ട്) ഉപയോഗിച്ച് പുതിയൊരു ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ഭാഷാ മുൻഗണന"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ഒരു ഭാഷ ചേർക്കുക"</string>
<string name="country_selection_title" msgid="2954859441620215513">"മേഖലാ മുൻഗണന"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s അഡ്മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു. കൂടുതലറിയാൻ അഡ്മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"നിങ്ങൾക്ക് പുതിയ സന്ദേശങ്ങൾ ഉണ്ട്"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"കാണുന്നതിന് SMS ആപ്പ് തുറക്കുക"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ചില ഫംഗ്ഷനുകൾ ലഭ്യമായേക്കില്ല"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"തുടരുന്നതിന് സ്പർശിക്കുക"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ഉപയോക്തൃ പ്രൊഫൈൽ ലോക്കുചെയ്തു"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ചില പ്രവർത്തനക്ഷമതകൾ പരിമിതപ്പെടാം"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"അൺലോക്കുചെയ്യാൻ ടാപ്പുചെയ്യുക"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ഉപയോക്തൃ ഡാറ്റ ലോക്കുചെയ്തു"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"ഔദ്യോഗിക പ്രൊഫൈൽ ലോക്കുചെയ്തു"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"ഔദ്യോഗിക പ്രൊഫൈൽ അൺലോക്കുചെയ്യാൻ ടാപ്പുചെയ്യുക"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ഫയലുകൾ കാണുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="pin_target" msgid="3052256031352291362">"പിൻ ചെയ്യുക"</string>
<string name="unpin_target" msgid="3556545602439143442">"അൺപിൻ ചെയ്യുക"</string>
<string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index dacb292ee37c..99500039d13b 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Дуудлага хийгчийн ID хязгаарлагдсан. Дараагийн дуудлага: Хязгаарлагдсан"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Үйлчилгээ провишн хийгдээгүй ."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Та дуудлага хийгчийн ID тохиргоог солиж чадахгүй."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Хязгаарлагдсан хандалт өөрчлөгдөв"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Дата үйлчилгээ хаагдсан."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Яаралтай үйлчилгээ хаагдсан."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Дуут үйлчилгээ хориглогдсон."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Апп-ыг шинэчилж, дахин эхлүүлэх"</string>
<string name="aerr_report" msgid="5371800241488400617">"Санал хүсэлт илгээх"</string>
<string name="aerr_close" msgid="2991640326563991340">"Хаах"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Дуу хаах"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Төхөөрөмжийг дахин эхлүүлэх хүртэл дууг нь хаах"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Хүлээх"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Апп-ыг хаах"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Нэмэлт сонголтыг харахын тулд дарна."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебагийг идэвхгүй болгох бол хүрнэ үү."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Алдааны тайланг админтай хуваалцах уу?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Асуудлыг шийдвэрлэхийн таны МТ админтулд алдааны тайланг хүслээ"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Алдааны тайланг хуваалцах уу?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Алдааны тайланг хуваалцаж байна..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Энэ төхөөрөмжийн асуудлыг шийдвэрлэхийнт тулд таны IT админ алдааны тайланг хүслээ. Апп болон өгөгдлийг хуваалцаж, таны төхөөрөмж бага зэрэг удаан ажиллаж болзошгүй."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Энэ төхөөрөмжийн асуудлыг шийдвэрлэхийн тулд таны IT админ алдааны тайланг хүслээ. Апп болон өгөгдлийг хуваалцсан байж болзошгүй."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Энэ нь таны төхөөрөмжийг түр хугацаанд удаашруулж болзошгүй"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ЗӨВШӨӨРӨХ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ТАТГАЛЗАХ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Алдааны тайланг авч байна..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Цуцлахын тулд хүрэх"</string>
<string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
<string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Апп-ын хэмжээг өөрчлөх боломжгүй. Үүнийг 2 хуруугаар гүйлгэнэ үү."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Апп хуваагдсан дэлгэцэд ажиллахгүй."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Таны админ суулгасан байна"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Танай админ шинэчилсэн"</string>
@@ -1535,12 +1535,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> сонгосон</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Бусад"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g>-г <xliff:g id="ACCOUNT">%2$s</xliff:g>-р шинэ Хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g>-г <xliff:g id="ACCOUNT">%2$s</xliff:g>-р шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Хэлний тохиргоо"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Хэл нэмэх"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Бүс нутгийн тохиргоо"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Санал болгосон"</string>
@@ -1553,12 +1552,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s админ идэвхгүй болгосон. Дэлгэрэнгүй мэдэхийн тулд тэдэнтэй холбоо барина уу."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Танд шинэ зурвасууд байна"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Үзэхийн тулд SMS аппыг нээх"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Зарим функц байхгүй"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Үргэлжлүүлэхийн тулд дарах"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Хэрэглэгчийн профайл түгжээтэй"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Зарим үйлдэл хязгаарлалттай байж болно"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Түгжээг тайлахын тулд дар"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Хэрэглэгчийн мэдээлэл түгжигдсэн"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Ажлын профайлыг түгжсэн"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Ажлын профайлын түгжээг тайлахын тулд дарна уу"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-д холбогдсон"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлыг үзэхийн тулд дарна уу"</string>
<string name="pin_target" msgid="3052256031352291362">"PIN"</string>
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 3041601444c3..968331ab58d4 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कॉलर ID डीफॉल्‍ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवेची तरतूद केलेली नाही."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"आपण कॉलर ID सेटिंग बदलू शकत नाही."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"प्रतिबंधित प्रवेश बदलला"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"डेटा सेवा अवरोधित केली आहे."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"आणीबाणी सेवा अवरोधित केली आहे."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"व्हॉइस सेवा अवरोधित केली आहे."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"अॅप रीसेट आणि रीस्टार्ट करा"</string>
<string name="aerr_report" msgid="5371800241488400617">"अभिप्राय पाठवा"</string>
<string name="aerr_close" msgid="2991640326563991340">"बंद करा"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"नि:शब्द करा"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"डिव्हाइस रीस्टार्ट होईपर्यंत नि:शब्द करा"</string>
<string name="aerr_wait" msgid="3199956902437040261">"प्रतीक्षा करा"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"अॅप बंद करा"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"अधिक पर्यायांसाठी स्पर्श करा."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्‍ट केले"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करणे अक्षम करण्यासाठी स्पर्श करा."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"प्रशासकासह दोष अहवाल सामायिक करायचा?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"आपल्या IT प्रशासकाने समस्या निवारण करण्‍यात मदत करण्यासाठी दोष अहवालाची विनंती केली"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग अहवाल सामायिक करायचा?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"दोष अहवाल सामायिक करीत आहे..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"आपल्या IT प्रशासकाने या डिव्हाइसची समस्या निवारण करण्यात मदत करण्यासाठी एका दोष अहवालाची विनंती केली. अॅप्स आणि डेटा सामायिक केले जाऊ शकतात आणि आपले डिव्हाइस तात्पुरते धीमे होऊ शकते."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"आपल्या IT प्रशासकाने या डिव्हाइसच्या समस्येचे निवारण करण्यात मदत करण्यासाठी दोष अहवालाची विनंती केली. अॅप्स आणि डेटा सामायिक केला जाऊ शकतो."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"हे तात्पुरता आपले डिव्हाइस धिमे करू शकते."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करा"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"नकार द्या"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"दोष अहवाल घेत आहे..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"रद्द करण्यासाठी स्पर्श करा"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड निवडा"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्‍यापूर्वी पिन साठी विचारा"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"अनपिन करण्‍यापूर्वी अनलॉक नमुन्यासाठी विचारा"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"अनपिन करण्‍यापूर्वी संकेतशब्दासाठी विचारा"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"अॅपचा आकार बदलण्यायोग्य नाही, दोन बोटांनी तो स्क्रोल करा."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"अॅप कदाचित विभाजित-स्क्रीनसह कार्य करू शकत नाही."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"अॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"आपल्या प्रशासकाद्वारे स्थापित केले आहे"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"आपल्या प्रशासकाद्वारे अद्यतनित केले"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडला</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"संकीर्ण"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"आपण या सूचनांचे महत्त्व सेट केले."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"आपण या सूचनांचे महत्त्व सेट केले."</string>
<string name="importance_from_person" msgid="9160133597262938296">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची (हे खाते असलेला वापरकर्ता आधीपासून विद्यमान आहे) <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"भाषा प्राधान्य"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"एक भाषा जोडा"</string>
<string name="country_selection_title" msgid="2954859441620215513">"प्रदेश प्राधान्य"</string>
<string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"सूचित केलेले"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s प्रशासकाद्वारे अक्षम केले. अधिक जाणून घेण्‍यासाठी त्यांच्याशी संपर्क साधा."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"आपल्याकडे नवीन संदेश आहेत"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"पाहण्‍यासाठी SMS अॅप उघडा"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"काही कार्ये कदाचित उपलब्ध नसू शकतात"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"सुरू ठेवण्यासाठी स्पर्श करा"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"वापरकर्ता प्रोफाईल लॉक केले"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"काही कार्यक्षमता मर्यादित असू शकतात"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"अनलॉक करण्यासाठी टॅप करा"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"वापरकर्ता डेटा लॉक केला"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"कार्य प्रोफाईल लॉक केले"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"कार्य प्रोफाईल अनलॉक करण्यासाठी टॅप करा"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> शी कनेक्ट केलेले"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फायली पाहण्यासाठी टॅप करा"</string>
<string name="pin_target" msgid="3052256031352291362">"पिन"</string>
<string name="unpin_target" msgid="3556545602439143442">"अनपिन करा"</string>
<string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 0f5156a9c20e..06401bf26b8f 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID pemanggil secara lalainya ditetapkan kepada tidak dihadkan. Panggilan seterusnya: Tidak terhad"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Perkhidmatan yang tidak diuntukkan."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Anda tidak boleh mengubah tetapan ID pemanggil."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Akses terhad diubah"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Perkhidmatan data disekat."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Perkhidmatan kecemasan disekat."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Perkhidmatan suara disekat."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Tetapkan semula dan mulakan semula apl"</string>
<string name="aerr_report" msgid="5371800241488400617">"Hantar maklum balas"</string>
<string name="aerr_close" msgid="2991640326563991340">"Tutup"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Redam"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Redam sehingga peranti dimulakan semula"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Tunggu"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Tutup apl"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk mendapatkan lagi pilihan."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk melumpuhkan penyahpepijatan USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Kongsi laporan pepijat dengan pentadbir?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah peranti ini. Apl dan data mungkin dikongsi dan peranti anda mungkin menjadi perlahan untuk sementara waktu."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah peranti ini. Apl dan data mungkin dikongsi."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Proses ini mungkin memperlahankan peranti anda untuk sementara waktu"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TERIMA"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Mengambil laporan pepijat…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Sentuh untuk membatalkan"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tukar papan kekunci"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pilih papan kekunci"</string>
<string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Minta corak buka kunci sebelum menyahsemat"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Minta kata laluan sebelum menyahsemat"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Apl tidak boleh ditukar saiznya, tatal apl itu menggunakan dua jari."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Apl mungkin tidak berfungsi dengan skrin terpisah."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Apl tidak menyokong skrin pisah."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh pentadbir anda"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Pelbagai"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Anda menetapkan kepentingan pemberitahuan ini."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Anda menetapkan kepentingan pemberitahuan ini."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Mesej ini penting disebabkan orang yang terlibat."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Pilihan bahasa"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Tambahkan bahasa"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Pilihan wilayah"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Dicadangkan"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Dilumpuhkan oleh pentadbir %1$s. Hubungi mereka untuk mengetahui lebih lanjut."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Anda mempunyai mesej baharu"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Buka apl SMS untuk melihat"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Sesetengah fungsi mgkn tidak tersedia"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Ketik untuk meneruskan"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil pengguna dikunci"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Sesetengah fungsi mungkin terhad"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Ketik untuk membuka kunci"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Data pengguna dikunci"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil kerja dikunci"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Ketik utk membuka profil kerja"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Disambungkan ke <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Ketik untuk melihat fail"</string>
<string name="pin_target" msgid="3052256031352291362">"Semat"</string>
<string name="unpin_target" msgid="3556545602439143442">"Nyahsemat"</string>
<string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index ca28662b453e..5cf2bd38c901 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ပုံသေအားဖြင့် ခေါ်ဆိုသူအိုင်ဒီ(Caller ID)အား ကန့်သတ်မထားပါ။ နောက်ထပ်အဝင်ခေါ်ဆိုမှု-ကန့်သတ်မထားပါ။"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"ဝန်ဆောင်မှုအား ကန့်သတ်မထားပါ"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"သင်သည် ခေါ်ဆိုသူ ID ဆက်တင်ကို မပြောင်းလဲနိုင်ပါ။"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ဝင်ရောက်ကြည့်ရှုခြင်းကန့်သတ်ချက်အားပြောင်းထားသည်"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ဒေတာဝန်ဆောင်မှုပိတ်ထားသည်။"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"အရေးပေါ်ဝန်ဆောင်မှုပိတ်ထားသည်။"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"အသံဝန်ဆောင်မှုပိတ်ထားသည်။"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"အက်ပ်ကို ပြန်လည်ပြင်ဆင်သတ်မှတ်ပြီး ပြန်လည်စတင်ပါ"</string>
<string name="aerr_report" msgid="5371800241488400617">"တုံ့ပြန်ချက်ပို့ပါ"</string>
<string name="aerr_close" msgid="2991640326563991340">"ပိတ်ပါ"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"အသံတိတ်ပါ"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"စက်ပစ္စည်း ပြန်လည်စတင်သည့်တိုင် အသံတိတ်ပါ"</string>
<string name="aerr_wait" msgid="3199956902437040261">"စောင့်ပါ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"အက်ပ်ကိုပိတ်ပါ"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ထပ်မံရွေးချယ်စရာများအတွက် ထိပါ"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ဒီဘာဂင် ပိတ်ရန် ထိပါ။"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို စီမံအုပ်ချုပ်သူထံ ပို့မလား။"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"သင်၏ IT စီမံအုပ်ချုပ်သူက ပြဿနာကို ဖြေရှင်းနိုင်ရန် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုပါသည်"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို မျှဝေမလား။"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ချွတ်ယွင်းမှုအစီရင်ခံစာ မျှဝေနေသည်…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ဤစက်ပစ္စည်းကို ပြဿနာအဖြေရှာရာတွင် ကူညီရန် သင့်အိုင်တီစီမံခန့်ခွဲသူသည် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုထားသည်။ အက်ပ်များနှင့် ဒေတာကိုမျှဝေထားနိုင်ပြီး သင့်စက်ပစ္စည်းကို ခေတ္တနှေးကွေးသွားစေနိုင်သည်။"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ဤစက်ပစ္စည်းကို ပြဿနာအဖြေရှာရာတွင် ကူညီရန် သင့်အိုင်တီစီမံခန့်ခွဲသူသည် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုထားသည်။ အက်ပ်များနှင့် ဒေတာကိုမျှဝေထားနိုင်ပါသည်။"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"၎င်းသည်သင့်စက်ပစ္စည်းကို ခေတ္တနှေးကွေးသွားစေနိုင်သည်"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"လက်ခံပါ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ငြင်းပယ်ပါ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ချွတ်ယွင်းချက် စာရင်းကို ယူနေပါသည်..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ဖျက်သိမ်းရန် တို့ပါ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ကီးဘုတ်များကို ရွေးရန်"</string>
<string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ပင်မဖြုတ်မီမှာ သော့ဖွင့် ရေးဆွဲမှုပုံစံကို မေးကြည့်ရန်"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ပင်မဖြုတ်မီမှာ စကားဝှက်ကို မေးကြည့်ရန်"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"အက်ပ်ကို အရွယ်အစားချိန်၍မရပါ၊ လက်ချောင်းနှစ်ချောင်းဖြင့် အပေါ်အောက်ဆွဲပါ။"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"မျက်နှာပြင် ခွဲခြမ်းပြသမှုဖြင့် အက်ပ်သည် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"သင့် အက်ဒမင်မှ သွင်းယူထား၏"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"သင့်စီမံခန့်ခွဲသူမှ အဆင့်မြှင့်ထားပါသည်။"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"အထွေထွေ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ဤအသိပေးချက်များ၏ အရေးပါမှုကိုသင်သတ်မှတ်ပြီးပါပြီ။"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ဤသတိပေးချက်များ၏ အရေးပါမှုကိုသတ်မှတ်ပြီးပါပြီ။"</string>
<string name="importance_from_person" msgid="9160133597262938296">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ကို <xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ဖန်တီးခွင့်ပြုမလား။"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> ကို <xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ် ဖန်တီးခွင့်ပြုမလား (ဤအကောင့်ဖြင့် အသုံးပြုသူ ရှိနှင့်ပြီးဖြစ်သည်)။"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ဘာသာစကားရွေးချယ်မှု"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ဒေသရွေးချယ်မှု"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"အကြံပြုထားသော"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်။ ပိုမိုလေ့လာရန် ၎င်းတို့ကိုဆက်သွယ်ပါ။"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"သင့်ထံတွင် စာအသစ်များရောက်နေသည်"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"ကြည့်ရှုရန် SMS အက်ပ်ကိုဖွင့်ပါ"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"အချို့လုပ်ဆောင်ချက်များ ရနိုင်သေးမည်မဟုတ်ပါ"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ရှေ့ဆက်ရန်တို့ပါ"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"အသုံးပြုသူပရိုဖိုင် သော့ခတ်ထားသည်"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"အချို့လုပ်ဆောင်ချက်များ ကန့်သတ်ချက်ရှိနိုင်သည်"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"သော့ဖွင့်ရန် တို့ပါ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"အသုံးပြုသူဒေတာအား သော့ခတ်ထားသည်"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"အလုပ်ပရိုဖိုင် သော့ခတ်ထားသည်"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"သင့်အလုပ်ပရိုဖိုင်ကို သော့ဖွင့်ရန် တို့ပါ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ချိတ်ဆက်ထားသည်"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ဖိုင်များကိုကြည့်ရန် တို့ပါ"</string>
<string name="pin_target" msgid="3052256031352291362">"တွဲပါ"</string>
<string name="unpin_target" msgid="3556545602439143442">"ဖြုတ်ပါ"</string>
<string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 737743a59c46..7ed5518b036d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Du kan ikke endre innstillingen for anrops-ID."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Tilgangsbegrensning endret"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datatjenesten er blokkert."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjenesten er blokkert."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Taletjenesten er blokkert."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Tilbakestill appen, og start den på nytt"</string>
<string name="aerr_report" msgid="5371800241488400617">"Send tilbakemelding"</string>
<string name="aerr_close" msgid="2991640326563991340">"Lukk"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorer"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorer frem til enheten starter på nytt"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Vent"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Lukk app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Trykk for å se flere alternativer."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Trykk for å slå av USB-feilsøking."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vil du dele feilrapporten med administratoren?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-administratoren din har bedt om en feilrapport for å hjelpe med feilsøkingen"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT-administratoren har bedt om en feilrapport for å hjelpe med feilsøkingen på denne enheten. Appene og dataene kan bli delt. Dette kan midlertidig gjøre enheten din tregere."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT-administratoren har bedt om en feilrapport for å hjelpe med feilsøkingen på denne enheten. Appene og dataene kan bli delt."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dette kan midlertidig gjøre enheten din tregere"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODTA"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVSLÅ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Kjører feilrapport …"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Trykk for å avbryte"</string>
<string name="select_input_method" msgid="8547250819326693584">"Endre tastatur"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Velg tastatur"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-kode for å løsne apper"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Krev bruk av opplåsningsmønster for å løsne apper"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Krev passord for å løsne apper"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Du kan ikke endre størrelse på appen – rull med to fingre."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen støtter ikke delt skjerm."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Installert av administratoren"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Oppdatert av administratoren"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> er valgt</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Du angir viktigheten for disse varslene."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Du angir viktigheten for disse varslene."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Dette er viktig på grunn av folkene som er involvert."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Det finnes allerede en bruker med denne kontoen.)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Språkinnstilling"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Legg til et språk"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Regionsinnstilling"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslått"</string>
@@ -1557,12 +1556,15 @@
<skip />
<string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nye meldinger"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Åpne SMS-appen for å se"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Noen funksjoner kan være utilgjengelige"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Trykk for å fortsette"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Brukerprofilen er låst"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Enkelte funksjoner kan være begrenset"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Trykk for å låse opp"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Brukerdataene er låst"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Jobbprofilen er låst"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Trykk for å låse opp jobbprofilen"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Koblet til <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Trykk for å se filer"</string>
<string name="pin_target" msgid="3052256031352291362">"Fest"</string>
<string name="unpin_target" msgid="3556545602439143442">"Løsne"</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 7ea4b48b345d..62915514bcdf 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कलर ID पूर्वनिर्धारितको लागि रोकावट छैन। अर्को कल: रोकावट छैन"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवाको व्यवस्था छैन।"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"तपाईँ कलर ID सेटिङ परिवर्तन गर्न सक्नुहुन्न।"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"प्रतिबन्धित पहुँच परिवर्तन भएको छ"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"डेटा सेवा रोकिएको छ।"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"आपतकालीन सेवा रोकिएको छ।"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"भ्वाइस सेवा ब्लक भएको छ।"</string>
@@ -923,7 +922,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"अनुप्रयोगलाई रिसेट गरी पुन: सुरु गर्नुहोस्"</string>
<string name="aerr_report" msgid="5371800241488400617">"प्रतिक्रिया पठाउनुहोस्"</string>
<string name="aerr_close" msgid="2991640326563991340">"बन्द गर्नुहोस्"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"म्यूट गर्नुहोस्"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"यन्त्र पुनः सुरु नभएसम्म म्यूट गर्नुहोस्"</string>
<string name="aerr_wait" msgid="3199956902437040261">"पर्खनुहोस्"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"अनुप्रयोग बन्द गर्नुहोस्"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1059,12 +1058,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"थप विकल्पहरूका लागि छुनुहोस्।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डिबग गर्ने असक्षम पार्न छुनुहोस्।"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"प्रशासकसँग बग रिपोर्ट साझेदारी गर्ने हो?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"तपाईंको IT व्यवस्थापकले समस्या निवारणमा मद्दत गर्न बग रिपोर्ट अनुरोध गर्नुभयो"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्टलाई साझेदारी गर्दै ..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"तपाईंको IT प्रशासकले यो यन्त्रको समस्या निवारण गर्नमा मद्दत गर्न बग रिपोर्टहरूका लागि अनुरोध गर्नु भएको छ । अनुप्रयोगहरू र डेटा साझेदारी गर्न सकिन्छ र तपाईंको यन्त्र अस्थायी रूपमा सुस्त हुन सक्छ।"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"तपाईंको IT प्रशासकले यो यन्त्रको समस्या निवारण गर्नमा मदत गर्न बग रिपोर्टहरूका लागि अनुरोध गर्नु भएको छ । Apps र डेटा साझेदारी गर्न सक्नुहुन्छ ।"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"यसले अस्थायी रूपमा तपाईंको यन्त्रलाई सुस्त बनाउन सक्छ"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार गर्नुहोस्"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार गर्नुहोस्"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"बग रिपोर्ट लिँदै..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"रद्द गर्न छुनुहोस्"</string>
<string name="select_input_method" msgid="8547250819326693584">"कुञ्जीपाटी परिवर्तन गर्नुहोस्"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड छान्नुहोस्"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>
@@ -1473,7 +1473,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"पिन निकाल्नुअघि खोल्ने रूपरेखा सोध्नुहोस्"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"अनुप्रयोगको आकार सानो-ठूलो बनाउन मिल्दैन, दुई औँलाले यसलाई स्क्रोल गर्नुहोस्।"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"अनुप्रयोगले विभाजित-स्क्रिनमा काम नगर्न सक्छ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"तपाईँको प्रशासकद्वारा स्थापना गरिएको"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"तपाईँको प्रशासकद्वारा अद्यावधिक गरिएको"</string>
@@ -1543,12 +1543,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयन गरियो</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> चयन गरियो</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहुन्छ।"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहोस् ।"</string>
<string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने (यस खाताको प्रयोगकर्ता पहिले नै अवस्थित छ) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"भाषाको प्राथमिकता"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"भाषा थप्नुहोस्"</string>
<string name="country_selection_title" msgid="2954859441620215513">"क्षेत्रको प्राथमिकता"</string>
<string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाव दिइयो"</string>
@@ -1561,12 +1560,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s प्रशासकद्वारा असक्षम गरिएको। थप जान्नका लागि तिनीहरूलाई सम्पर्क गर्नुहोस्।"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"तपाईंलाई नयाँ सन्देश आएको छ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"हेर्नका लागि SMS अनुप्रयोग खोल्नुहोस्"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"केही कार्यहरू उपलब्ध नहुन सक्छन्"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"जारी राख्नका लागि छुनुहोस्"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"प्रयोगकर्ता प्रोफाइल लक भयो"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"केही कार्य सीमित हुनसक्छ"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"अनलक गर्न ट्याप गर्नुहोस्"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"प्रयोगकर्ताको डेटा लक गरियो"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"कार्य प्रोफाइल लक भयो"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"कार्य प्रोफाइल अनलक गर्न ट्याप गर्नुहोस्"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> मा जडान गरिएको छ"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फाइलहरू हेर्न ट्याप गर्नुहोस्"</string>
<string name="pin_target" msgid="3052256031352291362">"पिन गर्नुहोस्"</string>
<string name="unpin_target" msgid="3556545602439143442">"अनपिन गर्नुहोस्"</string>
<string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 750b7166559a..404fdb49936c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Service niet voorzien."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"U kunt de instelling voor de beller-id niet wijzigen."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Beperkte toegang gewijzigd"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Gegevensservice is geblokkeerd."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Alarmservice is geblokkeerd."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Spraakservice is geblokkeerd."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"App resetten en opnieuw starten"</string>
<string name="aerr_report" msgid="5371800241488400617">"Feedback verzenden"</string>
<string name="aerr_close" msgid="2991640326563991340">"Sluiten"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Negeren"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Verbergen tot apparaat opnieuw wordt opgestart"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Wachten"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"App sluiten"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tik voor meer opties."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tik om USB-foutopsporing uit te schakelen."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Bugrapport delen met beheerder?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Je IT-beheerder heeft een bugrapport aangevraagd om het probleem op te lossen"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Je IT-beheerder heeft een bugrapport aangevraagd om problemen met dit apparaat op te lossen. Apps en gegevens kunnen worden gedeeld en je apparaat kan hierdoor tijdelijk worden vertraagd."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Je IT-beheerder heeft een bugrapport aangevraagd om problemen met dit apparaat op te lossen. Apps en gegevens kunnen worden gedeeld."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Dit kan je apparaat tijdelijk vertragen"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTEREN"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIGEREN"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Bugrapport genereren…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tik om te annuleren"</string>
<string name="select_input_method" msgid="8547250819326693584">"Toetsenbord wijzigen"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Toetsenborden kiezen"</string>
<string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vraag pin voor losmaken"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vraag patroon voor losmaken"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vraag wachtwoord voor losmaken"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Formaat van app kan niet worden aangepast, scrol met twee vingers."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"App werkt mogelijk niet met gesplitst scherm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"App biedt geen ondersteuning voor gesplitst scherm."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Geïnstalleerd door je beheerder"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Geüpdatet door je beheerder"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> geselecteerd</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diversen"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Je stelt het belang van deze meldingen in."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Je stelt het belang van deze meldingen in."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrijk vanwege de betrokken mensen."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Taalvoorkeur"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Een taal toevoegen"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Regiovoorkeur"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgesteld"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Uitgeschakeld door de beheerder van %1$s. Neem voor meer informatie contact op met de beheerder."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Je hebt nieuwe berichten"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Open je sms-app om ze te bekijken"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Sommige functies zijn mogelijk niet beschikbaar"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Tik om door te gaan"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Gebruikersprofiel vergrendeld"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Bepaalde functionaliteit kan zijn beperkt"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tik om te ontgrendelen"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Gebruikersgegevens vergrendeld"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Werkprofiel vergrendeld"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Ontgrendel werkprofiel met tik"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Verbonden met <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tik om bestanden te bekijken"</string>
<string name="pin_target" msgid="3052256031352291362">"Vastzetten"</string>
<string name="unpin_target" msgid="3556545602439143442">"Losmaken"</string>
<string name="app_info" msgid="6856026610594615344">"App-info"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 05f0ce23fd74..fa181da96891 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ਪ੍ਰਤਿਬੰਧਿਤ ਨਾ ਕਰਨ ਲਈ ਕਾਲਰ ID ਡਿਫੌਲਟਸ। ਅਗਲੀ ਕਾਲ: ਪ੍ਰਤਿਬੰਧਿਤ ਨਹੀਂ"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"ਸੇਵਾ ਪ੍ਰਬੰਧਿਤ ਨਹੀਂ ਹੈ।"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"ਤੁਸੀਂ ਕਾਲਰ ID ਸੈਟਿੰਗ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ਪ੍ਰਤਿਬੰਧਿਤ ਪਹੁੰਚ ਬਦਲੀ ਗਈ"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ਡਾਟਾ ਸੇਵਾ ਬਲੌਕ ਕੀਤੀ ਹੋਈ ਹੈ।"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"ਐਮਰਜੈਂਸੀ ਸੇਵਾ ਬਲੌਕ ਕੀਤੀ ਹੋਈ ਹੈ।"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"ਵੌਇਸ ਸੇਵਾ ਬਲੌਕ ਕੀਤੀ ਹੋਈ ਹੈ।"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ਐਪ ਨੂੰ ਰੀਸੈੱਟ ਅਤੇ ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
<string name="aerr_report" msgid="5371800241488400617">"ਪ੍ਰਤੀਕਰਮ ਭੇਜੋ"</string>
<string name="aerr_close" msgid="2991640326563991340">"ਬੰਦ ਕਰੋ"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"ਮਿਊਟ ਕਰੋ"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ ਤੱਕ ਮਿਊਟ ਕਰੋ"</string>
<string name="aerr_wait" msgid="3199956902437040261">"ਉਡੀਕ ਕਰੋ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ਐਪ ਬੰਦ ਕਰੋ"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ਡੀਬਗਿੰਗ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਲਈ ਛੋਹਵੋ।"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ਕੀ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ਸਮੱਸਿਆ ਦੇ ਨਿਪਟਾਰੇ ਵਿੱਚ ਮਦਦ ਲਈ ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇੱਕ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ਕੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱਚ ਮਦਦ ਲਈ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਐਪਾਂ ਅਤੇ ਡੈਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਅਤੇ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਆਰਜ਼ੀ ਤੌਰ \'ਤੇ ਹੌਲੀ ਹੋ ਸਕਦੀ ਹੈ।"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱੱਚ ਮਦਦ ਲਈ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਐਪਾਂ ਅਤੇ ਡੈਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"ਇਹ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਨੂੰ ਆਰਜ਼ੀ ਤੌਰ \'ਤੇ ਹੌਲੀ ਕਰ ਸਕਦਾ ਹੈ"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ਬੱਗ ਰਿਪਰੋਟ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ਰੱਦ ਕਰਨ ਲਈ ਸਪਰਸ਼ ਕਰੋ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ਕੀਬੋਰਡਸ ਚੁਣੋ"</string>
<string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ਅਨਪਿਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ PIN ਮੰਗੋ"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ਅਨਪਿਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪੈਟਰਨ ਅਨਲੌਕ ਕਰਨ ਲਈ ਪੁੱਛੋ"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ਅਨਪਿਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪਾਸਵਰਡ ਮੰਗੋ"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ਐਪ ਦਾ ਆਕਾਰ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ, ਇਸ ਨੂੰ ਦੋ ਉਂਗਲਾਂ ਨਾਲ ਸਕਰੋਲ ਕਰੋ।"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"ਤੁਹਾਡੇ ਪ੍ਰਬੰਧਕ ਵੱਲੋਂ ਇੰਸਟੌਲ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"ਵਿਵਿਧ"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
<string name="importance_from_person" msgid="9160133597262938296">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦੇਣੀ ਹੈ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦੇਣੀ ਹੈ (ਇਸ ਖਾਤੇ ਨਾਲ ਇੱਕ ਵਰਤੋਂਕਾਰ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ਭਾਸ਼ਾ ਤਰਜੀਹ"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ਇੱਕ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ਖੇਤਰ ਤਰਜੀਹ"</string>
<string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ। ਹੋਰ ਜਾਣਨ ਲਈ ਉਹਨਾਂ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"ਵੇਖਣ ਲਈ SMS ਐਪ ਖੋਲ੍ਹੋ"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ਹੋ ਸਕਦਾ ਹੈ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਉਪਲਬਧ ਨਾ ਹੋਣ"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਸਪਰਸ਼ ਕਰੋ"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"ਵਰਤੋਂਕਾਰ ਪ੍ਰੋਫਾਈਲ ਲੌਕ ਕੀਤੀ ਗਈ"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ਕੁਝ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਸੀਮਿਤ ਹੋ ਸਕਦੀ ਹੈ"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ਵਰਤੋਂਕਾਰ ਡੈਟਾ ਲੌਕ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਲੌਕ ਕੀਤੀ ਗਈ"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋਈ"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ਫ਼ਾਈਲਾਂ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="pin_target" msgid="3052256031352291362">"ਪਿੰਨ ਕਰੋ"</string>
<string name="unpin_target" msgid="3556545602439143442">"ਅਨਪਿੰਨ ਕਰੋ"</string>
<string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7e320a606be4..d1441bde5ec4 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Usługa nie jest świadczona."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Nie możesz zmienić ustawienia ID rozmówcy."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Zmieniono ograniczenie dostępu"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Usługa transmisji danych jest zablokowana."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usługa połączeń alarmowych jest zablokowana."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Usługa głosowa jest zablokowana."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Zresetuj aplikację i uruchom ją ponownie"</string>
<string name="aerr_report" msgid="5371800241488400617">"Prześlij opinię"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zamknij"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignoruj"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignoruj do momentu ponownego uruchomienia urządzenia"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Zaczekaj"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zamknij aplikację"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Kliknij, by zobaczyć 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="1016654627626476142">"Dotknij, aby wyłączyć debugowanie USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Udostępnić raport o błędzie administratorowi?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administrator poprosił o raport o błędzie, który pomoże w rozwiązaniu problemu"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administrator poprosił o raport o błędzie, by szybciej rozwiązać problemy na tym urządzeniu. Raport może zawierać informacje o aplikacjach i inne dane. Urządzenie może przez chwilę działać wolniej."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administrator poprosił o raport o błędzie, który pomoże w rozwiązaniu problemów na tym urządzeniu. Mogą zostać udostępnione aplikacje i dane."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Urządzenie może przez chwilę działać wolniej"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKCEPTUJ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODRZUĆ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Zgłaszam błąd…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Kliknij, by anulować"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmień klawiaturę"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Wybierz klawiatury"</string>
<string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Podaj PIN, aby odpiąć"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Aby odpiąć, poproś o wzór odblokowania"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Aby odpiąć, poproś o hasło"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Rozmiaru tej aplikacji nie można zmienić. Przewiń ją dwoma palcami."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacja może nie działać przy podzielonym ekranie."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacja nie obsługuje dzielonego ekranu."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Zainstalowany przez administratora"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Zaktualizowane przez administratora"</string>
@@ -1575,12 +1575,11 @@
<item quantity="other">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Wybrano <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Inne"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ustawiłeś ważność tych powiadomień."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ustawiłeś ważność tych powiadomień."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Zezwalasz aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Zezwalasz aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>)? Użytkownik z tym kontem już istnieje."</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Ustawienie języka"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dodaj język"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Ustawienie regionu"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerowane"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Wyłączone przez administratora organizacji %1$s. Skontaktuj się z nim, by dowiedzieć się więcej."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Masz nowe wiadomości"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Otwórz aplikację do SMS-ów, by wyświetlić wiadomość"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Niektóre funkcje mogą być niedostępne"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Kliknij, by kontynuować"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil użytkownika zablokowany"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Niektóre funkcje mogą być niedostępne"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Kliknij, by odblokować"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Dane użytkownika zablokowane"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil do pracy zablokowany"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Kliknij, by odblokować profil"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Połączono z: <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dotknij, by wyświetlić pliki"</string>
<string name="pin_target" msgid="3052256031352291362">"Przypnij"</string>
<string name="unpin_target" msgid="3556545602439143442">"Odepnij"</string>
<string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 1e3a887cf6c9..b444e0abb07d 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"O serviço não foi habilitado."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Não é possível alterar a configuração de identificação de chamadas."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito alterado"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"O serviço de voz está bloqueado."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Redefinir e reiniciar app"</string>
<string name="aerr_report" msgid="5371800241488400617">"Enviar feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Fechar"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Desativar até que dispositivo seja reiniciado"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Aguarde"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Fechar app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Toque para desativar a depuração do USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Compartilhar o relatório do bug com o administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Seu administrador de TI solicitou um relatório do bug para ajudar a resolver problemas"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados, o que pode deixar seu dispositivo temporariamente mais lento."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Isso pode deixar seu dispositivo temporariamente mais lento"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Gerando relatório do bug..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toque para cancelar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir padrão de desbloqueio antes de liberar"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir senha antes de liberar"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"O app não é redimensionável. Desloque-o com dois dedos."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"É possível que o app não funcione com o recurso de divisão de tela."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"O app não é compatível com a divisão de tela."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado pelo seu administrador"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Você definiu a importância dessas notificações."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Desativado pelo administrador de %1$s. Entre em contato com ele para saber mais."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Você tem mensagens novas"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Abra o app de SMS para ver"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Algumas funções podem não estar disponíveis."</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Toque para continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil do usuário bloqueado"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Algumas funcionalidades são limitadas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Toque para desbloquear"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Dados do usuário bloqueados"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabalho bloqueado"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque p/ desbl. perfil de trab."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toque para ver os arquivos"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixar guia"</string>
<string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 69520ee1623b..4a5b00540164 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Serviço não fornecido."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Não pode alterar a definição da identificação de chamadas."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito modificado"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"O serviço de voz está bloqueado."</string>
@@ -339,7 +338,7 @@
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite à aplicação modificar o registo de chamadas do tablet, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o registo de chamadas."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite à aplicação modificar o registo de chamadas da sua TV, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o registo de chamadas."</string>
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite à aplicação modificar o registo de chamadas do telemóvel, incluindo os dados sobre as chamadas recebidas e efetuadas. As aplicações maliciosas podem utilizar esta funcionalidade para apagar ou modificar o seu registo de chamadas."</string>
- <string name="permlab_bodySensors" msgid="4683341291818520277">"aceder a sensores corp. (como monit. do ritmo cardíaco)"</string>
+ <string name="permlab_bodySensors" msgid="4683341291818520277">"aceder a sensores corporais (como monitores do ritmo cardíaco)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Permite que a aplicação aceda a dados de sensores que monitorizam a sua condição física, como o ritmo cardíaco."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"ler eventos do calendário, para além de informações confidenciais"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite que a aplicação leia todos os eventos do calendário guardados no tablet, incluindo os de amigos ou colegas de trabalho. Pode permitir que a aplicação partilhe ou guarde dados do calendário, independentemente da confidencialidade ou sensibilidade."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Repor e reiniciar aplicação"</string>
<string name="aerr_report" msgid="5371800241488400617">"Enviar comentários"</string>
<string name="aerr_close" msgid="2991640326563991340">"Fechar"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Desativar som até o dispositivo reiniciar"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Aguardar"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Fechar aplicação"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desat. a depuração USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Pretende partilhar o relatório de erros com o administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"O seu administrador de TI solicitou um relatório de erros para ajudar na resolução de problemas"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"O seu administrador de TI solicitou um relatório de erro para ajudar na resolução de problemas deste dispositivo. As aplicações e os dados podem ser partilhados e o dispositivo pode tornar-se temporariamente mais lento."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"O seu administrador de TI solicitou um relatório de erro para ajudar na resolução de problemas deste dispositivo. As aplicações e os dados podem ser partilhados."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Esta ação pode tornar o dispositivo mais lento temporariamente"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"A criar relatório de erros…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toque para cancelar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de soltar"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir sequência de desbloqueio antes de soltar"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir palavra-passe antes de soltar"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"A aplicação não é redimensionável. Desloque-a com dois dedos."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"A aplicação pode não funcionar com o ecrã dividido."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"A aplicação não é compatível com o ecrã dividido."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado pelo administrador"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Definiu a importância destas notificações."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Definiu a importância destas notificações."</string>
<string name="importance_from_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Desativado pelo administrador de %1$s. Contacte-o para saber mais."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Tem mensagens novas"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Abra a aplicação de SMS para ver"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Algumas funções podem não estar disp."</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Toque para continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil de utilizador bloqueado"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Algumas funcionalid. limitadas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Toque para desbloquear"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Dados do utilizador bloqueados"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabalho bloqueado"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque p/ desb. perfil trabalho"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Ligado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tocar para ver ficheiros"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixar"</string>
<string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
<string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1e3a887cf6c9..b444e0abb07d 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"O serviço não foi habilitado."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Não é possível alterar a configuração de identificação de chamadas."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito alterado"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"O serviço de voz está bloqueado."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Redefinir e reiniciar app"</string>
<string name="aerr_report" msgid="5371800241488400617">"Enviar feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Fechar"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorar"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Desativar até que dispositivo seja reiniciado"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Aguarde"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Fechar app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Toque para desativar a depuração do USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Compartilhar o relatório do bug com o administrador?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Seu administrador de TI solicitou um relatório do bug para ajudar a resolver problemas"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados, o que pode deixar seu dispositivo temporariamente mais lento."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Isso pode deixar seu dispositivo temporariamente mais lento"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Gerando relatório do bug..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toque para cancelar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir padrão de desbloqueio antes de liberar"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir senha antes de liberar"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"O app não é redimensionável. Desloque-o com dois dedos."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"É possível que o app não funcione com o recurso de divisão de tela."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"O app não é compatível com a divisão de tela."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalado pelo seu administrador"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Você definiu a importância dessas notificações."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Desativado pelo administrador de %1$s. Entre em contato com ele para saber mais."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Você tem mensagens novas"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Abra o app de SMS para ver"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Algumas funções podem não estar disponíveis."</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Toque para continuar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil do usuário bloqueado"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Algumas funcionalidades são limitadas"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Toque para desbloquear"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Dados do usuário bloqueados"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Perfil de trabalho bloqueado"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Toque p/ desbl. perfil de trab."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toque para ver os arquivos"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixar guia"</string>
<string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 9783507f70c6..a89f1b387b63 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -45,7 +45,7 @@
<string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mesaj vocal"</string>
<string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
<string name="mmiError" msgid="5154499457739052907">"Problemă de conexiune sau cod MMI nevalid."</string>
- <string name="mmiFdnError" msgid="5224398216385316471">"Operația este limitată la numerele cu apelări restricţionate."</string>
+ <string name="mmiFdnError" msgid="5224398216385316471">"Operația este limitată la numerele cu apelări restricționate."</string>
<string name="serviceEnabled" msgid="8147278346414714315">"Serviciul a fost activat."</string>
<string name="serviceEnabledFor" msgid="6856228140453471041">"Serviciul a fost activat pentru:"</string>
<string name="serviceDisabled" msgid="1937553226592516411">"Serviciul a fost dezactivat."</string>
@@ -56,9 +56,9 @@
<string name="badPin" msgid="9015277645546710014">"Codul PIN vechi introdus nu este corect."</string>
<string name="badPuk" msgid="5487257647081132201">"Codul PUK introdus nu este corect."</string>
<string name="mismatchPin" msgid="609379054496863419">"Codurile PIN introduse nu se potrivesc."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Introduceţi un cod PIN alcătuit din 4 până la 8 cifre."</string>
- <string name="invalidPuk" msgid="8761456210898036513">"Introduceţi un cod PUK care să aibă 8 cifre sau mai mult."</string>
- <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceţi codul PUK pentru a-l debloca."</string>
+ <string name="invalidPin" msgid="3850018445187475377">"Introduceți un cod PIN alcătuit din 4 până la 8 cifre."</string>
+ <string name="invalidPuk" msgid="8761456210898036513">"Introduceți un cod PUK care să aibă 8 cifre sau mai mult."</string>
+ <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceți codul PUK pentru a-l debloca."</string>
<string name="needPuk2" msgid="4526033371987193070">"Introduceți codul PUK2 pentru a debloca cardul SIM."</string>
<string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit. Activați blocarea cardului SIM/RUIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
@@ -78,18 +78,17 @@
<string name="PwdMmi" msgid="7043715687905254199">"Modificare parolă"</string>
<string name="PinMmi" msgid="3113117780361190304">"Cod PIN modificat"</string>
<string name="CnipMmi" msgid="3110534680557857162">"Se apelează numărul prezent"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Se apelează un număr restricţionat"</string>
+ <string name="CnirMmi" msgid="3062102121430548731">"Se apelează un număr restricționat"</string>
<string name="ThreeWCMmi" msgid="9051047170321190368">"Apelare de tip conferință"</string>
<string name="RuacMmi" msgid="7827887459138308886">"Respingere apeluri supărătoare nedorite"</string>
<string name="CndMmi" msgid="3116446237081575808">"Se apelează serviciul de furnizare a numerelor"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Nu deranjaţi"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID-ul apelantului este restricţionat în mod prestabilit. Apelul următor: restricţionat"</string>
+ <string name="DndMmi" msgid="1265478932418334331">"Nu deranjați"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID-ul apelantului este restricționat în mod prestabilit. Apelul următor: restricționat"</string>
<string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID-ul apelantului este restricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
<string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: Restricționat."</string>
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Nu se asigură accesul la acest serviciu."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteți să modificați setarea pentru ID-ul apelantului."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acces restricționat modificat"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Serviciul de date este blocat."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Serviciul de urgență este blocat."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Serviciul de voce este blocat."</string>
@@ -119,8 +118,8 @@
<string name="roamingText6" msgid="2059440825782871513">"Roaming - sistem disponibil"</string>
<string name="roamingText7" msgid="7112078724097233605">"Roaming - partenerAlliance"</string>
<string name="roamingText8" msgid="5989569778604089291">"Roaming - partener Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - funcţionalitate completă a serviciului"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - funcţionalitate parţială a serviciului"</string>
+ <string name="roamingText9" msgid="7969296811355152491">"Roaming - funcționalitate completă a serviciului"</string>
+ <string name="roamingText10" msgid="3992906999815316417">"Roaming - funcționalitate parțială a serviciului"</string>
<string name="roamingText11" msgid="4154476854426920970">"Banner roaming activat"</string>
<string name="roamingText12" msgid="1189071119992726320">"Banner roaming dezactivat"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"Se caută serviciul"</string>
@@ -155,13 +154,13 @@
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protocolul nu este acceptat."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Nu s-a putut stabili o conexiune securizată."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Pagina nu a putut fi deschisă, deoarece adresa URL nu este validă."</string>
- <string name="httpErrorFile" msgid="2170788515052558676">"Fişierul nu a putut fi accesat."</string>
- <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nu s-a putut găsi fişierul solicitat."</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"Fișierul nu a putut fi accesat."</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nu s-a putut găsi fișierul solicitat."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Există prea multe solicitări în curs de procesare. Încercați din nou mai târziu."</string>
<string name="notification_title" msgid="8967710025036163822">"Eroare de conectare pentru <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Sincronizare"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ștergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeți câteva fișiere pentru a elibera spațiu."</string>
<string name="low_memory" product="watch" msgid="4415914910770005166">"Spațiul de stocare de pe ceas este plin! Ștergeți câteva fișiere pentru a elibera spațiu."</string>
<string name="low_memory" product="tv" msgid="516619861191025923">"Spațiul de stocare al televizorului este plin. Ștergeți câteva fișiere pentru a elibera spațiu."</string>
@@ -177,9 +176,9 @@
<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>
- <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opţiuni tablet PC"</string>
+ <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opțiuni tablet PC"</string>
<string name="power_dialog" product="tv" msgid="6153888706430556356">"Opțiuni TV"</string>
- <string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
+ <string name="power_dialog" product="default" msgid="1319919075463988638">"Opțiuni telefon"</string>
<string name="silent_mode" msgid="7167703389802618663">"Mod Silențios"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Activați funcția wireless"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Dezactivați funcția wireless"</string>
@@ -200,11 +199,11 @@
<string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ceasul dvs. se va închide."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonul dvs. se va închide."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriți să închideți?"</string>
- <string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniţi în modul sigur"</string>
- <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriți să reporniţi în modul sigur? Astfel vor fi dezactivate toate aplicațiile terţă parte pe care le-ați instalat. Acestea vor fi restabilite când reporniţi din nou."</string>
+ <string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniți în modul sigur"</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriți să reporniți în modul sigur? Astfel vor fi dezactivate toate aplicațiile terță parte pe care le-ați instalat. Acestea vor fi restabilite când reporniți din nou."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string>
<string name="no_recent_tasks" msgid="8794906658732193473">"Nu există aplicații recente."</string>
- <string name="global_actions" product="tablet" msgid="408477140088053665">"Opţiuni tablet PC"</string>
+ <string name="global_actions" product="tablet" msgid="408477140088053665">"Opțiuni tablet PC"</string>
<string name="global_actions" product="tv" msgid="7240386462508182976">"Opțiuni TV"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
@@ -279,36 +278,36 @@
<string name="permdesc_install_shortcut" msgid="8341295916286736996">"Permite unei aplicații să adauge comenzi rapide pe ecranul de pornire, fără intervenția utilizatorului."</string>
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"dezinstalează comenzi rapide"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite aplicației să elimine comenzi rapide de pe ecranul de pornire, fără intervenția utilizatorului."</string>
- <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecţionează apelurile efectuate"</string>
+ <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecționează apelurile efectuate"</string>
<string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite aplicației să vadă numărul format în timpul unui apel de ieșire, cu opțiunea de a redirecționa apelul către un alt număr sau de a întrerupe apelul."</string>
- <string name="permlab_receiveSms" msgid="8673471768947895082">"primeşte mesaje text (SMS)"</string>
+ <string name="permlab_receiveSms" msgid="8673471768947895082">"primește mesaje text (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
- <string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
+ <string name="permlab_receiveMms" msgid="1821317344668257098">"primește mesaje text (MMS)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"citește mesajele cu transmisie celulară"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanța sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgență."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obțină detalii despre feedurile sincronizate în prezent."</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"trimită și să vadă mesajele SMS"</string>
- <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neașteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neașteptate. Aplicațiile rău intenționate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"citește mesajele text (SMS sau MMS)"</string>
- <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
<string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
- <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Permite aplicației să citească mesajele SMS stocate pe telefon sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string>
- <string name="permlab_receiveWapPush" msgid="5991398711936590410">"primeşte mesaje text (WAP)"</string>
+ <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Permite aplicației să citească mesajele SMS stocate pe telefon sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
+ <string name="permlab_receiveWapPush" msgid="5991398711936590410">"primește mesaje text (WAP)"</string>
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau șterge mesajele care v-au fost trimise fără a vi le arăta."</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"preluare aplicații care rulează"</string>
- <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informațiile despre activităţile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informațiile despre activitățile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"să gestioneze profilul și proprietarii dispozitivului"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Permite aplicațiilor să seteze proprietarii de profiluri și proprietarul dispozitivului."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"reordonare aplicații care rulează"</string>
- <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite aplicației să mute activităţile în prim-plan și în fundal. Aplicaţia poate face acest lucru fără aportul dvs."</string>
- <string name="permlab_enableCarMode" msgid="5684504058192921098">"activare mod Maşină"</string>
- <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite aplicației să activeze modul Maşină."</string>
+ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite aplicației să mute activitățile în prim-plan și în fundal. Aplicația poate face acest lucru fără aportul dvs."</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"activare mod Mașină"</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite aplicației să activeze modul Mașină."</string>
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"închide alte aplicații"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite aplicației să oprească procesele derulate în fundal de alte aplicații. Acest lucru poate face ca respectivele aplicații să nu mai ruleze."</string>
<string name="permlab_systemAlertWindow" msgid="3543347980839518613">"suprapune elemente vizuale peste alte aplicații"</string>
- <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părți ale interfeței cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeței în orice aplicație sau pot schimba ceea ce credeți că vedeţi în alte aplicații."</string>
+ <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părți ale interfeței cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeței în orice aplicație sau pot schimba ceea ce credeți că vedeți în alte aplicații."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"rulare continuă a aplicației"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea tabletei."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea televizorului."</string>
@@ -316,7 +315,7 @@
<string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spațiu de stocare al aplicației"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"modifică setări de sistem"</string>
- <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permite aplicației să modifice datele din setările sistemului. Aplicaţiile rău intenţionate pot corupe configuraţia sistemului dvs."</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permite aplicației să modifice datele din setările sistemului. Aplicațiile rău intenționate pot corupe configurația sistemului dvs."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"rulează la pornire"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea tabletei poate dura mai mult timp, iar rularea continuă a aplicației poate încetini dispozitivul."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea televizorului poate dura mai mult timp, iar funcționarea continuă a aplicației poate încetini televizorul."</string>
@@ -326,27 +325,27 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"citește agenda"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenționate pot distribui datele de contact fără știrea dvs."</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenționate pot distribui datele de contact fără știrea dvs."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"citește jurnalul de apeluri"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenționate pot distribui aceste date fără știrea dvs."</string>
<string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string>
- <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenționate pot distribui aceste date fără știrea dvs."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
<string name="permlab_bodySensors" msgid="4683341291818520277">"să acceseze senzorii corporali (cum ar fi monitoarele cardiace)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Permite aplicației să acceseze date de la senzorii care vă monitorizează starea fizică, cum ar fi ritmul cardiac."</string>
- <string name="permlab_readCalendar" msgid="5972727560257612398">"citirea evenimentelor din calendar și a informaţiilor confidenţiale"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
+ <string name="permlab_readCalendar" msgid="5972727560257612398">"citirea evenimentelor din calendar și a informațiilor confidențiale"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
<string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Permite aplicației să citească toate evenimentele din calendar stocate pe televizor, inclusiv cele ale prietenilor sau colegilor. Cu această permisiune, aplicația poate să permită accesul la datele din calendar sau să le salveze, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
- <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
<string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaților fără știrea proprietarului"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string>
@@ -354,9 +353,9 @@
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
<string name="permlab_accessFineLocation" msgid="251034415460950944">"să acceseze locația exactă (bazată pe GPS și pe rețea)"</string>
- <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obţină locația dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locația dvs. și pot să consume mai multă energie a bateriei."</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obțină locația dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicațiile pot utiliza această permisiune pentru a determina locația dvs. și pot să consume mai multă energie a bateriei."</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"să acceseze locația aproximativă (bazată pe rețea)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locația dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locația dvs. aproximativă."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obțină locația dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicațiile pot utiliza această permisiune pentru a determina locația dvs. aproximativă."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"înregistreze sunet"</string>
@@ -368,11 +367,11 @@
<string name="permlab_vibrate" msgid="7696427026057705834">"controlează vibrarea"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite aplicației să controleze mecanismul de vibrare."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
- <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenția dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgență. Aplicațiile rău intenționate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
<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="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_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
<string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"împiedică intrarea televizorului în stare de inactivitate"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
@@ -392,11 +391,11 @@
<string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Permite aplicației să modifice fusul orar al televizorului."</string>
<string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite aplicației să schimbe fusul orar al telefonului."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"găsește conturi pe dispozitiv"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Permite aplicației să obţină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Permite aplicației să obțină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
<string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Permite aplicației să obțină lista de conturi cunoscute de televizor. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
- <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permite aplicației să obţină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permite aplicației să obțină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"vizualizează conexiunile la rețea"</string>
- <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite aplicației să vadă informațiile despre conexiunile la rețea, cum ar fi reţelele existente și cele care sunt conectate."</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite aplicației să vadă informațiile despre conexiunile la rețea, cum ar fi rețelele existente și cele care sunt conectate."</string>
<string name="permlab_createNetworkSockets" msgid="7934516631384168107">"să aibă acces deplin la rețea"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permite aplicației să creeze socluri de rețea și să utilizeze protocoale de rețea personalizate. Browserul și alte aplicații oferă mijloacele de trimitere a datelor pe internet, astfel încât această permisiune nu este necesară pentru trimiterea datelor pe internet."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"modificare conectivitate în rețea"</string>
@@ -404,10 +403,10 @@
<string name="permlab_changeTetherState" msgid="5952584964373017960">"modificare conectivitate tethering"</string>
<string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permite aplicației să modifice starea de conectivitate prin tethering la rețea."</string>
<string name="permlab_accessWifiState" msgid="5202012949247040011">"vizualizează conexiunile Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite aplicației să vadă informațiile despre reţelele Wi-Fi, de ex. dacă o rețea Wi-Fi este activată, precum și numele dispozitivelor conectate la rețeaua Wi-Fi."</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite aplicației să vadă informațiile despre rețelele Wi-Fi, de ex. dacă o rețea Wi-Fi este activată, precum și numele dispozitivelor conectate la rețeaua Wi-Fi."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"se conectează și se deconectează de la Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite aplicației să se conecteze și să se deconecteze de la punctele de acces Wi-Fi, precum și să efectueze modificări în configuraţia dispozitivului pentru reţelele Wi-Fi."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitere recepţionare difuzare multiplă Wi-Fi"</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite aplicației să se conecteze și să se deconecteze de la punctele de acces Wi-Fi, precum și să efectueze modificări în configurația dispozitivului pentru rețelele Wi-Fi."</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitere recepționare difuzare multiplă Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar tableta dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar televizorul dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar telefonul dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
@@ -416,19 +415,19 @@
<string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Permite aplicației să configureze televizorul Bluetooth local, precum și să descopere și să se asocieze cu dispozitive la distanță."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite aplicației să configureze telefonul Bluetooth local, să descopere și să se împerecheze cu dispozitive la distanță."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"se conectează și se deconectează de la WiMAX"</string>
- <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informațiile cu privire la toate reţelele WiMAX conectate."</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informațiile cu privire la toate rețelele WiMAX conectate."</string>
<string name="permlab_changeWimaxState" msgid="340465839241528618">"schimbați starea WiMAX"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicației să conecteze și să deconecteze tableta la și de la reţelele WiMAX."</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicației să conecteze și să deconecteze tableta la și de la rețelele WiMAX."</string>
<string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Permite aplicației să conecteze și să deconecteze televizorul la și de la rețelele WiMAX."</string>
- <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite aplicației să conecteze și să deconecteze telefonul la și de la reţelele WiMAX."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite aplicației să conecteze și să deconecteze telefonul la și de la rețelele WiMAX."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"conectează dispozitive Bluetooth"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite aplicației să vadă configuraţia tabletei Bluetooth, să efectueze și să accepte conexiuni cu dispozitive împerecheate."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite aplicației să vadă configurația tabletei Bluetooth, să efectueze și să accepte conexiuni cu dispozitive împerecheate."</string>
<string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Permite aplicației să vadă configurația funcției Bluetooth a televizorului, precum și să efectueze și să accepte conexiuni cu dispozitive asociate."</string>
- <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite aplicației să vadă configuraţia telefonului Bluetooth, să efectueze și să accepte conexiuni cu dispozitive împerecheate."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite aplicației să vadă configurația telefonului Bluetooth, să efectueze și să accepte conexiuni cu dispozitive împerecheate."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlare schimb de date prin Near Field Communication"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Permite aplicației să comunice cu etichetele, cardurile și cititoarele NFC (Near Field Communication)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"dezactivează blocarea ecranului"</string>
- <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite aplicației să dezactiveze blocarea tastelor și orice modalitate asociată de securizare prin parolă. De exemplu, telefonul dezactivează blocarea tastelor când se primeşte un apel telefonic și reactivează blocarea tastelor la terminarea apelului."</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite aplicației să dezactiveze blocarea tastelor și orice modalitate asociată de securizare prin parolă. De exemplu, telefonul dezactivează blocarea tastelor când se primește un apel telefonic și reactivează blocarea tastelor la terminarea apelului."</string>
<string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestionează hardware-ul pentru amprentă"</string>
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite aplicației să invoce metode pentru a adăuga și pentru a șterge șabloane de amprentă pentru utilizare."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"folosește hardware-ul pentru amprentă"</string>
@@ -456,12 +455,12 @@
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Permite unei aplicații să modifice setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicația poate activa sincronizarea aplicației Persoane cu un anumit cont."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"citire statistici privind sincronizarea"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Permite unei aplicații să citească statisticile de sincronizare ale unui cont, inclusiv istoricul evenimentelor de sincronizare și volumul datelor sincronizate."</string>
- <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"citește conţinutul stocării USB"</string>
- <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"citește conţinutul cardului SD"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"citește conținutul stocării USB"</string>
+ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"citește conținutul cardului SD"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permite aplic. citirea conținutului stoc. USB."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permite aplicației citirea conținutul cardului SD."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau șterge conţinutul stocării USB"</string>
- <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau șterge conţinutul cardului SD"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau șterge conținutul stocării USB"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau șterge conținutul cardului SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permite scriere în stoc. USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicației să scrie pe cardul SD."</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"efectuarea/primirea apelurilor SIP"</string>
@@ -483,7 +482,7 @@
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"gestionează politica de rețea"</string>
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicației să gestioneze politicile de rețea și să definească regulile specifice aplicațiilor."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificați modul de calcul al utilizării rețelei"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obişnuite."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obișnuite."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
@@ -513,7 +512,7 @@
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setați reguli pentru parolă"</string>
<string name="policydesc_limitPassword" msgid="2502021457917874968">"Stabiliți lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizați încercările de deblocare a ecranului"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocaţi tableta sau ștergeți datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
<string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați televizorul sau ștergeți toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați telefonul sau ștergeți toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
@@ -593,7 +592,7 @@
<string name="phoneTypePager" msgid="7582359955394921732">"Pager"</string>
<string name="phoneTypeOther" msgid="1544425847868765990">"Altele"</string>
<string name="phoneTypeCallback" msgid="2712175203065678206">"Apelare inversă"</string>
- <string name="phoneTypeCar" msgid="8738360689616716982">"Maşină"</string>
+ <string name="phoneTypeCar" msgid="8738360689616716982">"Mașină"</string>
<string name="phoneTypeCompanyMain" msgid="540434356461478916">"Numărul de telefon principal al companiei"</string>
<string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
<string name="phoneTypeMain" msgid="6766137010628326916">"Număr de telefon principal"</string>
@@ -606,7 +605,7 @@
<string name="phoneTypeAssistant" msgid="5596772636128562884">"Asistent"</string>
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
<string name="eventTypeCustom" msgid="7837586198458073404">"Personalizate"</string>
- <string name="eventTypeBirthday" msgid="2813379844211390740">"Zi de naştere"</string>
+ <string name="eventTypeBirthday" msgid="2813379844211390740">"Zi de naștere"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Zi aniversară"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"Altul"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"Personalizat"</string>
@@ -655,13 +654,13 @@
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Serviciu"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Altul"</string>
<string name="quick_contacts_not_available" msgid="746098007828579688">"Nu s-a găsit nicio aplicație pentru a afișa această persoană de contact."</string>
- <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceţi codul PIN"</string>
- <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduceţi codul PUK și noul cod PIN"</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceți codul PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Introduceți codul PUK și noul cod PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Codul PUK"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Noul cod PIN"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceţi parola"</font></string>
- <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
- <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Atingeți și introduceți parola"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceți parola pentru a debloca"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceți codul PIN pentru a debloca"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsați Meniu, apoi 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgență"</string>
@@ -669,58 +668,58 @@
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecranul este blocat."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsați Meniu pentru deblocare."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenaţi modelul pentru a debloca"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenați modelul pentru a debloca"</string>
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"Urgență"</string>
- <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Reveniţi la apel"</string>
+ <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Reveniți la apel"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Corect!"</string>
<string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Încercați din nou"</string>
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Încercați din nou"</string>
- <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depăşit numărul maxim de încercări pentru Deblocare facială"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depășit numărul maxim de încercări pentru Deblocare facială"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Niciun card SIM"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nu există card SIM în computerul tablet PC."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Niciun card SIM în televizor."</string>
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Telefonul nu are card SIM."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Introduceţi un card SIM."</string>
- <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Cardul SIM lipseşte sau nu poate fi citit. Introduceţi un card SIM."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Introduceți un card SIM."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Cardul SIM lipsește sau nu poate fi citit. Introduceți un card SIM."</string>
<string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Card SIM inutilizabil."</string>
- <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Cardul dvs. SIM este dezactivat definitiv.\n Contactaţi furnizorul de servicii wireless pentru a obţine un alt card SIM."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Cardul dvs. SIM este dezactivat definitiv.\n Contactați furnizorul de servicii wireless pentru a obține un alt card SIM."</string>
<string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Melodia anterioară"</string>
<string name="lockscreen_transport_next_description" msgid="573285210424377338">"Melodia următoare"</string>
<string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pauză"</string>
<string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Redați"</string>
<string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Opriți"</string>
- <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Derulaţi"</string>
- <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Derulaţi rapid înainte"</string>
+ <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Derulați"</string>
+ <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Derulați rapid înainte"</string>
<string name="emergency_calls_only" msgid="6733978304386365407">"Numai apeluri de urgență"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rețea blocată"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Cardul SIM este blocat cu codul PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultaţi Ghidul de utilizare sau contactaţi Serviciul de relaţii cu clienţii."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultați Ghidul de utilizare sau contactați Serviciul de relații cu clienții."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Cardul SIM este blocat."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Se deblochează cardul SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
- <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Aţi efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Aţi efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va fi acum resetat la setările prestabilite din fabrică."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va fi acum resetat la setările prestabilite din fabrică."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Încercați din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ați uitat modelul?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Deblocare cont"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Prea multe încercări de desenare a modelului"</string>
- <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Pentru a debloca, conectaţi-vă folosind Contul Google."</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Pentru a debloca, conectați-vă folosind Contul Google."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nume de utilizator (e-mail)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parolă"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Conectați-vă"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nume de utilizator sau parolă nevalide."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Aţi uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Se verifică..."</string>
- <string name="lockscreen_unlock_label" msgid="737440483220667054">"Deblocaţi"</string>
+ <string name="lockscreen_unlock_label" msgid="737440483220667054">"Deblocați"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sunet activat"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sunet dezactivat"</string>
<string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Desenarea modelului a început"</string>
@@ -742,7 +741,7 @@
<string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"A început reordonarea widgeturilor."</string>
<string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordonarea widgeturilor s-a încheiat."</string>
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgetul <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a fost eliminat."</string>
- <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Extindeţi zona de deblocare."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Extindeți zona de deblocare."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Deblocare prin glisare."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Deblocare cu model."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Deblocare facială."</string>
@@ -758,7 +757,7 @@
<string name="granularity_label_link" msgid="5815508880782488267">"link"</string>
<string name="granularity_label_line" msgid="5764267235026120888">"rând"</string>
<string name="factorytest_failed" msgid="5410270329114212041">"Testarea de fabrică nu a reușit"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Acţiunea FACTORY_TEST este acceptată doar pentru pachetele instalate în /system/app."</string>
+ <string name="factorytest_not_system" msgid="4435201656767276723">"Acțiunea FACTORY_TEST este acceptată doar pentru pachetele instalate în /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Nu s-a găsit niciun pachet care să ofere acțiunea FACTORY_TEST."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Reporniți"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La pagina de la „<xliff:g id="TITLE">%s</xliff:g>” apare:"</string>
@@ -776,7 +775,7 @@
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
<string name="autofill_province" msgid="2231806553863422300">"Provincie"</string>
- <string name="autofill_postal_code" msgid="4696430407689377108">"Cod poştal"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Cod poștal"</string>
<string name="autofill_state" msgid="6988894195520044613">"Stat"</string>
<string name="autofill_zip_code" msgid="8697544592627322946">"Cod ZIP"</string>
<string name="autofill_county" msgid="237073771020362891">"Județ"</string>
@@ -788,20 +787,20 @@
<string name="autofill_area" msgid="3547409050889952423">"Zonă"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"citește marcajele și istoricul web"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"scrie în marcajele și în istoricul web"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Permite aplicației să modifice istoricul sau marcajele browserului stocate pe televizor. Cu această permisiune, aplicația poate șterge sau modifica datele din browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcție."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite aplicației să adauge mesaje în Mesaje primite în mesageria vocală."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modificare permisiuni pentru locația geografică a browserului"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicației să modifice permisiunile privind locația geografică a browserului. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a permite trimiterea informaţiilor privind locația către site-uri web arbitrare."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicației să modifice permisiunile privind locația geografică a browserului. Aplicațiile rău intenționate pot utiliza această permisiune pentru a permite trimiterea informațiilor privind locația către site-uri web arbitrare."</string>
<string name="save_password_message" msgid="767344687139195790">"Doriți ca browserul să rețină această parolă?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
+ <string name="save_password_remember" msgid="6491879678996749466">"Rețineți"</string>
<string name="save_password_never" msgid="8274330296785855105">"Niciodată"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"Nu aveți permisiunea de a deschide această pagină."</string>
<string name="text_copied" msgid="4985729524670131385">"Text copiat în clipboard."</string>
@@ -818,8 +817,8 @@
<string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteți interogarea"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
<string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Explorați prin atingere?"</string>
- <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
- <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacționa cu tableta."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacționa cu telefonul."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
<plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -866,8 +865,8 @@
<string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"prânz"</string>
<string name="Noon" msgid="3342127745230013127">"Prânz"</string>
- <string name="midnight" msgid="7166259508850457595">"miezul nopţii"</string>
- <string name="Midnight" msgid="5630806906897892201">"Miezul nopţii"</string>
+ <string name="midnight" msgid="7166259508850457595">"miezul nopții"</string>
+ <string name="Midnight" msgid="5630806906897892201">"Miezul nopții"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Selectați-le pe toate"</string>
@@ -875,19 +874,19 @@
<string name="copy" msgid="2681946229533511987">"Copiați"</string>
<string name="paste" msgid="5629880836805036433">"Inserați"</string>
<string name="paste_as_plain_text" msgid="5427792741908010675">"Inserați ca text simplu"</string>
- <string name="replace" msgid="5781686059063148930">"Înlocuiţi..."</string>
+ <string name="replace" msgid="5781686059063148930">"Înlocuiți..."</string>
<string name="delete" msgid="6098684844021697789">"Ștergeți"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiați adresa URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Selectați text"</string>
<string name="undo" msgid="7905788502491742328">"Anulați"</string>
<string name="redo" msgid="7759464876566803888">"Repetați"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selectare text"</string>
- <string name="addToDictionary" msgid="4352161534510057874">"Adăugați în dicţionar"</string>
+ <string name="addToDictionary" msgid="4352161534510057874">"Adăugați în dicționar"</string>
<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="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="editTextMenuTitle" msgid="4909135564941815494">"Acțiuni pentru text"</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>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează acum"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"Atingeți pentru mai multe informații sau pentru a opri aplicația."</string>
@@ -895,7 +894,7 @@
<string name="cancel" msgid="6442560571259935130">"Anulați"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Anulați"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atenţie"</string>
+ <string name="dialog_alert_title" msgid="2049658708609043103">"Atenție"</string>
<string name="loading" msgid="7933681260296021180">"Se încarcă…"</string>
<string name="capital_on" msgid="1544682755514494298">"DA"</string>
<string name="capital_off" msgid="6815870386972805832">"NU"</string>
@@ -909,12 +908,12 @@
<string name="whichSendApplicationNamed" msgid="2799370240005424391">"Distribuiți cu %1$s"</string>
<string name="whichHomeApplication" msgid="4307587691506919691">"Selectați o aplicație de pe ecranul de pornire"</string>
<string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utilizați %1$s ca ecran de pornire"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acţiune."</string>
+ <string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acțiune."</string>
<string name="use_a_different_app" msgid="8134926230585710243">"Utilizați altă aplicație"</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ștergeți setările prestabilite din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
- <string name="chooseActivity" msgid="7486876147751803333">"Alegeți o acţiune"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"Alegeți o acțiune"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"Alegeți o aplicație pentru dispozitivul USB"</string>
- <string name="noApplications" msgid="2991814273936504689">"Această acţiune nu poate fi efectuată de nicio aplicație."</string>
+ <string name="noApplications" msgid="2991814273936504689">"Această acțiune nu poate fi efectuată de nicio aplicație."</string>
<string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> s-a oprit"</string>
<string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> s-a oprit"</string>
<string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se oprește încontinuu"</string>
@@ -923,7 +922,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Resetați și reporniți aplicația"</string>
<string name="aerr_report" msgid="5371800241488400617">"Trimiteți feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Închideți"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Dezactivați"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Dezactivați până la repornirea dispozitivului"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Așteptați"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Închideți aplicația"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -933,15 +932,15 @@
<string name="anr_process" msgid="6156880875555921105">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde"</string>
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Raportați"</string>
- <string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string>
+ <string name="wait" msgid="7147118217226317732">"Așteptați"</string>
<string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriți să o închideți?"</string>
- <string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecționată"</string>
- <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
- <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"Aplicație redirecționată"</string>
+ <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcționează acum."</string>
+ <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată inițial."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
- <string name="screen_compat_mode_show" msgid="4013878876486655892">"Afişaţi întotdeauna"</string>
+ <string name="screen_compat_mode_show" msgid="4013878876486655892">"Afișați întotdeauna"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
- <string name="smv_application" msgid="3307209192155442829">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
+ <string name="smv_application" msgid="3307209192155442829">"Aplicația <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string>
<string name="android_start_title" msgid="8418054686415318207">"Android pornește..."</string>
@@ -952,21 +951,21 @@
<string name="android_upgrading_complete" msgid="1405954754112999229">"Se finalizează pornirea."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Atingeți pentru a comuta la aplicație"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Comutaţi între aplicații?"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Comutați între aplicații?"</string>
<string name="heavy_weight_switcher_text" msgid="7022631924534406403">"O altă aplicație rulează deja și trebuie oprită înainte a putea porni o aplicație nouă."</string>
- <string name="old_app_action" msgid="493129172238566282">"Reveniţi la <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="old_app_action" msgid="493129172238566282">"Reveniți la <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="old_app_description" msgid="2082094275580358049">"Nu porniți aplicația nouă."</string>
- <string name="new_app_action" msgid="5472756926945440706">"Porniţi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_action" msgid="5472756926945440706">"Porniți <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="new_app_description" msgid="1932143598371537340">"Opriți vechea aplicație fără să salvați."</string>
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> a depășit limita de memorie"</string>
<string name="dump_heap_notification_detail" msgid="2075673362317481664">"Datele privind memoria au fost culese; atingeți pentru a trimite"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Trimiteți datele privind memoria?"</string>
<string name="dump_heap_text" msgid="4809417337240334941">"Procesul <xliff:g id="PROC">%1$s</xliff:g> și-a depășit limita de memorie de <xliff:g id="SIZE">%2$s</xliff:g>. Sunt disponibile datele privind memoria, pe care le puteți trimite dezvoltatorului. Atenție: aceste date privind memoria pot conține informațiile personale la care aplicația are acces."</string>
- <string name="sendText" msgid="5209874571959469142">"Alegeți o acţiune pentru text"</string>
+ <string name="sendText" msgid="5209874571959469142">"Alegeți o acțiune pentru text"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Volum sonerie"</string>
<string name="volume_music" msgid="5421651157138628171">"Volum media"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Redare prin Bluetooth"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Ton de apel silenţios setat"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Ton de apel silențios setat"</string>
<string name="volume_call" msgid="3941680041282788711">"Volum apel de intrare"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Volum apel Bluetooth"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Volum alarmă"</string>
@@ -992,7 +991,7 @@
<item quantity="other">Rețele Wi-Fi deschise disponibile</item>
<item quantity="one">Rețea Wi-Fi deschisă disponibilă</item>
</plurals>
- <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la reţeaua Wi-Fi"</string>
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la rețeaua Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Conectați-vă la rețea"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
@@ -1004,26 +1003,26 @@
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplicația %1$s dorește să se conecteze la rețeaua Wi-Fi %2$s"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"O aplicație"</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniți Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeți pentru setări"</string>
- <string name="accept" msgid="1645267259272829559">"Acceptaţi"</string>
- <string name="decline" msgid="2112225451706137894">"Refuzaţi"</string>
- <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitaţia a fost trimisă."</string>
+ <string name="accept" msgid="1645267259272829559">"Acceptați"</string>
+ <string name="decline" msgid="2112225451706137894">"Refuzați"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitația a fost trimisă."</string>
<string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitație pentru conectare"</string>
<string name="wifi_p2p_from_message" msgid="570389174731951769">"De la:"</string>
<string name="wifi_p2p_to_message" msgid="248968974522044099">"Către:"</string>
- <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceți codul PIN necesar:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
<string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectată la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"Televizorul se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
- <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la reţeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
- <string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="select_character" msgid="3365550120617701745">"Introduceți caracterul"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
<string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"Permiteți"</string>
- <string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Refuzați"</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; intenționează să trimită un mesaj la &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"Acest lucru "<b>"poate genera costuri"</b>" în contul dvs. mobil."</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Acest lucru va genera costuri în contul dvs. mobil."</b></string>
@@ -1038,14 +1037,14 @@
<string name="sim_done_button" msgid="827949989369963775">"Terminat"</string>
<string name="sim_added_title" msgid="3719670512889674693">"Card SIM adăugat"</string>
<string name="sim_added_message" msgid="7797975656153714319">"Reporniți dispozitivul pentru a accesa rețeaua mobilă."</string>
- <string name="sim_restart_button" msgid="4722407842815232347">"Reporniţi"</string>
+ <string name="sim_restart_button" msgid="4722407842815232347">"Reporniți"</string>
<string name="carrier_app_dialog_message" msgid="7066156088266319533">"Pentru ca noul SIM să funcționeze corect, va trebui să instalați și să deschideți o aplicație de la operatorul dvs."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"DESCĂRCAȚI APLICAȚIA"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NU ACUM"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"S-a introdus un card SIM nou"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Atingeți pentru a-l configura"</string>
- <string name="time_picker_dialog_title" msgid="8349362623068819295">"Setaţi ora"</string>
- <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setaţi data"</string>
+ <string name="time_picker_dialog_title" msgid="8349362623068819295">"Setați ora"</string>
+ <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setați data"</string>
<string name="date_time_set" msgid="5777075614321087758">"Setați"</string>
<string name="date_time_done" msgid="2507683751759308828">"Terminat"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NOU: "</font></string>
@@ -1061,12 +1060,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"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="1016654627626476142">"Atingeți pentru a dezactiva depanarea USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Trimiteți raportul de eroare administratorului?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații, iar funcționarea dispozitivului poate fi încetinită temporar."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Acest proces poate încetini temporar funcționarea dispozitivului"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTAȚI"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZAȚI"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Se creează un raport de eroare…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Atingeți pentru a anula"</string>
<string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Alegeți tastaturi"</string>
<string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
@@ -1075,7 +1075,7 @@
<string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Atingeți pentru a selecta un aspect de tastatură."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidaţi"</u></string>
+ <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Se pregătește <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Se verifică dacă există erori"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"A fost detectat un nou <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1119,7 +1119,7 @@
<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="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeți de două ori pentru a mări/micşora"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeți de două ori pentru a mări/micșora"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nu s-a putut adăuga widgetul."</string>
<string name="ime_action_go" msgid="8320845651737369027">"Accesați"</string>
<string name="ime_action_search" msgid="658110271822807811">"Căutați"</string>
@@ -1128,13 +1128,13 @@
<string name="ime_action_done" msgid="8971516117910934605">"Terminat"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"Înapoi"</string>
<string name="ime_action_default" msgid="2840921885558045721">"Executați"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Formaţi numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="dial_number_using" msgid="5789176425167573586">"Formați numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Creați contactul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Următoarele aplicații solicită permisiunea de a accesa contul dvs. acum și în viitor."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Permiteți această solicitare?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"Solicitare de acces"</string>
<string name="allow" msgid="7225948811296386551">"Permiteți"</string>
- <string name="deny" msgid="2081879885755434506">"Refuzaţi"</string>
+ <string name="deny" msgid="2081879885755434506">"Refuzați"</string>
<string name="permission_request_notification_title" msgid="6486759795926237907">"Permisiune solicitată"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Permisiune solicitată\npentru contul <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="forward_intent_to_owner" msgid="1207197447013960896">"Utilizați această aplicație în afara profilului de serviciu"</string>
@@ -1143,29 +1143,29 @@
<string name="sync_binding_label" msgid="3687969138375092423">"Sincronizare"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilitate"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
- <string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"Modificați imaginea de fundal"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
<string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent pentru notificări"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
- <string name="vpn_text" msgid="3011306607126450322">"Atingeți pentru a gestiona reţeaua."</string>
- <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeți pentru a gestiona reţeaua."</string>
- <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la reţeaua VPN activată permanent…"</string>
- <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la reţeaua VPN activată permanent"</string>
+ <string name="vpn_text" msgid="3011306607126450322">"Atingeți pentru a gestiona rețeaua."</string>
+ <string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeți pentru a gestiona rețeaua."</string>
+ <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la rețeaua VPN activată permanent…"</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la rețeaua VPN activată permanent"</string>
<string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string>
<string name="vpn_lockdown_config" msgid="6415899150671537970">"Atingeți pentru a configura"</string>
<string name="upload_file" msgid="2897957172366730416">"Alegeți un fișier"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
- <string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
+ <string name="reset" msgid="2448168080964209908">"Resetați"</string>
<string name="submit" msgid="1602335572089911941">"Trimiteți"</string>
- <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Maşină activat"</string>
- <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieşi din modul Maşină."</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Mașină activat"</string>
+ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieși din modul Mașină."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"Atingeți pentru a configura."</string>
<string name="back_button_label" msgid="2300470004503343439">"Înapoi"</string>
<string name="next_button_label" msgid="1080555104677992408">"Înainte"</string>
- <string name="skip_button_label" msgid="1275362299471631819">"Omiteţi"</string>
+ <string name="skip_button_label" msgid="1275362299471631819">"Omiteți"</string>
<string name="no_matches" msgid="8129421908915840737">"Nicio potrivire"</string>
<string name="find_on_page" msgid="1946799233822820384">"Găsiți pe pagină"</string>
<plurals name="matches_found" formatted="false" msgid="1210884353962081884">
@@ -1186,10 +1186,10 @@
<string name="gpsNotifMessage" msgid="1374718023224000702">"Solicitat de <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
<string name="gpsVerifYes" msgid="2346566072867213563">"Da"</string>
<string name="gpsVerifNo" msgid="1146564937346454865">"Nu"</string>
- <string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ştergere a fost depăşită"</string>
- <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceți?"</string>
+ <string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ștergere a fost depășită"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente șterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceți?"</string>
<string name="sync_really_delete" msgid="2572600103122596243">"Ștergeți elementele"</string>
- <string name="sync_undo_deletes" msgid="2941317360600338602">"Anulați aceste ştergeri"</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"Anulați aceste ștergeri"</string>
<string name="sync_do_nothing" msgid="3743764740430821845">"Nu trebuie să luați nicio măsură deocamdată"</string>
<string name="choose_account_label" msgid="5655203089746423927">"Alegeți un cont"</string>
<string name="add_account_label" msgid="2935267344849993553">"Adăugați un cont"</string>
@@ -1197,13 +1197,13 @@
<string name="number_picker_increment_button" msgid="2412072272832284313">"Creșteți"</string>
<string name="number_picker_decrement_button" msgid="476050778386779067">"Reduceți"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeți și țineți apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
- <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisaţi în sus pentru a creşte și în jos pentru a reduce."</string>
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisați în sus pentru a crește și în jos pentru a reduce."</string>
<string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creșteți valoarea pentru minute"</string>
<string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduceți valoarea pentru minute"</string>
<string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creșteți valoarea pentru oră"</string>
<string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reduceți valoarea pentru oră"</string>
- <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setaţi valoarea PM"</string>
- <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setaţi valoarea AM"</string>
+ <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setați valoarea PM"</string>
+ <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setați valoarea AM"</string>
<string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creșteți valoarea pentru lună"</string>
<string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reduceți valoarea pentru lună"</string>
<string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creșteți valoarea pentru zi"</string>
@@ -1224,11 +1224,11 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Permiteți accesul pentru"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Permiteți accesul pentru <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Mâner glisant. Atingeți și țineți apăsat."</string>
- <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glisaţi pentru a debloca."</string>
- <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conectaţi un set căşti-microfon pentru a auzi tastele apăsate când introduceţi parola."</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glisați pentru a debloca."</string>
+ <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conectați un set căști-microfon pentru a auzi tastele apăsate când introduceți parola."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punct."</string>
- <string name="action_bar_home_description" msgid="5293600496601490216">"Navigaţi la ecranul de pornire"</string>
- <string name="action_bar_up_description" msgid="2237496562952152589">"Navigaţi în sus"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navigați la ecranul de pornire"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navigați în sus"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Mai multe opțiuni"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
@@ -1246,12 +1246,12 @@
<string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Ați atins limita de date mobile"</string>
<string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Ați atins limita de date Wi-Fi"</string>
<string name="data_usage_limit_body" msgid="291731708279614081">"S-au întrerupt datele pentru restul ciclului"</string>
- <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"S-a depăşit limita de date 2G-3G"</string>
- <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"S-a depăşit limita de date 4G"</string>
+ <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"S-a depășit limita de date 2G-3G"</string>
+ <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"S-a depășit limita de date 4G"</string>
<string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Limită de date mobile depășită"</string>
- <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"S-a depăşit limita de date Wi-Fi"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"S-a depășit limita de date Wi-Fi"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> peste limita specificată."</string>
- <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datele de fundal restricţionate"</string>
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datele de fundal restricționate"</string>
<string name="data_usage_restricted_body" msgid="6741521330997452990">"Atingeți pt. a elimina limita."</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Certificat de securitate"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certificatul este valid."</string>
@@ -1302,45 +1302,45 @@
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", securizat"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
- <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greșit"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greșită"</string>
- <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greșit"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercați din nou peste <xliff:g id="NUMBER">%1$d</xliff:g> (de) secunde."</string>
- <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
- <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
- <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
- <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceţi codul PUK pentru a continua. Contactaţi operatorul pentru mai multe detalii."</string>
- <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceţi codul PIN dorit"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenați modelul"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceți codul PIN al cardului SIM"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceți codul PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceți parola"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Cardul SIM este acum dezactivat. Introduceți codul PUK pentru a continua. Contactați operatorul pentru mai multe detalii."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Introduceți codul PIN dorit"</string>
<string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmați codul PIN dorit"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
- <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceți un cod PIN format din 4 până la 8 cifre."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Codul PUK trebuie să conțină 8 numere."</string>
- <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceți codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
- <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectați-vă cu Contul dvs. Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Conectați-vă"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
- <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"Se verifică contul…"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Aţi efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Aţi efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
- <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
- <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
<string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string>
<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="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>
@@ -1477,7 +1477,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicită modelul pentru deblocare înainte de a anula fixarea"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicită parola înainte de a anula fixarea"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Aplicația nu poate fi redimensionată. Derulați în ea cu două degete."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplicația nu acceptă ecranul împărțit."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Instalat de administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizat de un administrator"</string>
@@ -1556,12 +1556,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selectat</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Dvs. setați importanța acestor notificări."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Dvs. setați importanța acestor notificări."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Notificarea este importantă având în vedere persoanele implicate."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Limba preferată"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Adăugați o limbă"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Regiunea preferată"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string>
@@ -1574,12 +1573,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Dezactivat de administratorul companiei %1$s. Contactați-l pentru a afla mai multe."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Aveți mesaje noi"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Deschideți aplicația pentru SMS-uri ca să vizualizați"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Este posibil ca unele funcții să nu fie disponibile"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Atingeți pentru a continua"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil utilizator: blocat"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Unele funcții ar putea fi limitate"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Atingeți pentru a debloca"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Datele utilizatorului: blocate"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profil de serviciu blocat"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Atingeți ca să deblocați"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectat la <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Atingeți pentru a vedea fișierele"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixați"</string>
<string name="unpin_target" msgid="3556545602439143442">"Anulați fixarea"</string>
<string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 408d4431a8c9..85cbdc4a943d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Идентификация абонента по умолчанию не запрещена. След. вызов: разрешена"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Услуга не предоставляется."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Невозможно изменить параметр идентификатора вызывающего абонента."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ограничения доступа изменены"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Служба данных заблокирована."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Служба экстренной помощи заблокирована."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Служба передачи голосовых сообщений заблокирована."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Сбросить и перезапустить"</string>
<string name="aerr_report" msgid="5371800241488400617">"Отправить отзыв"</string>
<string name="aerr_close" msgid="2991640326563991340">"Закрыть"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Скрыть"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Отключить до перезагрузки устройства"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Подождать"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Закрыть приложение"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Нажмите, чтобы настроить."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Нажмите, чтобы отключить отладку по USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Отправить администратору информацию об ошибке?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Ваш администратор запросил информацию об ошибке. Эти данные помогут устранить неполадку."</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Разрешить доступ к информации об ошибке?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Отправка отчета об ошибке"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Администратор запросил отчет об ошибке, чтобы устранить неполадку. Он может получить доступ к приложениям и данным. Возможно временное снижение скорости работы вашего устройства."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Администратор запросил отчет об ошибке, чтобы устранить неполадку. Он может получить доступ к приложениям и данным."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Скорость работы устройства может быть временно снижена."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИНЯТЬ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТКЛОНИТЬ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Подождите…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Нажмите, чтобы отменить"</string>
<string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Выбрать раскладку"</string>
<string name="show_ime" msgid="2506087537466597099">"Показывать на экране, когда физическая клавиатура включена"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-код для отключения"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запрашивать графический ключ для отключения блокировки"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запрашивать пароль для отключения блокировки"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Размер окна нельзя изменить. Прокрутите страницу двумя пальцами."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Приложение не поддерживает разделение экрана."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Приложение не поддерживает разделение экрана."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Установлено администратором"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Обновлено администратором"</string>
@@ -1542,7 +1542,7 @@
<item quantity="other">На %d часа</item>
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
- <string name="zen_mode_alarm" msgid="9128205721301330797">"До следующего будильника в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (будильник)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Пока вы не отключите режим \"Не беспокоить\""</string>
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
@@ -1575,12 +1575,11 @@
<item quantity="many">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="other">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Другое"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Вы определяете важность этих уведомлений."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Вы определяете важность этих уведомлений."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Важное (люди)"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать пользователя для аккаунта <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя для аккаунта <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь c таким аккаунтом уже есть)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Языковые настройки"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Добавьте язык"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Региональные настройки"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Рекомендуемые"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Пакет заблокирован администратором компании \"%1$s\". Обратитесь к нему за дополнительной информацией."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Новые сообщения"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Чтобы просмотреть, откройте приложение для обмена SMS"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Некоторые функции недоступны"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Нажмите, чтобы продолжить"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Профиль заблокирован"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Некоторые функции недоступны"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Нажмите для разблокировки"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Пользов. данные заблокированы"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Рабочий профиль заблокирован"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Нажмите, чтобы разблокировать раб. профиль"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Подключено к <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Нажмите, чтобы просмотреть файлы"</string>
<string name="pin_target" msgid="3052256031352291362">"Закрепить"</string>
<string name="unpin_target" msgid="3556545602439143442">"Открепить"</string>
<string name="app_info" msgid="6856026610594615344">"О приложении"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 9bbab5609c5a..f37eb588c89e 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"අමතන්නාගේ ID සුපුරුදු අනුව සීමා වී නැත. මීළඟ ඇමතුම: සීමා කර ඇත"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"සේවාවන් සපයා නැත."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"අමතන්නාගේ ID සැකසීම ඔබට වෙනස්කල නොහැක."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"සීමිත ප්‍රවේශය වෙනස් කෙරිණි"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"දත්ත සේවාව අවහිර කර ඇත."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"හදිසි සේවාව අවහිර කර ඇත."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"හඬ සේවාව බාධා කර ඇත."</string>
@@ -919,7 +918,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"යෙදුම නැවත සකසා නැවත ආරම්භ කරන්න"</string>
<string name="aerr_report" msgid="5371800241488400617">"ප්‍රතිපෝෂණය යවන්න"</string>
<string name="aerr_close" msgid="2991640326563991340">"වසන්න"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"නිහඬ කරන්න"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"උපාංගය නැවත ආරම්භ වන තෙක් නිහඬ කරන්න"</string>
<string name="aerr_wait" msgid="3199956902437040261">"රැඳී සිටින්න"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"යෙදුම වසන්න"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1055,12 +1054,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"වඩා වැඩි විකල්ප සඳහා ස්පර්ශ කරන්න."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB නිදොස්කරණය සම්බන්ධිතයි"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB නිදොස්කරණය අබල කිරීමට ස්පර්ශ කරන්න."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"පරිපාලක සමඟ දෝෂ වාර්තාවක් බෙදා ගන්නද?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"දෝෂ වාර්තාව බෙදා ගන්නද?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"දෝෂ වාර්තාවක් බෙදා ගනිමින්..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"මෙම උපාංගය දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත. යෙදුම් සහ දත්ත බෙදා ගත හැකි අතර ඔබේ උපාංගය තාවකාලිකව මන්දගාමී විය හැකිය."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"මෙම උපාංගය දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත. යෙදුම් සහ දත්ත බෙදා ගත හැකිය."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"මෙය ඔබේ උපාංගය තාවකාලිකව මන්දගාමී කළ හැකිය"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"පිළිගන්න"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ප්‍රතික්ෂේප කරන්න"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"දෝෂ වාර්තාවක් ගනිමින්…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"අවලංගු කිරීමට ස්පර්ශ කරන්න"</string>
<string name="select_input_method" msgid="8547250819326693584">"යතුරු පුවරු වෙනස් කිරීම"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"යතුරු පුවරු තෝරන්න"</string>
<string name="show_ime" msgid="2506087537466597099">"භෞතික යතුරු පුවරුව සක්‍රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
@@ -1469,7 +1469,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ගැලවීමට පෙර අගුළු අරින රටාව සඳහා අසන්න"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ගැලවීමට පෙර මුරපදය විමසන්න"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"යෙදුම ප්‍රතිප්‍රමාණ කළ හැකි නොවේ, එය ඇඟිලි දෙකකින් අනුචලනය කරන්න."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"යෙදුම බෙදුම්-තිරය සමග ක්‍රියා නොකළ හැකිය."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"ඔබගේ පරිපාලක විසින් ස්ථාපනය කරන ලද"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"ඔබගේ පරිපාලක විසින් යාවත්කාලීන කරන ලදී"</string>
@@ -1539,12 +1539,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"විවිධාකාර"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
<string name="importance_from_person" msgid="9160133597262938296">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"භාෂා මනාප"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"භාෂාවක් එක් කරන්න"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ප්‍රදේශ මනාපය"</string>
<string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"යෝජිත"</string>
@@ -1557,12 +1556,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s පරිපාලක විසින් අබල කරන ලදී. තව දැන ගැනීමට ඔවුන් අමතන්න."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"ඔබට නව පණිවිඩ තිබේ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"බැලීමට විවෘත SMS යෙදුම විවෘත කරන්න"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"සමහර කාර්ය නොතිබිය හැකිය"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"දිගටම කරගෙන යාමට ස්පර්ශ කරන්න"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"පරිශීලක පැතිකඩ අගුලු දමා ඇත"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"ඇතැම් ක්‍රියාකාරිත්ව සීමිත විය හැකිය"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"අගුලු හැරීමට තට්ටු කරන්න"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"පරිශීලක දත්ත අගුලු දමා ඇත"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"කාර්යාල පැතිකඩ අගුලු දමා ඇත"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"කාර්යාල පැතිකඩ අගුලු හැරීමට තට්ටු කරන්න"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> වෙත සම්බන්ධ විය"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ගොනු බැලීමට තට්ටු කරන්න"</string>
<string name="pin_target" msgid="3052256031352291362">"අමුණන්න"</string>
<string name="unpin_target" msgid="3556545602439143442">"ගලවන්න"</string>
<string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4369374fc85b..ddb162a54233 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"V predvolenom nastavení nie je identifikácia volajúceho obmedzená. Ďalší hovor: Bez obmedzenia"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Služba nie je poskytovaná."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Nemôžete meniť nastavenia identifikácie volajúceho."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Obmedzený prístup bol zmenený"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Údajová služba je zablokovaná."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Tiesňová služba je zablokovaná."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Hlasová služba je zablokovaná."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Resetovať a reštartovať aplikáciu"</string>
<string name="aerr_report" msgid="5371800241488400617">"Odoslať spätnú väzbu"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zavrieť"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Ignorovať"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorovať do reštartu zariadenia"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Čakať"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zavrieť aplikáciu"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Ďalšie možnosti zobrazíte klepnutím."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Klepnutím zakážete ladenie cez USB"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Zdieľať hlásenie chyby so správcom?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Správca IT si vyžiadal hlásenie chyby, aby mohol problém vyriešiť"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Správca IT si vyžiadal hlásenie chyby, aby mohol vyriešiť problém na tomto zariadení. Aplikácie a dáta môžu byť zdieľané. Môže to dočasne spomaliť vaše zariadenie."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Správca IT si vyžiadal hlásenie chyby, aby mohol vyriešiť problém na tomto zariadení. Aplikácie a dáta môžu byť zdieľané."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Môže to dočasne spomaliť vaše zariadenie."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIJAŤ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMIETNUŤ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Vytvára sa hlásenie chyby…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Dotykom zrušíte"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmeniť klávesnicu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vybrať klávesnicu"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pred uvoľnením požiadať o bezpečnostný vzor"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pred uvoľnením požiadať o heslo"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Veľkosť aplikácie nie je možné zmeniť. Zobrazenie môžete posúvať dvoma prstami."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikácia nemusí fungovať so zapnutou rozdelenou obrazovkou."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Inštalovaný správcom"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizované správcom"</string>
@@ -1575,12 +1575,11 @@
<item quantity="other">Vybrané: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Vybrané: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Rôzne"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Nastavili ste dôležitosť týchto upozornení."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Nastavili ste dôležitosť týchto upozornení."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Jazykové predvoľby"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Pridať jazyk"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferovaný región"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Zakázané správcom %1$s. Ak chcete získať ďalšie informácie, kontaktujte ho."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Máte nové správy."</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Otvorte aplikáciu pre SMS a zobrazte správu"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Niektoré funkcie nemusia byť dostupné"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Pokračujte klepnutím"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil používateľa je zamknutý"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Niektoré funkcie môžu byť obmedzené"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Odomknite klepnutím"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Údaje používateľa sú uzamknuté"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Pracovný profil je uzamknutý"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Profil odomknete klepnutím"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Pripojené k zariadeniu <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Klepnutím zobrazíte súbory"</string>
<string name="pin_target" msgid="3052256031352291362">"Pripnúť"</string>
<string name="unpin_target" msgid="3556545602439143442">"Uvoľniť"</string>
<string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 2451e3d6b136..47330fb806d4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID klicatelja je ponastavljen na neomejeno. Naslednji klic: ni omejeno"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Storitev ni nastavljena in omogočena."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Ne morete spremeniti nastavitve ID-ja klicatelja."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Omejen dostop je spremenjen"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Podatkovna storitev je blokirana."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Klic v sili je blokiran."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna storitev je blokirana."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Ponastavitev in vnovični zagon aplikacije"</string>
<string name="aerr_report" msgid="5371800241488400617">"Pošlji povratne informacije"</string>
<string name="aerr_close" msgid="2991640326563991340">"Zapri"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Prezri"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Prezri do vnovičnega zagona naprave"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Počakajte"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Zapri aplikacijo"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Za več možnosti se dotaknite."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje in odpravljanje napak USB je povezano"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Želite skrbniku poslati poročilo o napakah?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Skrbnik IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Skrbnik za IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo in delovanje naprave bo morda začasno upočasnjeno."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Skrbnik za IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"To bo morda začasno upočasnilo delovanje naprave"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SPREJMEM"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"NE SPREJMEM"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Zajemanje poročila o napakah …"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Če želite prekiniti, se dotaknite"</string>
<string name="select_input_method" msgid="8547250819326693584">"Sprememba tipkovnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izbira tipkovnic"</string>
<string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Zahtevaj PIN pred odpenjanjem"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pred odpenjanjem vprašaj za geslo"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Velikosti aplikacije ni mogoče spremeniti. Po njej se pomikajte z dvema prstoma."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Namestil skrbnik"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Posodobil skrbnik"</string>
@@ -1575,12 +1575,11 @@
<item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> izbrani</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> izbranih</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Vi določite raven pomembnosti teh obvestil."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Vi določite raven pomembnosti teh obvestil."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Pomembno zaradi udeleženih ljudi."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Dovolite, da aplikacija <xliff:g id="APP">%1$s</xliff:g> ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Dovolite aplikaciji <xliff:g id="APP">%1$s</xliff:g>, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Nastavitev jezika"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dodajanje jezika"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Nastavitev območja"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Predlagano"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Onemogočil skrbnik %1$s. Za več informacij se obrnite nanj."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Imate nova sporočila."</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Za ogled odprite aplikacijo za SMS-je"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Nek. funk. morda niso na voljo"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Dotaknite se za nadaljevanje"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profil uporabnika zaklenjen"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Nekatere funkcije bodo omejene"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Dotaknite se, da odklenete"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Uporabniški podatki zaklenjeni"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Delovni profil je zaklenjen"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Dotaknite se za odkl. del. pr."</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Vzpostavljena povezava z napravo <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dotaknite se, če si želite ogledati datoteke"</string>
<string name="pin_target" msgid="3052256031352291362">"Pripenjanje"</string>
<string name="unpin_target" msgid="3556545602439143442">"Odpenjanje"</string>
<string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 70164bebd0ec..db46b89bc3be 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ja e telefonuesit kalon me paracaktim në listën e të telefonuesve të pakufizuar. Telefonata e radhës: e pakufizuar!"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Shërbimi nuk është përgatitur."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Nuk mund ta ndryshosh cilësimin e ID-së së telefonuesit."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Qasja e kufizuar u ndryshua"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Shërbimi i të dhënave është i bllokuar."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Shërbimi i urgjencës është i bllokuar."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Shërbimi me zë është bllokuar."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Rivendos dhe rinis aplikacionin"</string>
<string name="aerr_report" msgid="5371800241488400617">"Dërgo komentin"</string>
<string name="aerr_close" msgid="2991640326563991340">"Mbyll"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Çaktivizo audion"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Vendose në heshtje deri kur të riniset pajisja"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Prit!"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Mbyll aplikacionin"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Prek 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="1016654627626476142">"Prek për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ndaje raportin e defekteve në kod me administratorin?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve. Aplikacioni dhe të dhënat mund të ndahen dhe kjo mund të ngadalësojë përkohësisht pajisjen tënde."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve. Aplikacioni dhe të dhënat mund të ndahen."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Kjo mund të ngadalësojë përkohësisht pajisjen tënde"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRANO"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZO"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Po merret raporti i defekteve në kod…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Prek për ta anuluar"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ndërro tastierë"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Zgjidh tastierat"</string>
<string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Zhgozhdimi kërkon PIN-in"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Kërko model shkyçjeje para heqjes së gozhdimit"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Kërko fjalëkalim para heqjes nga gozhdimi."</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Përmasa e apl. nuk mund të ndryshohet, lëvize atë me të dy gishtat."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"U instalua nga administratori yt"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Përditësuar nga administratori"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> të zgjedhura</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Të ndryshme"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Dëshiron të lejosh <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Dëshiron të lejosh <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Preferenca për gjuhën"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Shto një gjuhë"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Preferenca e rajonit"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugjeruar"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Çaktivizuar nga administratori i %1$s. Kontaktoje për të mësuar më shumë."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Ke mesazhe të reja"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Hap aplikacionin SMS për ta parë"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Disa funksione mund të mos jenë të disponueshme"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Preke për të vazhduar"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Profili i përdoruesit i kyçur"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Disa funksione mund të jenë të kufizuara"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Trokit për të shkyçur"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Të dhënat e përdoruesit të kyçura"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profili i punës është i kyçur"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Trokit për ta shkyçur profilin e punës"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"U lidh me <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Trokit për të parë skedarët"</string>
<string name="pin_target" msgid="3052256031352291362">"Gozhdo"</string>
<string name="unpin_target" msgid="3556545602439143442">"Zhgozhdo"</string>
<string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a62d7d630b43..d1ac852ed04a 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -89,7 +89,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ИД позиваоца подразумевано није ограничен. Следећи позив: Није ограничен."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Услуга није добављена."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Не можете да промените подешавање ИД-а корисника."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ограничени приступ је промењен"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Услуга за податке је блокирана."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Услуга за хитне случајеве је блокирана."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Гласовна услуга је блокирана."</string>
@@ -923,7 +922,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Ресетуј и поново покрени апликацију"</string>
<string name="aerr_report" msgid="5371800241488400617">"Пошаљите повратне информације"</string>
<string name="aerr_close" msgid="2991640326563991340">"Затвори"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Игнориши"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Игнориши док се уређај не покрене поново"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Чекај"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Затвори апликацију"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1061,12 +1060,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Додирните за још опција."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Желите ли да делите извештај о грешци са администратором?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Желите ли да поделите извештај о грешци?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Дели се извештај о грешци…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема у вези са овим уређајем. Апликације и подаци могу да се деле, а уређај ће се привремено успорити."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема у вези са овим уређајем. Апликације и подаци могу да се деле."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Ово ће привремено успорити уређај"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИХВАТИ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Извештај о грешци се генерише…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Додирните да бисте отказали"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Изаберите тастатуре"</string>
<string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
@@ -1477,7 +1477,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тражи PIN пре откачињања"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тражи шаблон за откључавање пре откачињања"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тражи лозинку пре откачињања"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Величина апликације не може да се мења. Померајте је помоћу два прста."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Апликација можда неће функционисати са подељеним екраном."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Апликација не подржава подељени екран."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Инсталирао је ваш администратор"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирао је администратор"</string>
@@ -1556,12 +1556,11 @@
<item quantity="few">Изабране су <xliff:g id="COUNT_1">%1$d</xliff:g> ставке</item>
<item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ви подешавате важност ових обавештења."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ви подешавате важност ових обавештења."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Ово је важно због људи који учествују."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Желите ли да дозволите апликацији <xliff:g id="APP">%1$s</xliff:g> да направи новог корисника за <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Желите ли да дозволите апликацији <xliff:g id="APP">%1$s</xliff:g> да направи новог корисника за <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са овим налогом већ постоји)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Подешавање језика"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Додајте језик"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Подешавање региона"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
@@ -1574,12 +1573,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Онемогућио је администратор компаније %1$s. Контактирајте га да бисте сазнали више."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Имате нове поруке"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Отворите апликацију за SMS да бисте прегледали"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Неке функције нису доступне"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Додирните да бисте наставили"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Профил корисника је закључан"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Неке функције су можда ограничене"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Додирните да бисте откључали"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Подаци корисника су закључани"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Профил за Work је закључан"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Додиром откљ. профил за Work"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Повезано је са производом <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Додирните за преглед датотека"</string>
<string name="pin_target" msgid="3052256031352291362">"Закачи"</string>
<string name="unpin_target" msgid="3556545602439143442">"Откачи"</string>
<string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f90f95c91261..ab61097ee267 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjänsten är inte etablerad."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Det går inte att ändra inställningen för nummerpresentatör."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begränsad åtkomst har ändrats"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Datatjänsten är blockerad."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Räddningstjänsten är blockerad."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Rösttjänsten är blockerad."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Återställ och starta om appen"</string>
<string name="aerr_report" msgid="5371800241488400617">"Skicka feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Stäng"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Dölj"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Ignorera tills enheten har startat om"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Vänta"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Stäng appen"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Visa fler alternativ genom att trycka."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tryck om du vill inaktivera USB-felsökning."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vill du dela en felrapport med administratören?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-administratören har bett om en felrapport som hjälp vid felsökningen."</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"IT-administratören har bett om en felrapport som hjälp vid felsökningen av den här enheten. Appar och data kan komma att delas. Detta kan tillfälligt göra enheten långsammare."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"IT-administratören har bett om en felrapport som hjälp vid felsökningen av den här enheten. Appar och data kan komma att delas."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Detta kan tillfälligt göra enheten långsammare"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODKÄNN"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVVISA"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Felrapporten överförs …"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tryck här om du vill avbryta"</string>
<string name="select_input_method" msgid="8547250819326693584">"Byt tangentbord"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Välj tangentbord"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Be om upplåsningsmönster innan skärmen slutar fästas"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Be om lösenord innan skärmen slutar fästas"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Det går inte att ändra appens storlek. Rulla med två fingrar."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen kanske inte fungerar med delad skärm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen har inte stöd för delad skärm."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Paketet har installerats av administratören"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Uppdaterat av administratören"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> har valts</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Du anger hur viktiga aviseringarna är."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Du anger hur viktiga aviseringarna är."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Detta är viktigt på grund av personerna som deltar."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Språkinställning"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Lägg till ett språk"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Regionsinställningar"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Förslag"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Inaktiverat av administratören för %1$s. Kontakta administratören om du vill veta mer."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nya meddelanden"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Öppna sms-appen och visa meddelandet"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Vissa funktioner är inte tillgängliga"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Tryck om du vill fortsätta"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Användarprofilen är låst"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Vissa funktioner är begränsade"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck om du vill låsa upp"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Användaruppgifterna är låsta"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Jobbprofilen är låst"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Tryck och lås upp jobbprofilen"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Ansluten till <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Filerna visas om du trycker här"</string>
<string name="pin_target" msgid="3052256031352291362">"Fäst"</string>
<string name="unpin_target" msgid="3556545602439143442">"Lossa"</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 856484ca0bc0..271c48d61c4b 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Chaguo-msingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Haijazuiliwa"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Huduma haitathminiwi."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Hauwezi kubadilisha mpangilio wa kitambulisho cha anayepiga."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ufikiaji uliozuiwa umebadilishwa"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Huduma ya data imezuiwa."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Huduma ya dharura imezuiwa."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Huduma ya sauti imezuiwa."</string>
@@ -919,7 +918,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Weka na uanzishe upya programu"</string>
<string name="aerr_report" msgid="5371800241488400617">"Tuma maoni yako"</string>
<string name="aerr_close" msgid="2991640326563991340">"Funga"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Komesha"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Komesha hadi kifaa kianze upya"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Subiri"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Funga programu"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1055,12 +1054,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Gusa kwa chaguo zaidi."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili uzime utatuaji wa USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ungependa kushiriki ripoti ya hitilafu na msimamizi?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Msimamizi wako wa IT ameomba ripoti ya hitilafu ili kusaidia katika utatuzi"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Msimamizi wako wa Teknolojia ya Habari ameomba ripoti ya hitilafu ili kusaidia katika utatuzi wa kifaa hiki. Huenda hatua hii ikasababisha programu na data kushirikiwa na kupunguza kasi ya kifaa chako kwa muda."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Msimamizi wako wa TEHAMA ameomba ripoti ya hitilafu ili kusaidia katika utatuzi wa hitilafu kwenye kifaa hiki. Programu na data zinaweza kushirikiwa."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Hatua hii inaweza kupunguza kasi ya kifaa chako kwa muda"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KUBALI"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KATAA"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Inatayarisha ripoti ya hitilafu…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Gusa ili ufute"</string>
<string name="select_input_method" msgid="8547250819326693584">"Badilisha kibodi"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Chagua kibodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Iweke kwenye skrini wakati kibodi inapotumika"</string>
@@ -1469,7 +1469,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Omba PIN kabla hujabandua"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Omba mchoro wa kufungua kabla hujabandua"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Omba nenosiri kabla hujabandua"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Programu haiwezi kurekebishwa ukubwa, sogeza kwa kutumia vidole viwili."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Kilisakinishwa na msimamizi wako"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Kimesasiswa na msimamizi wako"</string>
@@ -1539,12 +1539,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> vimechaguliwa</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kimechaguliwa</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Anuwai"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Uliweka umuhimu wa arifa hizi."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Uliweka mipangilio ya umuhimu wa arifa hizi."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iunde Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iunde Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, akaunti hii tayari ina Mtumiaji)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Lugha ninayopendelea"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Ongeza lugha"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Mapendeleo ya eneo"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Inayopendekezwa"</string>
@@ -1557,12 +1556,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Imezimwa na msimamizi wa %1$s. Wasiliana naye ili upate maelezo zaidi."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Una ujumbe mpya"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Fungua programu ya SMS ili uweze kuangalia"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Huenda baadhi ya vipengele visipatikane"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Gusa ili uendelee"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Wasifu wa mtumiaji umefungwa"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Huenda baadhi ya utendaji ukawa vikwazo"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Gonga ili ufungue"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Data ya mtumiaji imefungwa"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Wasifu wa kazini umefungwa"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Gonga ili ufungue wasifu wa kazini"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Imeunganishwa na <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Gonga ili uangalie faili"</string>
<string name="pin_target" msgid="3052256031352291362">"Bandika"</string>
<string name="unpin_target" msgid="3556545602439143442">"Bandua"</string>
<string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index d7e96e897f5b..f49c1b508ecc 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"அழைப்பாளர் ஐடி ஆனது வரையறுக்கப்படவில்லை என்பதற்கு இயல்பாக அமைக்கப்பட்டது. அடுத்த அழைப்பு: வரையறுக்கப்படவில்லை"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"சேவை ஒதுக்கப்படவில்லை."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"அழைப்பாளர் ஐடி அமைப்பை மாற்ற முடியாது."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"வரையறுக்கப்பட்ட அணுகல் மாற்றப்பட்டது"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"தரவு சேவை தடைசெய்யப்பட்டுள்ளது."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"அவசர சேவை தடைசெய்யப்பட்டுள்ளது."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"குரல் சேவை தடைசெய்யப்பட்டுள்ளது."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"பயன்பாட்டை மீட்டமைத்து மீண்டும் தொடங்கு"</string>
<string name="aerr_report" msgid="5371800241488400617">"கருத்து தெரிவி"</string>
<string name="aerr_close" msgid="2991640326563991340">"மூடு"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"முடக்கு"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"சாதனம் மீண்டும் தொடங்கும் வரை முடக்கு"</string>
<string name="aerr_wait" msgid="3199956902437040261">"காத்திரு"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"பயன்பாட்டை மூடு"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1031,7 +1030,7 @@
<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">"புதிய சிம் சரியாக இயங்குவதற்கு, நீங்கள் பயன்படுத்தும் மொபைல் நிறுவனத்திலிருந்து பயன்பாட்டை நிறுவி, திறக்கவும்."</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">"புதிய சிம் செருகப்பட்டது"</string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"கூடுதல் விருப்பங்களுக்காகத் தொடவும்."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB பிழைத்திருத்தத்தை முடக்க, தொடவும்."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"பிழை அறிக்கையை நிர்வாகியுடன் பகிரவா?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார்"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"பிழை அறிக்கையைப் பகிரவா?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"பிழை அறிக்கையைப் பகிர்கிறது…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"இந்தச் சாதனத்தின் பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார். பயன்பாடுகளும் தரவும் பகிரப்படலாம். தற்காலிகமாக சாதனத்தின் வேகம் குறையலாம்."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"இந்தச் சாதனத்தின் பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார். பயன்பாடுகளும் தரவும் பகிரப்படலாம்."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"இது தற்காலிகமாக சாதனத்தின் வேகத்தைக் குறைக்கலாம்"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"சரி"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"வேண்டாம்"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"பிழை அறிக்கையை எடுக்கிறது…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ரத்துசெய்ய, தொடவும்"</string>
<string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"விசைப்பலகைகளைத் தேர்வுசெய்க"</string>
<string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"அகற்றும் முன் திறத்தல் வடிவத்தைக் கேள்"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"அகற்றும் முன் கடவுச்சொல்லைக் கேள்"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"பயன்பாட்டின் அளவை மாற்ற முடியாது. இருவிரல்களைப் பயன்படுத்தி, அதை உருட்டவும்."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"திரைப் பிரிப்பில் பயன்பாடு வேலைசெய்யாமல் போகக்கூடும்."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"திரையைப் பிரிப்பதைப் பயன்பாடு ஆதரிக்கவில்லை."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"நிர்வாகி நிறுவினார்"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டன</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டது</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"இதர அமைப்பு"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g>ஐ அனுமதிக்கவா?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (இந்தக் கணக்கில் ஏற்கனவே ஒரு பயனர் உள்ளார்) மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g>ஐ அனுமதிக்கவா?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"மொழி விருப்பம்"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"மொழியைச் சேர்"</string>
<string name="country_selection_title" msgid="2954859441620215513">"மண்டல விருப்பம்"</string>
<string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"பரிந்துரைகள்"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s நிர்வாகி முடக்கியுள்ளார். மேலும் அறிய, அவரைத் தொடர்புகொள்ளவும்."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"புதிய செய்திகள் வந்துள்ளன"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"பார்க்க, SMS பயன்பாட்டைத் திறக்கவும்"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"சில செயல்பாடு கிடைக்காமல் போகலாம்"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"தொடர, தொடவும்"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"பயனர் சுயவிவரம் பூட்டப்பட்டது"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"சில செயல்பாடு வரம்பிடப்பட்டிருக்கலாம்"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"திறக்க, தட்டவும்"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"பயனர் தரவு பூட்டப்பட்டது"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"பணி சுயவிவரம் பூட்டியுள்ளது"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"பணி சுயவிவரத்தை திறக்க, தட்டுக"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> உடன் இணைக்கப்பட்டது"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"கோப்புகளைப் பார்க்க, தட்டவும்"</string>
<string name="pin_target" msgid="3052256031352291362">"பின் செய்"</string>
<string name="unpin_target" msgid="3556545602439143442">"பின்னை அகற்று"</string>
<string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 6d42955553d5..8047621e7b81 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"కాలర్ ID డిఫాల్ట్‌గా అపరిమితానికి ఉంటుంది. తదుపరి కాల్: అపరిమితం"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"సేవ కేటాయించబడలేదు."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"మీరు కాలర్ ID సెట్టింగ్‌ను మార్చలేరు."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"పరిమితం చేయబడిన ప్రాప్యత మార్చబడింది"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"డేటా సేవ బ్లాక్ చేయబడింది."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"అత్యవసర సేవ బ్లాక్ చేయబడింది."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"వాయిస్ సేవ బ్లాక్ చేయబడింది."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"రీసెట్ చేసి, అనువర్తనాన్ని పునఃప్రారంభించు"</string>
<string name="aerr_report" msgid="5371800241488400617">"అభిప్రాయాన్ని పంపు"</string>
<string name="aerr_close" msgid="2991640326563991340">"మూసివేయి"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"మ్యూట్ చేయి"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"పరికరం పునఃప్రారంభమయ్యే వరకు మ్యూట్ చేయి"</string>
<string name="aerr_wait" msgid="3199956902437040261">"వేచి ఉండండి"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"అనువర్తనాన్ని మూసివేయి"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"మరిన్ని ఎంపికల కోసం తాకండి."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB డీబగ్గింగ్‌ను నిలిపివేయడానికి తాకండి."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"బగ్ నివేదికను నిర్వాహకులకు భాగస్వామ్యం చేయాలా?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"మీ ఐటి నిర్వాహకులు సమస్య పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"మీ ఐటి నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు మరియు మీ పరికరం పనితీరు తాత్కాలికంగా నెమ్మదించవచ్చు."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"మీ ఐటి నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"దీని వల్ల మీ పరికరం పనితీరు తాత్కాలికంగా నెమ్మదించవచ్చు"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ఆమోదిస్తున్నాను"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"తిరస్కరిస్తున్నాను"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"బగ్ నివేదికను తీస్తోంది…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"రద్దు చేయడానికి తాకండి"</string>
<string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్‌ను మార్చు"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"కీబోర్డ్‌లను ఎంచుకోండి"</string>
<string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్‌పై ఉంచుతుంది"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ నమూనా కోసం అడుగు"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"అనువర్తన పరిమాణాన్ని మార్చడం సాధ్యపడదు, రెండు వేళ్లతో దీన్ని స్క్రోల్ చేయండి."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"స్క్రీన్ విభజనతో అనువర్తనం పని చేయకపోవచ్చు."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేసారు"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"మీ నిర్వాహకుడు నవీకరించారు"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఎంచుకోబడ్డాయి</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"ఇతరాలు"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించాలా ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించాలా?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"భాష ప్రాధాన్యత"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"భాషను జోడించండి"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ప్రాంతం ప్రాధాన్యత"</string>
<string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$sని నిర్వాహకుడు నిలిపివేసారు. మరింత తెలుసుకోవడానికి వారిని సంప్రదించండి."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"వీక్షించడానికి SMS అనువర్తనాన్ని తెరవండి"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"కొన్ని విధులు ఉండకపోవచ్చు"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"కొనసాగడానికి తాకండి"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"వినియోగ. ప్రొఫైల్ లాక్ అయింది"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"కొంత కార్యాచరణ పరిమితం కావచ్చు"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"అన్‌లాక్ చేయడానికి నొక్కండి"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"వినియోగదారు డేటా లాక్ అయ్యింది"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"కార్యాలయ ప్రొఫైల్ లాక్ అయింది"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"కార్యాలయ ప్రొఫైల్ అన్‌లాక్ చేయుటకు నొక్కండి"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ఫైల్‌లను వీక్షించడానికి నొక్కండి"</string>
<string name="pin_target" msgid="3052256031352291362">"పిన్ చేయి"</string>
<string name="unpin_target" msgid="3556545602439143442">"అన్‌‌పిన్‌ ‌చేయి"</string>
<string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 0f98cfba478f..ae19150de3c0 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -29,6 +29,9 @@
<!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
is located in center. -->
- <string translatable="false" name="config_centeredPictureInPictureBounds">"600 331 1320 749"</string>
+ <string translatable="false" name="config_centeredPictureInPictureBounds">"596 280 1324 690"</string>
+ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+ when the PIP is shown with Recents. -->
+ <string translatable="false" name="config_pictureInPictureBoundsInRecents">"1480 123 1760 303"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 15cd2fff50dd..114b31ba103d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"หมายเลขผู้โทรได้รับการตั้งค่าเริ่มต้นเป็นไม่จำกัด การโทรครั้งต่อไป: ไม่จำกัด"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"ไม่มีการนำเสนอบริการ"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"คุณไม่สามารถเปลี่ยนการตั้งค่าหมายเลขผู้โทร"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"เปลี่ยนแปลงการเข้าถึงอย่างจำกัดแล้ว"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"บริการข้อมูลถูกปิดกั้น"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"บริการฉุกเฉินถูกปิดกั้น"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"บริการเสียงถูกปิดกั้น"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"รีเซ็ตแอปและเปิดใหม่"</string>
<string name="aerr_report" msgid="5371800241488400617">"ส่งความคิดเห็น"</string>
<string name="aerr_close" msgid="2991640326563991340">"ปิด"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"ปิด"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ปิดการแจ้งเตือนจนกว่าอุปกรณ์จะรีสตาร์ท"</string>
<string name="aerr_wait" msgid="3199956902437040261">"รอ"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ปิดแอป"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ต้องการแชร์รายงานข้อบกพร่องกับผู้ดูแลระบบไหม"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ไขปัญหา"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"แชร์รายงานข้อบกพร่องไหม"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"กำลังแชร์รายงานข้อบกพร่อง…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ปัญหาอุปกรณ์นี้ อาจมีการแชร์แอปและข้อมูล ซึ่งอาจทำให้อุปกรณ์ทำงานช้าลงชั่วคราว"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ปัญหาอุปกรณ์นี้ อาจมีการแชร์แอปและข้อมูล"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"การดำเนินการนี้อาจทำให้อุปกรณ์ทำงานช้าลงชั่วคราว"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ยอมรับ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ปฏิเสธ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"กำลังสร้างรายงานข้อบกพร่อง…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"แตะเพื่อยกเลิก"</string>
<string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"เลือกแป้นพิมพ์"</string>
<string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ขอรูปแบบการปลดล็อกก่อนเลิกตรึง"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ขอรหัสผ่านก่อนเลิกตรึง"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"แอปไม่สามารถปรับขนาดได้ เลื่อนแอปด้วยนิ้ว 2 นิ้ว"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"แอปอาจใช้ไม่ได้กับโหมดแยกหน้าจอ"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"ติดตั้งโดยผู้ดูแลระบบของคุณ"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"อัปเดตโดยผู้ดูแลระบบ"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
<item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"เบ็ดเตล็ด"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
<string name="importance_from_person" msgid="9160133597262938296">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว) ไหม"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"ค่ากำหนดภาษา"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"เพิ่มภาษา"</string>
<string name="country_selection_title" msgid="2954859441620215513">"ค่ากำหนดภูมิภาค"</string>
<string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"แนะนำ"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"ผู้ดูแลระบบ %1$s ได้ปิดใช้แล้ว โปรดสอบถามข้อมูลเพิ่มเติมจากเขา"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"คุณมีข้อความใหม่"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"เปิดแอป SMS เพื่อดู"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"บางฟังก์ชันอาจไม่พร้อมใช้งาน"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"แตะเพื่อดำเนินการต่อ"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"โปรไฟล์ผู้ใช้ถูกล็อก"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"อาจมีข้อจำกัดในบางฟังก์ชัน"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"แตะเพื่อปลดล็อก"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ล็อกข้อมูลผู้ใช้อยู่"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"โปรไฟล์งานถูกล็อก"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"แตะเพื่อปลดล็อกโปรไฟล์งาน"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"เชื่อมต่อ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"แตะเพื่อดูไฟล์"</string>
<string name="pin_target" msgid="3052256031352291362">"ปักหมุด"</string>
<string name="unpin_target" msgid="3556545602439143442">"เลิกปักหมุด"</string>
<string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index af36041c0777..1e2a60697866 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Naka-default na hindi pinaghihigpitan ang Caller ID. Susunod na tawag: Hindi pinaghihigpitan"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Hindi naprobisyon ang serbisyo."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Hindi mo mababago ang setting ng caller ID."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Nabago ang pinaghihigpitang access"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Naka-block ang serbisyo ng data."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Naka-block ang pang-emergency na serbisyo."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Naka-block ang serbisyo ng voice."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"I-reset at i-restart ang app"</string>
<string name="aerr_report" msgid="5371800241488400617">"Magpadala ng feedback"</string>
<string name="aerr_close" msgid="2991640326563991340">"Isara"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"I-mute"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"I-mute hanggang sa mag-restart ang device"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Maghintay"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Isara ang app"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Pindutin 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="1016654627626476142">"Pindutin upang i-disable ang pagde-debug ng USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ibahagi ang ulat ng bug sa admin?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Humiling ang iyong admin ng IT ng ulat ng bug upang makatulong sa pag-troubleshoot"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Humiling ang iyong IT admin ng isang ulat ng bug upang makatulong sa pag-troubleshoot sa device na ito. Maaaring ibahagi ang mga app at data at maaaring pansamantalang bumagal ang iyong device."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Humiling ang iyong IT admin ng isang ulat ng bug upang makatulong sa pag-troubleshoot sa device na ito. Maaaring ibahagi ang mga app at data."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Maaaring pansamantalang bumagal ang iyong device dahil dito"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TANGGAPIN"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TANGGIHAN"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Kinukuha ang ulat ng bug…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Pindutin upang kanselahin"</string>
<string name="select_input_method" msgid="8547250819326693584">"Baguhin ang keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pumili ng mga keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Humingi ng password bago mag-unpin"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Hindi nare-resize ang app, mag-scroll dito gamit ang dalawang daliri."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Maaaring hindi gumana ang app sa split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Hindi sinusuportahan ng app ang split-screen."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Na-install ng iyong administrator"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Na-update ng iyong administrator"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Iba Pa"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ikaw ang magtatakda ng kahalagahan ng mga notification na ito."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ikaw ang magtatakda sa kahalagahan ng mga notification na ito."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Mahalaga ito dahil sa mga taong kasangkot."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Kagustuhan sa wika"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Magdagdag ng wika"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Kagustuhan sa rehiyon"</string>
<string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Iminumungkahi"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Na-disable ng administrator ng %1$s. Makipag-ugnayan sa administrator upang matuto nang higit pa."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Mayroon kang mga bagong mensahe"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Buksan ang SMS app upang tingnan"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Maaaring hindi available ang ilang function"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Pindutin upang magpatuloy"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Naka-lock ang profile ng user"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Limitado ilang functionality"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Mag-tap upang ma-unlock"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Naka-lock ang data ng user"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Profile sa trabaho, naka-lock"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"I-unlock ang profile sa trabaho, i-tap"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Nakakonekta sa <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"I-tap upang makita ang mga file"</string>
<string name="pin_target" msgid="3052256031352291362">"I-pin"</string>
<string name="unpin_target" msgid="3556545602439143442">"I-unpin"</string>
<string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 6a4c7dff7e07..ab0781b1e1ea 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Hizmet sağlanamadı."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Arayanın kimliği ayarını değiştiremezsiniz."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Kısıtlanmış erişim değiştirildi"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Veri hizmeti engellendi."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Acil durum hizmeti engellendi."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Ses hizmeti engellendi."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Uygulamayı sıfırla ve yeniden başlat"</string>
<string name="aerr_report" msgid="5371800241488400617">"Geri bildirim gönder"</string>
<string name="aerr_close" msgid="2991640326563991340">"Kapat"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Yok say"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Cihaz yeniden başlatılana kadar bir daha gösterme"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Bekle"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Uygulamayı kapat"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Daha fazla seçenek 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="1016654627626476142">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Hata raporu yöneticiyle paylaşılsın mı?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"BT yöneticiniz, sorun gidermeye yardımcı olması için bir hata raporu istedi"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"BT yöneticiniz, bu cihazda sorun gidermeye yardımcı olması için bir hata raporu istedi. Uygulamalar ve veriler paylaşılabilir. Bu durum, cihazınızı geçici olarak yavaşlatabilir."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"BT yöneticiniz, bu cihazda sorun gidermeye yardımcı olması için bir hata raporu istedi. Uygulamalar ve veriler paylaşılabilir."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Bu durum, cihazınızı geçici olarak yavaşlatabilir"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KABUL ET"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REDDET"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Hata raporu alınıyor…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"İptal etmek için dokunun"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klavyeyi değiştir"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klavyeyi seç"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Uygulama yeniden boyutlandırılamaz. İki parmağınızla kaydırın."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Uygulama bölünmüş ekranda çalışmayabilir."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Uygulama bölünmüş ekranı desteklemiyor."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Yöneticiniz tarafından yüklendi"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Yöneticiniz tarafından güncellendi"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe seçildi</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Çeşitli"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Bu bildirimlerin önem derecesini ayarladınız."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Bu bildirimlerin önem derecesini ayarladınız."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Dil tercihi"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dil ekleyin"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Bölge tercihi"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Önerilen"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s yöneticisi tarafından devre dışı bırakıldı. Daha fazla bilgi edinmek için kendileriyle iletişime geçin."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Yeni mesajlarınız var"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Görüntülemek için SMS uygulamasını açın"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Bazı işlevler kullanılamayabilir"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Devam etmek için dokunun"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Kullanıcı profili kilitli"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Bazı işlevler sınırlı olabilir"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Kilidi açmak için dokunun"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Kullanıcı verileri kilitlendi"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"İş profili kilitlendi"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"İş profilinin kilidini açmak için hafifçe dokunun"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> cihazına bağlandı"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dosyaları görüntülemek için hafifçe dokunun"</string>
<string name="pin_target" msgid="3052256031352291362">"Sabitle"</string>
<string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string>
<string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 3eb3fd837ee6..439d68f2ffb0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -90,7 +90,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Ідентиф. абонента за умовч. не обмеж. Наст. дзвінок: не обмежений"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Службу не ініціалізовано."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Ви не можете змінювати налаштування ідентифікатора абонента."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Обмежений доступ змінено"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Службу даних заблоковано."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Аварійну службу заблоковано."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Голосову службу заблоковано."</string>
@@ -929,7 +928,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Скинути та перезапустити додаток"</string>
<string name="aerr_report" msgid="5371800241488400617">"Надіслати відгук"</string>
<string name="aerr_close" msgid="2991640326563991340">"Закрити"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Вимкнути звук"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Вимкнути звук до перезавантаження пристрою"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Чекати"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Закрити додаток"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1069,12 +1068,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Торкніться, щоб побачити більше опцій."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Торкніться, щоб вимкнути налагодження USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Надіслати адміністратору повідомлення про помилку?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Ваш ІТ-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Надіслати звіт про помилку?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Ваш IT-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему з пристроєм. Він може отримати доступ до ваших додатків і даних. Це також може тимчасово сповільнити роботу вашого пристрою."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Ваш IT-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему з пристроєм. Він може отримати доступ до ваших додатків і даних."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Це може тимчасово сповільнити роботу вашого пристрою"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЙНЯТИ"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ВІДХИЛИТИ"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Створюється повідомлення про помилку…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Торкніться, щоб скасувати"</string>
<string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Вибрати клавіатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
@@ -1487,7 +1487,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN-код для відкріплення"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запитувати ключ розблокування перед відкріпленням"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запитувати пароль перед відкріпленням"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Розмір додатка не можна змінити. Прокручуйте його двома пальцями."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Додаток може не працювати в режимі розділеного екрана."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Додаток не підтримує розділення екрана."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Установив адміністратор"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Оновлено адміністратором"</string>
@@ -1575,12 +1575,11 @@
<item quantity="many">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="other">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Інше"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Ви вказуєте пріоритет цих сповіщень."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Ви вказуєте пріоритет цих сповіщень."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Важливе з огляду на учасників."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Вибір мови"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Додати мову"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Вибір регіону"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Пропозиції"</string>
@@ -1593,12 +1592,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Вимкнув адміністратор %1$s. Зв’яжіться з ним, щоб дізнатися більше."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"У вас є нові повідомлення"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Щоб переглянути, відкрийте додаток для SMS"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Деякі функції можуть бути недоступні"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Торкніться, щоб продовжити"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Профіль користувача блокується"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Деякі функції можуть не працювати"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Торкніться, щоб розблокувати"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Дані користувача заблоковано"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Робочий профіль заблоковано"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Торкніться, щоб розблокувати"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Під’єднано до пристрою <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Торкніться, щоб переглянути файли"</string>
<string name="pin_target" msgid="3052256031352291362">"Закріпити"</string>
<string name="unpin_target" msgid="3556545602439143442">"Відкріпити"</string>
<string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 48877b46b7c1..1bf224bc4e3d 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"‏کالر ID کی ڈیفالٹ ترتیب غیر محدود کردہ ہے۔ اگلی کال: غیر محدود کردہ"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"سروس فراہم نہیں کی گئی۔"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"‏آپ کالر ID کی ترتیبات تبدیل نہیں کر سکتے ہیں۔"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"محدود رسائی تبدیل ہو گئی"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"ڈیٹا سروس مسدود ہے۔"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"ہنگامی سروس مسدود ہے۔"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"صوتی سروس مسدود ہے۔"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"ایپ کو دوبارہ ترتیب دیں اور دوبارہ شروع کریں"</string>
<string name="aerr_report" msgid="5371800241488400617">"تاثرات بھیجیں"</string>
<string name="aerr_close" msgid="2991640326563991340">"بند کریں"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"خاموش کریں"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"آلہ دوبارہ اسٹارٹ ہونے تک خاموش رکھیں"</string>
<string name="aerr_wait" msgid="3199956902437040261">"انتظار کریں"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"ایپ بند کریں"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"مزید اختیارات کیلئے ٹچ کریں۔"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"‏USB ڈیبگ کرنا مربوط ہو گیا"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"‏USB ڈیبگنگ کو غیر فعال کرنے کیلئے ٹچ کریں۔"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"منتظم کے ساتھ بگ رپورٹ کا اشتراک کریں؟"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"‏آپ کے IT منتظم نے ٹربل شوٹ میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"بگ رپورٹ کا اشتراک کریں؟"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"بگ رپورٹ کا اشتراک ہو رہا ہے…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"‏آپ کے IT منتظم نے اس آلہ کا مسئلہ حل کرنے میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی ہے۔ ایپس اور ڈیٹا کا اشتراک ہو سکتا ہے اور آپ کا آلہ عارضی طور پر سست ہو سکتا ہے۔"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"‏آپ کے IT منتظم نے اس آلہ کا مسئلہ حل کرنے میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی ہے۔ ایپس اور ڈیٹا کا اشتراک ہو سکتا ہے۔"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"اس سے آپ کا آلہ عارضی طور پر سست ہو سکتا ہے"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول کریں"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"مسترد کریں"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"بگ رپورٹ لی جا رہی ہے…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"منسوخ کرنے کیلئے ٹچ کریں"</string>
<string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"کی بورڈز منتخب کریں"</string>
<string name="show_ime" msgid="2506087537466597099">"‏جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏پن ہٹانے سے پہلے PIN طلب کریں"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ایپ ری سائز ایبل نہیں ہے، اسے دو انگلیوں کے ساتھ سکرول کریں۔"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"ممکن ہے کہ ایپ سپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"آپ کے منتظم کی جانب سے انسٹال کر دیا گیا"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"آپ کے منتظم نے اپ ڈيٹ کر دیا"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> منتخب کردہ</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقات"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
<string name="importance_from_person" msgid="9160133597262938296">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں؟"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں (اس اکاؤنٹ کے ساتھ ایک صارف پہلے سے موجود ہے) ؟"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"زبان کی ترجیح"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ایک زبان شامل کریں"</string>
<string name="country_selection_title" msgid="2954859441620215513">"علاقہ کی ترجیح"</string>
<string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"تجویز کردہ"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"‏%1$s منتظم کی جانب سے غیر فعال کر دیا گیا۔ مزید جاننے کیلئے ان سے رابطہ کریں۔"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"آپ کے پاس نئے پیغامات ہیں"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"‏دیکھنے کیلئے SMS ایپ کھولیں"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"ممکن ہے کچھ فنکشز دستیاب نہ ہوں"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"جاری رکھنے کیلئے تھپتھپائیں"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"صارف پروفائل مقفل ہو گئی"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"کچھ فعالیت محدود ہو سکتی ہے"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"غیرمقفل کرنے کیلئے تھپتھپائیں"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"صارف کا ڈیٹا مقفل ہے"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"دفتری پروفائل مقفل ہے"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"دفتری پروفائل غیر مقفل کرنے کیلئے تھپتھپائیں"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> سے منسلک"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"فائلوں کو دیکھنے کیلئے تھپتھپائیں"</string>
<string name="pin_target" msgid="3052256031352291362">"پن کریں"</string>
<string name="unpin_target" msgid="3556545602439143442">"پن ہٹائیں"</string>
<string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index cc60c8c51350..d86203667a7b 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Qo‘ng‘iroq qiluvchi ma’lumotlari cheklanmagan. Keyingi qo‘ng‘iroq: cheklanmagan"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Xizmat ishalamaydi."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Qo‘ng‘iroq qiluvchining ID raqami sozlamasini o‘zgartirib bo‘lmaydi."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Cheklangan ruxsatlar o‘zgartirildi"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Ma’lumot xizmati bloklandi."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Favqulodda xizmati bloklandi."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Ovoz xizmati bloklandi."</string>
@@ -864,7 +863,7 @@
<string name="Midnight" msgid="5630806906897892201">"Yarim tun"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Barchasini tanlash"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Hammasini belgilash"</string>
<string name="cut" msgid="3092569408438626261">"Kesish"</string>
<string name="copy" msgid="2681946229533511987">"Nusxa olish"</string>
<string name="paste" msgid="5629880836805036433">"Joylash"</string>
@@ -894,7 +893,7 @@
<string name="capital_on" msgid="1544682755514494298">"I"</string>
<string name="capital_off" msgid="6815870386972805832">"O"</string>
<string name="whichApplication" msgid="4533185947064773386">"Ilovani tanlang"</string>
- <string name="whichApplicationNamed" msgid="8260158865936942783">"“%1$s” ilovasi yordamida bajarish"</string>
+ <string name="whichApplicationNamed" msgid="8260158865936942783">"“%1$s” bilan ochish"</string>
<string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"“%1$s” yordamida ochish"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Ilovani qayta tiklash va qayta ishga tushirish"</string>
<string name="aerr_report" msgid="5371800241488400617">"Fikr-mulohaza yuborish"</string>
<string name="aerr_close" msgid="2991640326563991340">"Yopish"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"E’tiborsiz qoldirish"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Qurilma o‘chib yonguncha e’tiborsiz qoldirish"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Kuting"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Ilovani yopish"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -977,12 +976,12 @@
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtonlar"</string>
<string name="ringtone_unknown" msgid="5477919988701784788">"Noma’lum rington"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
- <item quantity="other">Wi-Fi tarmoqlari mavjud emas</item>
- <item quantity="one">Wi-Fi tarmog‘i mavjud emas</item>
+ <item quantity="other">Wi-Fi tarmoqlari aniqlandi</item>
+ <item quantity="one">Wi-Fi tarmog‘i aniqlandi</item>
</plurals>
<plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
- <item quantity="other">Ochiq Wi-Fi tarmoqlari mavjud</item>
- <item quantity="one">Ochiq Wi-Fi tarmog‘i mavjud</item>
+ <item quantity="other">Ochiq Wi-Fi tarmoqlari aniqlandi</item>
+ <item quantity="one">Ochiq Wi-Fi tarmog‘i aniqlandi</item>
</plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi tarmoqqa kirish"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Tarmoqqa kirish"</string>
@@ -998,7 +997,7 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct’ni ishga tushirish. Bu Wi-Fi mijoz/ulanish nuqtasini o‘chiradi."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ishga tushirilmadi."</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoqilgan"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sozlamalarga kirish uchun bosing"</string>
<string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
<string name="decline" msgid="2112225451706137894">"Rad qilish"</string>
@@ -1019,7 +1018,7 @@
<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;ga xabar jo‘natishni xohlaydi."</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"Bunda, mobil hisobingizdan "<b>"to‘lov olinishi mumkin"</b>"."</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bunda, mobil hisobingizdan to‘lov olinishi mumkin."</b></string>
- <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Jo‘natish"</string>
+ <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Yuborish"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Bekor qilish"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Tanlovim eslab qolinsin"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Siz buni keyinroq sozlamalar &gt; ilovalar menusidan o‘zgartirishingiz mumkin"</string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sozlash uchun bosing."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"O‘chirib qo‘yish uchun bosing."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Administrator bilan xatoliklar hisoboti ulashilsinmi?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administratoringiz nosozliklarni tuzatish uchun xatoliklar hisobotini so‘ramoqda"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Administratoringiz bu qurilma nosozliklarini tuzatish uchun xatoliklar hisobotini so‘ramoqda. Ilova va ma’lumotlardan foydalanilishi va bu vaqtincha qurilmangizni sekinlashtirishi ham mumkin."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Administratoringiz bu qurilma nosozliklarini tuzatish uchun xatoliklar hisobotini so‘ramoqda. Ilova va ma’lumotlardan foydalanilishi mumkin."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Qurilmaning ishlash tezligi vaqtincha pasayishi mumkin."</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"QABUL QILISH"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RAD ETISH"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Xatoliklar hisoboti olinmoqda…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Bekor qilish uchun bosing"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturani tanlash"</string>
<string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
@@ -1115,7 +1115,7 @@
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string>
<string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string>
<string name="ime_action_search" msgid="658110271822807811">"Qidirish"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Jo‘natish"</string>
+ <string name="ime_action_send" msgid="2316166556349314424">"Yuborish"</string>
<string name="ime_action_next" msgid="3138843904009813834">"Keyingi"</string>
<string name="ime_action_done" msgid="8971516117910934605">"Tayyor"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"Old."</string>
@@ -1150,10 +1150,10 @@
<string name="upload_file" msgid="2897957172366730416">"Faylni tanlash"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Hech qanday fayl tanlanmadi"</string>
<string name="reset" msgid="2448168080964209908">"Tiklash"</string>
- <string name="submit" msgid="1602335572089911941">"Jo‘natish"</string>
+ <string name="submit" msgid="1602335572089911941">"Yuborish"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mashina usuli yoqilgan"</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Avtomashina rejimidan chiqish uchun bosing."</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"Modem yoki ulanish nuqtasi - faol"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Modem rejimi yoniq"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"Sozlash uchun bosing."</string>
<string name="back_button_label" msgid="2300470004503343439">"Orqaga"</string>
<string name="next_button_label" msgid="1080555104677992408">"Keyingi"</string>
@@ -1167,7 +1167,7 @@
<string name="action_mode_done" msgid="7217581640461922289">"Tayyor"</string>
<string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"USB xotirasi tozalanmoqda…"</string>
<string name="progress_erasing" product="default" msgid="6596988875507043042">"SD xotira kartasi tozalanmoqda…"</string>
- <string name="share" msgid="1778686618230011964">"Bo‘lishish"</string>
+ <string name="share" msgid="1778686618230011964">"Yuborish"</string>
<string name="find" msgid="4808270900322985960">"Topish"</string>
<string name="websearch" msgid="4337157977400211589">"Veb qidiruv"</string>
<string name="find_next" msgid="5742124618942193978">"Keyingisini topish"</string>
@@ -1212,8 +1212,8 @@
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Kiritish"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Ilovani tanlang"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ishga tushmadi"</string>
- <string name="shareactionprovider_share_with" msgid="806688056141131819">"Bo‘lishish:"</string>
- <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> bilan bo‘lishish"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"Ruxsat berish"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ilovasiga ruxsat berish"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Surish uchun dastak. Bosing va ushlab turing."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Qulfdan chiqarish uchun silang."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Parol kalitlarini eshitish uchun garnitura ulang."</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Yechishda PIN-kod so‘ralsin"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bo‘shatishdan oldin chizmali parol so‘ralsin"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bo‘shatishdan oldin parol so‘ralsin"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Oyna o‘lchamini o‘zgartirib bo‘lmaydi. Sahifani ikkita barmoq bilan aylantiring."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Ilova ekranni ikkiga bo‘lish rejimini qo‘llab-quvvatlamaydi."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Administratoringiz tomonidan o‘rnatilgan"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta tanlandi</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta tanlandi</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Boshqa belgilar"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Bu odamlar siz uchun muhim."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Til sozlamalari"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Tilni qo‘shing"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Hudud sozlamalari"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Taklif etiladi"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"%1$s administratori tomonidan o‘chirilgan. Batafsil ma’lumot uchun bog‘laning."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Sizga yangi SMS keldi"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Ko‘rish uchun SMS ilovasini oching"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Ayrim funksiyalar mavjud bo‘lmasligi mumkin"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Davom etish uchun bosing"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Foydalanuvchi profili yopiq"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Ba’zi funksiyalar cheklanishi m-n"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Qulfni ochish uchun bosing"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Foydalanuvchi ma’lumotlari yopiq"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Ishchi profil yopiq"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Qulfini ochish uchun bosing"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> qurilmasiga ulandi"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Fayllarni ko‘rish uchun bosing"</string>
<string name="pin_target" msgid="3052256031352291362">"Qadash"</string>
<string name="unpin_target" msgid="3556545602439143442">"Olib tashlash"</string>
<string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 44e76b5ed46a..af69c3105fd3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Số gọi đến mặc định thành không bị giới hạn. Cuộc gọi tiếp theo. Không bị giới hạn"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Dịch vụ không được cấp phép."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Bạn không thể thay đổi cài đặt ID người gọi."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Quyền truy cập bị giới hạn đã thay đổi"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Dịch vụ dữ liệu bị chặn."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Dịch vụ khẩn cấp đã bị chặn."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Dịch vụ thoại đã bị chặn."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Đặt lại và khởi động lại ứng dụng"</string>
<string name="aerr_report" msgid="5371800241488400617">"Gửi phản hồi"</string>
<string name="aerr_close" msgid="2991640326563991340">"Đóng"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Bỏ qua"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Tắt tiếng cho đến khi thiết bị khởi động lại"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Đợi"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Đóng ứng dụng"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Chạm để có các tùy chọn khác."</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="1016654627626476142">"Chạm để vô hiệu hóa gỡ lỗi USB."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Chia sẻ báo cáo lỗi với quản trị viên?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố thiết bị này. Bạn có thể chia sẻ ứng dụng, đồng thời dữ liệu và thiết bị của bạn tạm thời có thể bị chậm."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Quản trị viên CNTT của bạn đã yêu cầu báo cáo lỗi để giúp khắc phục sự cố thiết bị này. Bạn có thể chia sẻ ứng dụng và dữ liệu."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Tác vụ này tạm thời có thể làm chậm thiết bị của bạn"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"CHẤP NHẬN"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TỪ CHỐI"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Đang thực hiện báo cáo lỗi…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Chạm để hủy"</string>
<string name="select_input_method" msgid="8547250819326693584">"Thay đổi bàn phím"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Chọn bàn phím"</string>
<string name="show_ime" msgid="2506087537466597099">"Tiếp tục sử dụng ứng dụng trên màn hình trong khi bàn phím thực đang hoạt động"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Hỏi hình mở khóa trước khi bỏ ghim"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Hỏi mật khẩu trước khi bỏ ghim"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ứng dụng không đổi kích thước được, hãy cuộn ứng dụng bằng hai ngón tay."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Được cài đặt bởi quản trị viên của bạn"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Được cập nhật bởi quản trị viên của bạn"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">Đã chọn <xliff:g id="COUNT_1">%1$d</xliff:g></item>
<item quantity="one">Đã chọn <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Khác"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Bạn đặt tầm quan trọng của các thông báo này."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Bạn đặt tầm quan trọng của các thông báo này."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Thông báo này quan trọng vì những người có liên quan."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (người dùng có tài khoản này đã tồn tại)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Tùy chọn ngôn ngữ"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Thêm ngôn ngữ"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Tùy chọn khu vực"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Ðược đề xuất"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Đã bị quản trị viên %1$s tắt. Hãy liên hệ với quản trị viên để tìm hiểu thêm."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Bạn có tin nhắn mới"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Mở ứng dụng SMS để xem"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Một số c.năng có thể ko k.dụng"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Chạm để tiếp tục"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Đã khóa hồ sơ người dùng"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Một số chức năng có thể bị hạn chế"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Nhấn để mở khóa"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Đã khóa dữ liệu người dùng"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Đã khóa hồ sơ công việc"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Nhấn để mở khóa hồ sơ công việc"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Đã kết nối với <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Nhấn để xem tệp"</string>
<string name="pin_target" msgid="3052256031352291362">"Ghim"</string>
<string name="unpin_target" msgid="3556545602439143442">"Bỏ ghim"</string>
<string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 63df5beff76d..61753b1f0211 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -25,6 +25,7 @@
<style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
<style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Micro.Dialog" />
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.Micro" />
<style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Micro" />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index a84fc26d4828..85616b160d61 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"默认显示本机号码,在下一次通话中也显示"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供服务。"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"您无法更改来电显示设置。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"网络可用情况发生变化"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"数据网络服务已停用。"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已停用。"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"语音服务已停用。"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"重置并重启应用"</string>
<string name="aerr_report" msgid="5371800241488400617">"发送反馈"</string>
<string name="aerr_close" msgid="2991640326563991340">"关闭"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"忽略(直到设备重启)"</string>
<string name="aerr_wait" msgid="3199956902437040261">"等待"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"关闭应用"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"触摸以查看更多选项。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"触摸可停用USB调试。"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"要与管理员分享错误报告吗?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"您的 IT 管理员已请求获取错误报告,以便帮助您排查问题"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享错误报告吗?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"您的 IT 管理员希望获取错误报告,以便排查此设备的问题。报告可能会透露您设备上的应用和数据,设备运行速度也可能会因此而暂时减慢。"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"您的 IT 管理员希望获取错误报告,以便排查此设备的问题。报告可能会透露您设备上的应用和数据。"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"这可能会暂时减慢您设备的运行速度"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒绝"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"正在生成错误报告…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"触摸可取消"</string>
<string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"选择键盘"</string>
<string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消时要求绘制解锁图案"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消时要求输入密码"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"无法调整该应用的大小,请用双指滚动该应用。"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下运行。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"应用不支持分屏。"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理员安装"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item>
<item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"这些通知的重要性由您来设置。"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"这些通知的重要性由您来设置。"</string>
<string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"语言偏好设置"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"添加语言"</string>
<string name="country_selection_title" msgid="2954859441620215513">"区域偏好设置"</string>
<string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"建议语言"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"该软件包已被%1$s管理员禁用。请与管理员联系以了解详情。"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"您有新消息"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"打开短信应用查看"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"部分功能可能无法使用"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"触摸即可继续"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"用户个人资料已锁定"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"部分功能可能会受到限制"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"点按即可解锁"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"用户数据已锁定"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"工作资料已锁定"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"点按即可解锁工作资料"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"已连接到<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"点按即可查看文件"</string>
<string name="pin_target" msgid="3052256031352291362">"固定"</string>
<string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
<string name="app_info" msgid="6856026610594615344">"应用信息"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 168025921284..4c46574b077a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"預設顯示來電號碼,下一通電話也繼續顯示。"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供此服務。"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"您無法更改來電顯示設定。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"受限存取已更改"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖數據傳輸服務。"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"已封鎖緊急服務。"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"已封鎖語音服務。"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"重設並重新啟動應用程式"</string>
<string name="aerr_report" msgid="5371800241488400617">"傳送意見反映"</string>
<string name="aerr_close" msgid="2991640326563991340">"關閉"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"忽略直至裝置重新啟動"</string>
<string name="aerr_wait" msgid="3199956902437040261">"等一下"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"關閉應用程式"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"輕觸以瀏覽更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"要與管理員分享錯誤報告嗎?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"您的 IT 管理員要求您提供錯誤報告,以協助解決疑難"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"您的 IT 管理員要求您提供錯誤報告,以協助解決此裝置的問題。報告可能包含應用程式和相關資料,裝置的運作速度也可能暫時減慢。"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"您的 IT 管理員要求您提供錯誤報告,以協助解決此裝置的問題。報告可能會披露裝置中的應用程式和相關資料。"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"裝置的運作速度可能因而減慢"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"正在取得錯誤報告…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"輕觸即可取消"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"在實體鍵盤處於連接狀態時保持顯示"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"無法調整應用程式的大小,請用兩隻手指捲動此應用程式。"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"應用程式可能無法在分割畫面中運作。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"應用程式不支援分割畫面。"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理員安裝"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"已由您的管理員更新"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
<item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"您可以為這些通知設定重要性。"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"您可以設定這些通知的重要性。"</string>
<string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及的人。"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"語言偏好設定"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"新增語言"</string>
<string name="country_selection_title" msgid="2954859441620215513">"地區偏好設定"</string>
<string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"推薦"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"「%1$s」管理員已停用此套件。請與管理員聯絡以瞭解詳情。"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"您有新的訊息"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"開啟短訊應用程式查看內容"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"部分功能可能無法使用"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"輕觸即可繼續"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"使用者個人檔案目前處於鎖定狀態"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"部分功能可能會受到限制"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"輕按即可解鎖"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"使用者資料已上鎖"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"工作設定檔已上鎖"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"輕按即可將工作設定檔解鎖"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"已連線至 <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"輕按即可查看檔案"</string>
<string name="pin_target" msgid="3052256031352291362">"固定"</string>
<string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
<string name="app_info" msgid="6856026610594615344">"應用程式資料"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 59c893cf5ad1..7db879485ee7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"預設顯示本機號碼,下一通電話也繼續顯示。"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"無法提供此服務。"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"您無法變更來電顯示設定。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"受限存取已變更"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖數據傳輸服務。"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"已封鎖緊急服務。"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"已封鎖語音服務。"</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"重設並重新啟動應用程式"</string>
<string name="aerr_report" msgid="5371800241488400617">"提供意見"</string>
<string name="aerr_close" msgid="2991640326563991340">"關閉"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"略過直到裝置重新啟動"</string>
<string name="aerr_wait" msgid="3199956902437040261">"等候"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"關閉應用程式"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"輕觸即可顯示更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"要與管理員分享錯誤報告嗎?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"您的 IT 管理員要求您提供錯誤報告以便排解問題"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"您的 IT 管理員要求您提供錯誤報告,以便排解這個裝置發生的問題。報告可能會揭露裝置中的應用程式和相關資料,裝置運行速度也可能會因此暫時減慢。"</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"您的 IT 管理員要求您提供錯誤報告,以便排解這個裝置發生的問題。報告可能會揭露裝置中的應用程式和相關資料。"</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"這可能會暫時減慢裝置運行速度"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"正在接收錯誤報告…"</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"輕觸即可取消"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"無法調整這個應用程式的大小,請用雙指捲動該應用程式。"</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"應用程式可能無法在分割畫面中運作。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"這個應用程式不支援分割畫面。"</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理員安裝"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"由您的管理員更新"</string>
@@ -1537,12 +1537,11 @@
<item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
<item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"這些通知的重要性由您決定。"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"這些通知的重要性由您決定。"</string>
<string name="importance_from_person" msgid="9160133597262938296">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"要允許 <xliff:g id="APP">%1$s</xliff:g> 為 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"要允許 <xliff:g id="APP">%1$s</xliff:g> 為 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎 (這個帳戶目前已有使用者)?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"語言偏好設定"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"新增語言"</string>
<string name="country_selection_title" msgid="2954859441620215513">"地區偏好設定"</string>
<string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"建議語言"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"這個套件已由「%1$s」管理員停用。請與對方聯絡以瞭解詳情。"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"您有新訊息"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"開啟簡訊應用程式來查看內容"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"部分功能可能無法使用"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"輕觸即可繼續作業"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"使用者個人資料目前處於鎖定狀態"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"部分功能可能受到鎖定"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"輕按即可解鎖"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"使用者資料已鎖定"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Work 設定檔目前處於鎖定狀態"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"輕按即可將 Work 設定檔解鎖"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"已連線至 <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"輕觸即可查看檔案"</string>
<string name="pin_target" msgid="3052256031352291362">"固定"</string>
<string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
<string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9fd47254f5de..9432024dac36 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -88,7 +88,6 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"I-ID Yomshayeli ishintshela kokungavinjelwe. Ucingo olulandelayo: Aluvinjelwe"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Isevisi ayilungiselelwe."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Ngeke ukwazi ukuguqul izilungiselelo zemininingwane yoshayayo."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ukufinyelela okuvinjelwe kushintshiwe"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Isevisi yedatha ivaliwe."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Isevisi ephuthumayo ivimbelwe."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Isevisi yezwi ivimbelwe."</string>
@@ -917,7 +916,7 @@
<string name="aerr_reset" msgid="7645427603514220451">"Setha kabusha uphinde uqalise kabusha uhlelo lokusebenza"</string>
<string name="aerr_report" msgid="5371800241488400617">"Thumela impendulo"</string>
<string name="aerr_close" msgid="2991640326563991340">"Vala"</string>
- <string name="aerr_mute" msgid="7698966346654789433">"Thulisa"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"Thulisa ize iqalise kabusha idivayisi"</string>
<string name="aerr_wait" msgid="3199956902437040261">"Linda"</string>
<string name="aerr_close_app" msgid="3269334853724920302">"Vala uhlelo lokusebenza"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
@@ -1053,12 +1052,13 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Thinta ukuze uthole ezinye izinketho."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Thinta ukwenza ukuthi ukudibhaga kwe-USB kungasebenzi."</string>
- <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Yabelana ngombiko wesiphazamisi nomqondisi?"</string>
- <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Umqondisi wakho we-IT ucele umbiko wesiphazamisi ukuze asize ukuxazulula inkinga"</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>
+ <string name="share_remote_bugreport_notification_message" msgid="752583906074230920">"Umlawuli wakho we-IT ucele umbiko wesiphazamisi ukusiza ukuxazulula inkinga yale divayisi. Izinhlelo zokusebenza zingabelwana futhi idivayisi yakho ingahle yehle kancane."</string>
+ <string name="share_finished_remote_bugreport_notification_message" msgid="4627312060769912353">"Umqondisi wakho we-IT ucele umbiko wesiphazamisi ukukusiza ukuxazulula inkinga kule divayisi. Izinhlelo zokusebenza nedatha ingabiwa."</string>
+ <string name="sharing_remote_bugreport_notification_message" msgid="673106383408474893">"Lokhu kungahambisa kancane idivayisi yakho okwesikhashana"</string>
<string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"YAMUKELA"</string>
<string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"YENQABA"</string>
- <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Ithatha umbiko wesiphazamisi..."</string>
- <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Thinta ukuze ukhansele"</string>
<string name="select_input_method" msgid="8547250819326693584">"Shintsha ikhibhodi"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Khetha amakhibhodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
@@ -1467,7 +1467,7 @@
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Cela iphethini yokuvula ngaphambi kokususa ukuphina"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Cela iphasiwedi ngaphambi kokususa ukuphina"</string>
- <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Uhlelo lokusebenza alukwazi ukunikezwa usayizi omusha, liskrole ngeminwe emibili."</string>
+ <string name="dock_forced_resizable" msgid="5914261505436217520">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
<string name="package_installed_device_owner" msgid="8420696545959087545">"Ifakwe ngumlawuli wakho"</string>
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ibuyekezwe ngumqondisi wakho"</string>
@@ -1537,12 +1537,11 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
</plurals>
- <string name="default_notification_topic_label" msgid="227586145791870829">"Okwahlukahlukene"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"Usethe ukubaluleka kwalezi zaziso."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"Usethe ukubaluleka kwalezi zaziso."</string>
<string name="importance_from_person" msgid="9160133597262938296">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukudala umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukudala umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (umsebenzisi onale akhawunti usuvel ukhona) ?"</string>
- <string name="language_selection_title" msgid="7181332986330337171">"Okuncamelayo kolimi"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Engeza ulwimi"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Okuncamelayo kwesifunda"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Okuphakanyisiwe"</string>
@@ -1555,12 +1554,15 @@
<string name="suspended_package_message" msgid="6341091587106868601">"Ikhutshazwe umlawuli we-%1$s. Xhumana nabo ukuze ufunde kabanzi."</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Unemilayezo emisha"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Vula uhlelo lokusebenza lwe-SMS ukuze ubuke"</string>
- <string name="user_encrypted_title" msgid="7664361246988454307">"Eminye imisebenzi ingahle ingatholakali"</string>
- <string name="user_encrypted_message" msgid="7504541494700807850">"Thinta ukuze uqhubeke"</string>
- <string name="user_encrypted_detail" msgid="979981584766912935">"Iphrofayela yomsebenzisi ikhiyiwe"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"Okunye ukusebenza kungakhawulelwe"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"Thepha ukuze uvule"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"Idatha yomsebenzisi ikhiyiwe"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"Iphrofayela yomsebenzi ikhiyiwe"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"Thepha ukuze uvule iphrofayela yomsebenzi"</string>
<string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Kuxhumekile ku-<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Thepha ukuze ubuke onke amafayela"</string>
<string name="pin_target" msgid="3052256031352291362">"Phina"</string>
<string name="unpin_target" msgid="3556545602439143442">"Susa ukuphina"</string>
<string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index be8577ae9b65..7c0212801851 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3539,6 +3539,9 @@ i
If no format string is specified, the Chronometer will simply display
"MM:SS" or "H:MM:SS". -->
<attr name="format" format="string" localization="suggested" />
+ <!-- Specifies whether this Chronometer counts down or counts up from the base.
+ If not specified this is false and the Chronometer counts up. -->
+ <attr name="countDown" format="boolean" />
</declare-styleable>
<declare-styleable name="CompoundButton">
<!-- Indicates the initial checked state of this button. -->
@@ -5030,7 +5033,7 @@ i
<attr name="firstDayOfWeek" format="integer" />
<!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="minDate" />
- <!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
+ <!-- The maximal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="maxDate" />
<!-- The text appearance for the month and year in the calendar header. -->
<attr name="monthTextAppearance" format="reference" />
@@ -8045,12 +8048,19 @@ i
{@link android.media.tv.TvInputService#SERVICE_META_DATA} meta-data entry.
Described here are the attributes that can be included in that tag. -->
<declare-styleable name="TvInputService">
- <!-- Component name of an activity for setup of this service.
- The setup includes scanning channels and registering EPG data. -->
+ <!-- Component name of an activity that allows the user to set up this service. -->
<attr name="setupActivity" format="string" />
- <!-- Component name of an activity that allows the user to modify
- the settings for this service. -->
+ <!-- Component name of an activity that allows the user to modify the settings for this
+ service. -->
<attr name="settingsActivity" />
+ <!-- Attribute whether the TV input service can record programs. This value can be changed
+ at runtime by calling
+ {@link android.media.tv.TvInputService#updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo)}. -->
+ <attr name="canRecord" format="boolean" />
+ <!-- The number of tuners that the TV input service is associated with. This value can be
+ changed at runtime by calling
+ {@link android.media.tv.TvInputService#updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo)}. -->
+ <attr name="tunerCount" format="integer" />
</declare-styleable>
<!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the
@@ -8172,4 +8182,18 @@ i
<!-- The current color for the offset inside the gradient. -->
<attr name="color" />
</declare-styleable>
+
+ <!-- @hide Attributes which will be read by the Activity to intialize the
+ base activity TaskDescription. -->
+ <declare-styleable name="ActivityTaskDescription">
+ <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary
+ color. -->
+ <attr name="colorPrimary" />
+ <!-- @hide From Theme.windowBackground, used for calculating the
+ TaskDescription background color. -->
+ <attr name="windowBackground" />
+ <!-- @hide From Theme.windowBackgroundFallback, used for calculating the
+ TaskDescription background color. -->
+ <attr name="windowBackgroundFallback" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 3a5336cd05f1..d0d1d5a0b694 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -248,9 +248,12 @@
may cost the user money. Such permissions may be highlighted
when shown to the user with this additional information. -->
<flag name="costsMoney" value="0x0001" />
- <!-- Additional flag from base permission type: this permission is hidden
- and should not show in the UI. -->
- <flag name="hidden" value="0x2" />
+ <!-- Additional flag from base permission type: this permission has been
+ removed and it is no longer enforced. It shouldn't be shown in the
+ UI. Removed permissions are kept as normal permissions for backwards
+ compatibility as apps may be checking them before calling an API.
+ -->
+ <flag name="removed" value="0x2" />
</attr>
<!-- Specified the name of a group that this permission is associated
@@ -429,8 +432,10 @@
sets. -->
<attr name="multiArch" format ="boolean" />
- <!-- Specify abiOverride for multiArch application. -->
- <attr name="abiOverride" />
+ <!-- Specify whether the 32 bit version of the ABI should be used in a
+ multiArch application. If both abioverride flag (i.e. using abi option of abd install)
+ and use32bitAbi are used, then use32bit is ignored.-->
+ <attr name="use32bitAbi" />
<!-- Specify whether a component is allowed to have multiple instances
of itself running in different processes. Use with the activity
@@ -912,6 +917,17 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="restoreAnyVersion" format="boolean" />
+ <!-- Indicates that full-data backup operations for this application may
+ be performed even if the application is in a foreground-equivalent
+ state. <em>Use with caution!</em> Setting this flag to <code>true</code>
+ can impact app behavior while the user is interacting with the device.
+
+ <p>If unspecified, the default value of this attribute is <code>false</code>,
+ which means that the OS will avoid backing up the application while it is
+ running in the foreground (such as a music app that is actively playing
+ music via a service in the startForeground() state). -->
+ <attr name="backupInForeground" format="boolean" />
+
<!-- The default install location defined by an application. -->
<attr name="installLocation">
<!-- Let the system decide ideal install location -->
@@ -1245,6 +1261,7 @@
<attr name="killAfterRestore" />
<attr name="restoreNeedsApplication" />
<attr name="restoreAnyVersion" />
+ <attr name="backupInForeground" />
<attr name="neverEncrypt" />
<!-- Request that your application's processes be created with
a large Dalvik heap. This applies to <em>all</em> processes
@@ -1423,22 +1440,24 @@
<attr name="reqFiveWayNav" />
</declare-styleable>
- <!-- The <code>uses-feature</code> tag specifies
- a specific feature used by the application.
- For example an application might specify that it requires
- specific version of OpenGL. Multiple such attribute
- values can be specified by the application.
+ <!-- The <code>uses-feature</code> tag specifies a specific device
+ hardware or software feature used by the application. For
+ example an application might specify that it requires
+ a camera. Multiple attribute values can be specified by the
+ application.
<p>This appears as a child tag of the root
{@link #AndroidManifest manifest} tag. -->
<declare-styleable name="AndroidManifestUsesFeature" parent="AndroidManifest">
+ <!-- The name of the feature that is being used. -->
+ <attr name="name" />
+ <!-- The version of the feature that is being used. -->
+ <attr name="version" format="integer" />
<!-- The GLES driver version number needed by an application.
The higher 16 bits represent the major number and the lower 16 bits
represent the minor number. For example for GL 1.2 referring to
0x00000102, the actual value should be set as 0x00010002. -->
- <attr name="glEsVersion" format="integer"/>
- <!-- The name of the feature that is being used. -->
- <attr name="name" />
+ <attr name="glEsVersion" format="integer" />
<!-- Specify whether this feature is required for the application.
The default is true, meaning the application requires the
feature, and does not want to be installed on devices that
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 507925b70336..b65f19b08e07 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -29,6 +29,7 @@
<string-array name="config_statusBarIcons">
<item><xliff:g id="id">@string/status_bar_rotate</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_headset</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_data_saver</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_ime</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_sync_failing</xliff:g></item>
@@ -56,6 +57,7 @@
<string translatable="false" name="status_bar_rotate">rotate</string>
<string translatable="false" name="status_bar_headset">headset</string>
+ <string translatable="false" name="status_bar_data_saver">data_saver</string>
<string translatable="false" name="status_bar_managed_profile">managed_profile</string>
<string translatable="false" name="status_bar_ime">ime</string>
<string translatable="false" name="status_bar_sync_failing">sync_failing</string>
@@ -998,7 +1000,6 @@
0 - Nothing
1 - Recent apps view in SystemUI
2 - Launch assist intent
- 3 - Start picture-in-picture (PIP) or launch PIP UI
This needs to match the constants in
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
-->
@@ -1993,10 +1994,10 @@
See {@link com.android.server.notification.NotificationSignalExtractor} -->
<string-array name="config_notificationSignalExtractors">
<item>com.android.server.notification.ValidateNotificationPeople</item>
- <item>com.android.server.notification.TopicPriorityExtractor</item>
- <item>com.android.server.notification.TopicImportanceExtractor</item>
+ <item>com.android.server.notification.PriorityExtractor</item>
+ <item>com.android.server.notification.ImportanceExtractor</item>
<item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
- <item>com.android.server.notification.TopicVisibilityExtractor</item>
+ <item>com.android.server.notification.VisibilityExtractor</item>
</string-array>
<!-- Flag indicating that this device does not rotate and will always remain in its default
@@ -2443,6 +2444,10 @@
is located in center. -->
<string translatable="false" name="config_centeredPictureInPictureBounds">"0 0 300 300"</string>
+ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
+ when the PIP is shown with Recents. -->
+ <string translatable="false" name="config_pictureInPictureBoundsInRecents">"0 0 100 100"</string>
+
<!-- Controls the snap mode for the docked stack divider
0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
@@ -2469,4 +2474,9 @@
much in the way of user data.
-->
<bool name="config_strongAuthRequiredOnBoot">true</bool>
+
+ <!-- Wallpaper cropper package. Used as the default cropper if the active launcher doesn't
+ handle wallpaper cropping.
+ -->
+ <string name="config_wallpaperCropperPackage" translatable="false">com.android.wallpapercropper</string>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8e86f78e02fd..152473afe077 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -56,6 +56,10 @@
calculate the bounds of the stacks-->
<dimen name="docked_stack_divider_insets">19dp</dimen>
+ <!-- To how much the docked stack gets reduced when we decide to minimize the docked stack, i.e.
+ when the user opens homescreen. -->
+ <dimen name="docked_stack_minimize_thickness">8dp</dimen>
+
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
@@ -146,9 +150,6 @@
<!-- The margin on the end of the content view with a picture.-->
<dimen name="notification_content_picture_margin">56dp</dimen>
- <!-- The margin on the end of the content view with a picture in the compact media.-->
- <dimen name="notification_content_picture_margin_media">72dp</dimen>
-
<!-- height of the content margin to accomodate for the header -->
<dimen name="notification_content_margin_top">30dp</dimen>
@@ -267,7 +268,7 @@
<!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
<dimen name="notification_text_size">14sp</dimen>
<!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
- <dimen name="notification_title_text_size">16sp</dimen>
+ <dimen name="notification_title_text_size">14sp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
<dimen name="notification_subtext_size">12sp</dimen>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 96a81d138457..2fe4f6652a87 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -82,6 +82,9 @@
<dimen name="text_size_medium_material">18sp</dimen>
<dimen name="text_size_small_material">14sp</dimen>
+ <dimen name="text_edit_floating_toolbar_elevation">2dp</dimen>
+ <dimen name="text_edit_floating_toolbar_margin">20dp</dimen>
+
<dimen name="floating_window_z">16dp</dimen>
<dimen name="floating_window_margin_left">16dp</dimen>
<dimen name="floating_window_margin_top">8dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5c5aff0998fa..06e2248bbb5a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2696,10 +2696,15 @@
<public type="attr" name="endX" />
<public type="attr" name="endY" />
<public type="attr" name="offset" />
- <public type="attr" name="abiOverride" />
+ <public type="attr" name="use32bitAbi" />
<public type="attr" name="bitmap" />
<public type="attr" name="hotSpotX" />
<public type="attr" name="hotSpotY" />
+ <public type="attr" name="version" />
+ <public type="attr" name="backupInForeground" />
+ <public type="attr" name="countDown" />
+ <public type="attr" name="canRecord" />
+ <public type="attr" name="tunerCount" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4e10d39e0005..7b113023d194 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -185,8 +185,6 @@
<!-- Displayed to tell the user that they cannot change the caller ID setting. -->
<string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
- <!-- Notification title to tell the user that restricted state is changed by access control. -->
- <string name="RestrictedChangedTitle">Restricted access changed</string>
<!-- Displayed to tell the user that data service is blocked by access control. -->
<string name="RestrictedOnData">Data service is blocked.</string>
<!-- Displayed to tell the user that emergency service is blocked by access control. -->
@@ -2608,8 +2606,8 @@
<string name="aerr_report">Send feedback</string>
<!-- Button that closes a crashed application -->
<string name="aerr_close">Close</string>
- <!-- Button that mutes further crashes of the crashed application-->
- <string name="aerr_mute">Mute</string>
+ <!-- Button that mutes further crashes of the crashed application. Note that this only appears on engineering builds. -->
+ <string name="aerr_mute">Mute until device restarts</string>
<!-- Button that waits a bit more for an unresponsive app -->
<string name="aerr_wait">Wait</string>
<!-- Button that closes an unresponsive application -->
@@ -2920,17 +2918,19 @@
<string name="adb_active_notification_message">Touch to disable USB debugging.</string>
<!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
- <string name="share_remote_bugreport_notification_title">Share bug report with admin?</string>
+ <string name="share_remote_bugreport_notification_title">Share bug report?</string>
+ <!-- Title of notification shown to indicate that bug report is still being collected after sharing was accepted. -->
+ <string name="sharing_remote_bugreport_notification_title">Sharing bug report\u2026</string>
<!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
- <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot</string>
+ <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down.</string>
+ <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
+ <string name="share_finished_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
+ <!-- Message of notification shown to shown to indicate that bug report is still being collected after sharing was accepted. -->
+ <string name="sharing_remote_bugreport_notification_message">This may temporarily slow down your device</string>
<!-- Acceptance label of notification shown to ask for user consent for sharing the remote bugreport. -->
<string name="share_remote_bugreport_notification_accept">ACCEPT</string>
<!-- Decline label of notification shown to ask for user consent for sharing the remote bugreport. -->
<string name="share_remote_bugreport_notification_decline">DECLINE</string>
- <!-- Title of notification shown for remote bugreport progress. -->
- <string name="remote_bugreport_progress_notification_title">Taking bug report\u2026</string>
- <!-- Message of notification shown for remote bugreport progress. User can cancel the bugreport -->
- <string name="remote_bugreport_progress_notification_message_can_cancel">Touch to cancel</string>
<!-- Used to replace %s in urls retreived from the signin server with locales. For Some -->
<!-- devices we don't support all the locales we ship to and need to replace the '%s' with a -->
@@ -4014,8 +4014,8 @@
<string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
<!-- Multi-Window strings -->
- <!-- Warning message when a non-resizeble tasks is docked whose display windows are cropped. -->
- <string name="dock_cropped_windows_text">App is not resizeable, scroll it with two fingers.</string>
+ <!-- Warning message when an app that got forced to be resizable gets shown in split-screen -->
+ <string name="dock_forced_resizable">App may not work with split-screen.</string>
<!-- Warning message when we try to dock a non-resizeble tasks and launch it in fullscreen instead. -->
<string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
@@ -4160,9 +4160,7 @@
<item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
</plurals>
- <string name="default_notification_topic_label">Miscellaneous</string>
-
- <string name="importance_from_topic">You set the importance of these notifications.</string>
+ <string name="importance_from_user">You set the importance of these notifications.</string>
<string name="importance_from_person">This is important because of the people involved.</string>
<!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] -->
@@ -4173,7 +4171,7 @@
<!-- Locale picker strings -->
<!-- Title for the language selection screen [CHAR LIMIT=25] -->
- <string name="language_selection_title">Language preference</string>
+ <string name="language_selection_title">Add a language</string>
<!-- Title for the region selection screen [CHAR LIMIT=25] -->
<string name="country_selection_title">Region preference</string>
<!-- Hint text in a search edit box (used to filter long language / country lists) [CHAR LIMIT=25] -->
@@ -4204,11 +4202,16 @@
<string name="new_sms_notification_content">Open SMS app to view</string>
<!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_title">Some functions might not be available</string>
+ <string name="user_encrypted_title">Some functionality may be limited</string>
<!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_message">Touch to continue</string>
+ <string name="user_encrypted_message">Tap to unlock</string>
<!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
- <string name="user_encrypted_detail">User profile locked</string>
+ <string name="user_encrypted_detail">User data locked</string>
+
+ <!-- Notification detail shown when work profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="profile_encrypted_detail">Work profile locked</string>
+ <!-- Notification message shown when work profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+ <string name="profile_encrypted_message">Tap to unlock work profile</string>
<!-- Title of notification shown after a MTP device is connected to Android. -->
<string name="usb_mtp_launch_notification_title">Connected to <xliff:g id="product_name">%1$s</xliff:g></string>
@@ -4225,4 +4228,7 @@
<!-- View application info for a target. -->
<string name="app_info">App info</string>
+ <!-- The representation of a time duration when negative. An example is -1:14. This can be used with a countdown timer for example.-->
+ <string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>
+
</resources>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index 6c6914156732..fdf9e31e4a60 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -1175,7 +1175,6 @@ please see styles_device_defaults.xml.
<style name="Widget.Holo.SuggestionItem" parent="TextAppearance.Holo.Medium">
<item name="background">@color/white</item>
<item name="drawablePadding">8dip</item>
- <item name="ellipsize">marquee</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
<item name="layout_height">wrap_content</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 9efcfdace11b..db418f7947b9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -996,7 +996,6 @@ please see styles_device_defaults.xml.
<item name="alpha">.87</item>
<item name="textColor">@color/black</item>
<item name="drawablePadding">8dip</item>
- <item name="ellipsize">marquee</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
<item name="layout_height">48dip</item>
@@ -1017,7 +1016,6 @@ please see styles_device_defaults.xml.
<item name="alpha">.87</item>
<item name="textColor">#009688</item>
<item name="drawablePadding">8dip</item>
- <item name="ellipsize">marquee</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
<item name="layout_height">48dip</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f75f023b8c31..44a7a8d39077 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -306,6 +306,7 @@
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="string" name="config_defaultPictureInPictureBounds" />
<java-symbol type="string" name="config_centeredPictureInPictureBounds" />
+ <java-symbol type="string" name="config_pictureInPictureBoundsInRecents" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
@@ -484,7 +485,6 @@
<java-symbol type="string" name="Noon" />
<java-symbol type="string" name="PinMmi" />
<java-symbol type="string" name="PwdMmi" />
- <java-symbol type="string" name="RestrictedChangedTitle" />
<java-symbol type="string" name="RestrictedOnAllVoice" />
<java-symbol type="string" name="RestrictedOnData" />
<java-symbol type="string" name="RestrictedOnEmergency" />
@@ -610,7 +610,7 @@
<java-symbol type="string" name="display_manager_overlay_display_name" />
<java-symbol type="string" name="display_manager_overlay_display_secure_suffix" />
<java-symbol type="string" name="display_manager_overlay_display_title" />
- <java-symbol type="string" name="dock_cropped_windows_text" />
+ <java-symbol type="string" name="dock_forced_resizable" />
<java-symbol type="string" name="dock_non_resizeble_failed_to_dock_text" />
<java-symbol type="string" name="double_tap_toast" />
<java-symbol type="string" name="durationDays" />
@@ -1506,6 +1506,7 @@
<java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
<java-symbol type="dimen" name="docked_stack_divider_thickness" />
<java-symbol type="dimen" name="docked_stack_divider_insets" />
+ <java-symbol type="dimen" name="docked_stack_minimize_thickness" />
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="dimen" name="navigation_bar_height" />
@@ -1770,10 +1771,11 @@
<java-symbol type="string" name="adb_active_notification_title" />
<java-symbol type="string" name="share_remote_bugreport_notification_title" />
<java-symbol type="string" name="share_remote_bugreport_notification_message" />
+ <java-symbol type="string" name="share_finished_remote_bugreport_notification_message" />
+ <java-symbol type="string" name="sharing_remote_bugreport_notification_title" />
+ <java-symbol type="string" name="sharing_remote_bugreport_notification_message" />
<java-symbol type="string" name="share_remote_bugreport_notification_accept" />
<java-symbol type="string" name="share_remote_bugreport_notification_decline" />
- <java-symbol type="string" name="remote_bugreport_progress_notification_title" />
- <java-symbol type="string" name="remote_bugreport_progress_notification_message_can_cancel" />
<java-symbol type="string" name="aerr_application" />
<java-symbol type="string" name="aerr_process" />
<java-symbol type="string" name="aerr_application_repeated" />
@@ -2387,7 +2389,6 @@
<java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
<java-symbol type="string" name="config_packagedKeyboardName" />
- <java-symbol type="string" name="default_notification_topic_label" />
<java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
@@ -2426,7 +2427,7 @@
<java-symbol type="dimen" name="notification_content_margin_end" />
<java-symbol type="dimen" name="notification_content_picture_margin" />
<java-symbol type="dimen" name="notification_content_margin_top" />
- <java-symbol type="string" name="importance_from_topic" />
+ <java-symbol type="string" name="importance_from_user" />
<java-symbol type="string" name="importance_from_person" />
<java-symbol type="layout" name="work_widget_mask_view" />
@@ -2459,6 +2460,7 @@
<java-symbol type="string" name="status_bar_rotate" />
<java-symbol type="string" name="status_bar_headset" />
+ <java-symbol type="string" name="status_bar_data_saver" />
<java-symbol type="string" name="status_bar_managed_profile" />
<java-symbol type="string" name="status_bar_ime" />
<java-symbol type="string" name="status_bar_sync_failing" />
@@ -2484,7 +2486,6 @@
<java-symbol type="string" name="status_bar_clock" />
<!-- Locale picker -->
- <java-symbol type="id" name="l10nWarn" />
<java-symbol type="id" name="locale_search_menu" />
<java-symbol type="layout" name="language_picker_item" />
<java-symbol type="layout" name="language_picker_section_header" />
@@ -2511,17 +2512,20 @@
<java-symbol type="dimen" name="media_notification_expanded_image_max_size" />
<java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
<java-symbol type="dimen" name="notification_content_image_margin_end" />
- <java-symbol type="dimen" name="notification_content_picture_margin_media" />
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
<java-symbol type="layout" name="app_anr_dialog" />
<java-symbol type="id" name="aerr_wait" />
+ <java-symbol type="id" name="notification_content_container" />
+
<!-- Encryption notification while accounts are locked by credential encryption -->
<java-symbol type="string" name="user_encrypted_title" />
<java-symbol type="string" name="user_encrypted_message" />
<java-symbol type="string" name="user_encrypted_detail" />
+ <java-symbol type="string" name="profile_encrypted_detail" />
+ <java-symbol type="string" name="profile_encrypted_message" />
<java-symbol type="drawable" name="ic_user_secure" />
<java-symbol type="string" name="usb_mtp_launch_notification_title" />
@@ -2536,4 +2540,8 @@
<java-symbol type="string" name="carrier_app_dialog_not_now" />
<java-symbol type="string" name="carrier_app_notification_title" />
<java-symbol type="string" name="carrier_app_notification_text" />
+ <java-symbol type="string" name="negative_duration" />
+
+ <!-- WallpaperManager config -->
+ <java-symbol type="string" name="config_wallpaperCropperPackage" />
</resources>
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
index 7322e8d6949b..9e45d099b669 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -22,6 +22,8 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := \
libnativehelper
+LOCAL_CFLAGS += -Wall -Werror
+
LOCAL_MODULE := libframeworks_coretests_jni
# this does not prevent build system
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index 3e8301038359..8d9119275bc8 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -37,7 +37,7 @@ int register_com_android_frameworks_coretests_JNITests(JNIEnv* env) {
/*
* JNI Initialization
*/
-jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
+jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) {
JNIEnv *e;
int status;
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index c3afbf672ae2..3869cd29f69f 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -66,7 +66,7 @@ public class FullBackupTest extends AndroidTestCase {
assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
@@ -99,7 +99,7 @@ public class FullBackupTest extends AndroidTestCase {
FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "include.txt").getCanonicalPath(),
@@ -128,15 +128,16 @@ public class FullBackupTest extends AndroidTestCase {
FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "include1.txt").getCanonicalPath(),
fileDomainIncludes.iterator().next());
Set<String> databaseDomainIncludes = includeMap.get(FullBackup.DATABASE_TREE_TOKEN);
+ // Three expected here because of "-journal" and "-wal" files
assertEquals("Didn't find expected database domain include.",
- 2, databaseDomainIncludes.size()); // two expected here because of "-journal" file
+ 3, databaseDomainIncludes.size());
assertTrue("Invalid path parsed for <include/>",
databaseDomainIncludes.contains(
new File(mContext.getDatabasePath("foo").getParentFile(), "include2.txt")
@@ -147,6 +148,12 @@ public class FullBackupTest extends AndroidTestCase {
mContext.getDatabasePath("foo").getParentFile(),
"include2.txt-journal")
.getCanonicalPath()));
+ assertTrue("Invalid path parsed for <include/>",
+ databaseDomainIncludes.contains(
+ new File(
+ mContext.getDatabasePath("foo").getParentFile(),
+ "include2.txt-wal")
+ .getCanonicalPath()));
List<String> sharedPrefDomainIncludes = new ArrayList<String>(
includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN));
@@ -168,7 +175,7 @@ public class FullBackupTest extends AndroidTestCase {
sharedPrefDomainIncludes.get(2));
- assertEquals("Unexpected number of <exclude/>s", 6, excludesSet.size());
+ assertEquals("Unexpected number of <exclude/>s", 7, excludesSet.size());
// Sets are annoying to iterate over b/c order isn't enforced - convert to an array and
// sort lexicographically.
List<String> arrayedSet = new ArrayList<String>(excludesSet);
@@ -183,20 +190,24 @@ public class FullBackupTest extends AndroidTestCase {
.getCanonicalPath(),
arrayedSet.get(1));
assertEquals("Invalid path parsed for <exclude/>",
- new File(mContext.getFilesDir(), "exclude1.txt").getCanonicalPath(),
+ new File(mContext.getDatabasePath("foo").getParentFile(), "exclude2.txt-wal")
+ .getCanonicalPath(),
arrayedSet.get(2));
assertEquals("Invalid path parsed for <exclude/>",
+ new File(mContext.getFilesDir(), "exclude1.txt").getCanonicalPath(),
+ arrayedSet.get(3));
+ assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3")
.getCanonicalPath(),
- arrayedSet.get(3));
+ arrayedSet.get(4));
assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3.xml")
.getCanonicalPath(),
- arrayedSet.get(4));
+ arrayedSet.get(5));
assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude4.xml")
.getCanonicalPath(),
- arrayedSet.get(5));
+ arrayedSet.get(6));
}
public void testParseBackupSchemeFromXml_invalidXmlFails() throws Exception {
@@ -247,7 +258,7 @@ public class FullBackupTest extends AndroidTestCase {
assertEquals("Didn't throw away invalid \"..\" path.", 0, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
public void testDoubleDotInPath_isIgnored() throws Exception {
@@ -261,7 +272,7 @@ public class FullBackupTest extends AndroidTestCase {
assertEquals("Didn't throw away invalid \"..\" path.", 0, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 605f067afebc..9ab62cc03bea 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -24,6 +24,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.os.UserHandle;
import android.test.InstrumentationTestCase;
import android.util.Pair;
@@ -116,14 +117,14 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
}
}
- Mockito.when(mMockPm.queryBroadcastReceivers(
+ Mockito.when(mMockPm.queryBroadcastReceiversAsUser(
Mockito.argThat(new ArgumentMatcher<Intent>() {
@Override
public boolean matches(Object object) {
Intent intent = (Intent) object;
return NetworkScoreManager.ACTION_SCORE_NETWORKS.equals(intent.getAction());
}
- }), Mockito.eq(0)))
+ }), Mockito.eq(0), Mockito.eq(UserHandle.USER_SYSTEM)))
.thenReturn(receivers);
}
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
new file mode 100644
index 000000000000..d2e811cd8ece
--- /dev/null
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -0,0 +1,588 @@
+/*
+ * 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.method;
+
+import android.app.Activity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.InputType;
+import android.text.method.BaseKeyListener;
+import android.text.method.KeyListenerTestCase;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test backspace key handling of {@link android.text.method.BaseKeyListner}.
+ *
+ * TODO: Move some of test cases to the CTS.
+ */
+public class BackspaceTest extends KeyListenerTestCase {
+ private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
+ public int getInputType() {
+ return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ }
+ };
+
+ // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
+ // Then update the state to the result of TextView.
+ private void backspace(final EditorState state, int modifiers) {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.setText(state.mText, BufferType.EDITABLE);
+ mTextView.setKeyListener(mKeyListener);
+ mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mTextView.hasWindowFocus());
+
+ final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ state.mText = mTextView.getText();
+ state.mSelectionStart = mTextView.getSelectionStart();
+ state.mSelectionEnd = mTextView.getSelectionEnd();
+ }
+
+ @SmallTest
+ public void testSurrogatePairs() {
+ EditorState state = new EditorState();
+
+ state.setByString("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F441 U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // TODO: introduce edge cases.
+ }
+
+ @SmallTest
+ public void testReplacementSpan() {
+ EditorState state = new EditorState();
+
+ // ReplacementSpan will be set to "()" region.
+ state.setByString("'abc' ( 'de' ) 'fg' |");
+ backspace(state, 0);
+ state.assertEquals("'abc' ( 'de' ) 'f' |");
+ backspace(state, 0);
+ state.assertEquals("'abc' ( 'de' ) |");
+ backspace(state, 0);
+ state.assertEquals("'abc' |");
+ backspace(state, 0);
+ state.assertEquals("'ab' |");
+ backspace(state, 0);
+ state.assertEquals("'a' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'abc' [ ( 'de' ) ] 'fg'");
+ backspace(state, 0);
+ state.assertEquals("'abc' | 'fg'");
+ backspace(state, 0);
+ state.assertEquals("'ab' | 'fg'");
+ backspace(state, 0);
+ state.assertEquals("'a' | 'fg'");
+ backspace(state, 0);
+ state.assertEquals("| 'fg'");
+ backspace(state, 0);
+ state.assertEquals("| 'fg'");
+
+ state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'");
+ backspace(state, 0);
+ state.assertEquals("'ab' | 'g'");
+ backspace(state, 0);
+ state.assertEquals("'a' | 'g'");
+ backspace(state, 0);
+ state.assertEquals("| 'g'");
+ backspace(state, 0);
+ state.assertEquals("| 'g'");
+
+ // TODO: introduce edge cases.
+ }
+
+ @SmallTest
+ public void testCombiningEnclosingKeycaps() {
+ EditorState state = new EditorState();
+
+ // U+20E3 is COMBINING ENCLOSING KEYCAP.
+ state.setByString("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector before COMBINING ECLOSING KEYCAP
+ state.setByString("'1' U+FE0E U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'1' U+E0101 U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // multiple COMBINING ENCLOSING KEYCAP
+ state.setByString("'1' U+20E3 U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Isolated COMBINING ENCLOSING KEYCAP
+ state.setByString("U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple COMBINING ENCLOSING KEYCAP
+ state.setByString("U+20E3 U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testVariationSelector() {
+ EditorState state = new EditorState();
+
+ // U+FE0F is VARIATION SELECTOR-16.
+ state.setByString("'#' U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // U+E0100 is VARIATION SELECTOR-17.
+ state.setByString("U+845B U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // Isolated variation selector
+ state.setByString("U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple variation selectors
+ state.setByString("U+FE0F U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+FE0F U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+E0100 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+E0100 U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Multiple variation selectors
+ state.setByString("'#' U+FE0F U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("'#' U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'#' U+FE0F U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("'#' U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+845B U+E0100 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("U+845B U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+845B U+E0100 U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("U+845B U+E0100 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testEmojiZWJSequence() {
+ EditorState state = new EditorState();
+
+ // U+200D is ZERO WIDTH JOINER.
+ state.setByString("U+1F441 U+200D U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F441 U+200D U+1F5E8 U+FE0E |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // End with ZERO WIDTH JOINER
+ state.setByString("U+1F441 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER
+ state.setByString("U+200D U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("U+200D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+FE0E U+200D U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("U+FE0E U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+FE0E |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Multiple ZERO WIDTH JOINER
+ state.setByString("U+1F441 U+200D U+200D U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 U+200D U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Isolated ZERO WIDTH JOINER
+ state.setByString("U+200D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple ZERO WIDTH JOINER
+ state.setByString("U+200D U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+200D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testFlags() {
+ EditorState state = new EditorState();
+
+ // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
+ // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S.
+ state.setByString("U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'a' U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("'a' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+1F1FA U+1F1F8 U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("'a' U+1F1FA U+1F1F8 'b' U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("'a' U+1F1FA U+1F1F8 'b' |");
+ backspace(state, 0);
+ state.assertEquals("'a' U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("'a' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Edcae cases
+ // Isolated regional indicator symbol
+ state.setByString("U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Odd numbered regional indicator symbols
+ state.setByString("U+1F1FA U+1F1F8 U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA U+1F1F8 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testEmojiModifier() {
+ EditorState state = new EditorState();
+
+ // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
+ state.setByString("U+1F466 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Edge cases
+ // Isolated emoji modifier
+ state.setByString("U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Isolated multiple emoji modifier
+ state.setByString("U+1F3FB U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Multiple emoji modifiers
+ state.setByString("U+1F466 U+1F3FB U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("U+1F466 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
+ public void testMixedEdgeCases() {
+ EditorState state = new EditorState();
+
+ // COMBINING ENCLOSING KEYCAP + variation selector
+ state.setByString("'1' U+20E3 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("'1' |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + COMBINING ENCLOSING KEYCAP
+ state.setByString("U+2665 U+FE0F U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("U+2665 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
+ state.setByString("'1' U+20E3 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
+ state.setByString("'1' U+20E3 U+200D U+1F5E8 |");
+ backspace(state, 0);
+ state.assertEquals("'1' U+20E3 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+ state.setByString("U+200D U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("U+200D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+ state.setByString("U+1F441 U+200D U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F441 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + regional indicator symbol
+ state.setByString("'1' U+20E3 U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
+ state.setByString("U+1F1FA U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // COMBINING ENCLOSING KEYCAP + emoji modifier
+ state.setByString("'1' U+20E3 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("'1' U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + COMBINING ENCLOSING KEYCAP
+ state.setByString("U+1F466 U+1F3FB U+20E3 |");
+ backspace(state, 0);
+ state.assertEquals("U+1f466 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + end with ZERO WIDTH JOINER
+ state.setByString("U+2665 U+FE0F U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+2665 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + ZERO WIDTH JOINER
+ state.setByString("U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER + variation selector
+ state.setByString("U+200D U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + variation selector
+ state.setByString("U+1F469 U+200D U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("U+1F469 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + regional indicator symbol
+ state.setByString("U+2665 U+FE0F U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("U+2665 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + variation selector
+ state.setByString("U+1F1FA U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Variation selector + emoji modifier
+ state.setByString("U+2665 U+FE0F U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("U+2665 U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + variation selector
+ state.setByString("U+1F466 U+1F3FB U+FE0F |");
+ backspace(state, 0);
+ state.assertEquals("U+1F466 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Start withj ZERO WIDTH JOINER + regional indicator symbol
+ state.setByString("U+200D U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("U+200D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + Regional indicator symbol
+ state.setByString("U+1F469 U+200D U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("U+1F469 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F469 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + end with ZERO WIDTH JOINER
+ state.setByString("U+1F1FA U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + ZERO WIDTH JOINER
+ state.setByString("U+1F1FA U+200D U+1F469 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Start with ZERO WIDTH JOINER + emoji modifier
+ state.setByString("U+200D U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("U+200D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // ZERO WIDTH JOINER + emoji modifier
+ state.setByString("U+1F469 U+200D U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("U+1F469 U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F469 |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + end with ZERO WIDTH JOINER
+ state.setByString("U+1F466 U+1F3FB U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F466 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + ZERO WIDTH JOINER
+ state.setByString("U+1F466 U+1F3FB U+200D U+1F469 |");
+ backspace(state, 0);
+ state.assertEquals("U+1F466 U+1F3FB U+200D |");
+ backspace(state, 0);
+ state.assertEquals("U+1F466 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Regional indicator symbol + Emoji modifier
+ state.setByString("U+1F1FA U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // Emoji modifier + regional indicator symbol
+ state.setByString("U+1F466 U+1F3FB U+1F1FA |");
+ backspace(state, 0);
+ state.assertEquals("U+1F466 U+1F3FB |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+}
diff --git a/core/tests/coretests/src/android/text/method/EditorState.java b/core/tests/coretests/src/android/text/method/EditorState.java
new file mode 100644
index 000000000000..bbbbd6dd52c4
--- /dev/null
+++ b/core/tests/coretests/src/android/text/method/EditorState.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 android.text.method;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ReplacementSpan;
+
+import junit.framework.Assert;
+
+/**
+ * Represents an editor state.
+ *
+ * The editor state can be specified by following string format.
+ * - Components are separated by space(U+0020).
+ * - Single-quoted string for printable ASCII characters, e.g. 'a', '123'.
+ * - U+XXXX form can be used for a Unicode code point.
+ * - Components inside '[' and ']' are in selection.
+ * - Components inside '(' and ')' are in ReplacementSpan.
+ * - '|' is for specifying cursor position.
+ *
+ * Selection and cursor can not be specified at the same time.
+ *
+ * Example:
+ * - "'Hello,' | U+0020 'world!'" means "Hello, world!" is displayed and the cursor position
+ * is 6.
+ * - "'abc' [ 'def' ] 'ghi'" means "abcdefghi" is displayed and "def" is selected.
+ * - "U+1F441 | ( U+1F441 U+1F441 )" means three U+1F441 characters are displayed and
+ * ReplacementSpan is set from offset 2 to 6.
+ */
+public class EditorState {
+ private static final String REPLACEMENT_SPAN_START = "(";
+ private static final String REPLACEMENT_SPAN_END = ")";
+ private static final String SELECTION_START = "[";
+ private static final String SELECTION_END = "]";
+ private static final String CURSOR = "|";
+
+ public Editable mText;
+ public int mSelectionStart = -1;
+ public int mSelectionEnd = -1;
+
+ public EditorState() {
+ }
+
+ /**
+ * A mocked {@link android.text.style.ReplacementSpan} for testing purpose.
+ */
+ private static class MockReplacementSpan extends ReplacementSpan {
+ public int getSize(Paint paint, CharSequence text, int start, int end,
+ Paint.FontMetricsInt fm) {
+ return 0;
+ }
+ public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+ int y, int bottom, Paint paint) {
+ }
+ }
+
+ // Returns true if the code point is ASCII and graph.
+ private boolean isGraphicAscii(int codePoint) {
+ return 0x20 < codePoint && codePoint < 0x7F;
+ }
+
+ // Setup editor state with string. Please see class description for string format.
+ public void setByString(String string) {
+ final StringBuilder sb = new StringBuilder();
+ int replacementSpanStart = -1;
+ int replacementSpanEnd = -1;
+ mSelectionStart = -1;
+ mSelectionEnd = -1;
+
+ final String[] tokens = string.split(" +");
+ for (String token : tokens) {
+ if (token.startsWith("'") && token.endsWith("'")) {
+ for (int i = 1; i < token.length() - 1; ++i) {
+ final char ch = token.charAt(1);
+ if (!isGraphicAscii(ch)) {
+ throw new IllegalArgumentException(
+ "Only printable characters can be in single quote. " +
+ "Use U+" + Integer.toHexString(ch).toUpperCase() + " instead");
+ }
+ }
+ sb.append(token.substring(1, token.length() - 1));
+ } else if (token.startsWith("U+")) {
+ final int codePoint = Integer.parseInt(token.substring(2), 16);
+ if (codePoint < 0 || 0x10FFFF < codePoint) {
+ throw new IllegalArgumentException("Invalid code point is specified:" + token);
+ }
+ sb.append(Character.toChars(codePoint));
+ } else if (token.equals(CURSOR)) {
+ if (mSelectionStart != -1 || mSelectionEnd != -1) {
+ throw new IllegalArgumentException(
+ "Two or more cursor/selection positions are specified.");
+ }
+ mSelectionStart = mSelectionEnd = sb.length();
+ } else if (token.equals(SELECTION_START)) {
+ if (mSelectionStart != -1) {
+ throw new IllegalArgumentException(
+ "Two or more cursor/selection positions are specified.");
+ }
+ mSelectionStart = sb.length();
+ } else if (token.equals(SELECTION_END)) {
+ if (mSelectionEnd != -1) {
+ throw new IllegalArgumentException(
+ "Two or more cursor/selection positions are specified.");
+ }
+ mSelectionEnd = sb.length();
+ } else if (token.equals(REPLACEMENT_SPAN_START)) {
+ if (replacementSpanStart != -1) {
+ throw new IllegalArgumentException(
+ "Only one replacement span is supported");
+ }
+ replacementSpanStart = sb.length();
+ } else if (token.equals(REPLACEMENT_SPAN_END)) {
+ if (replacementSpanEnd != -1) {
+ throw new IllegalArgumentException(
+ "Only one replacement span is supported");
+ }
+ replacementSpanEnd = sb.length();
+ } else {
+ throw new IllegalArgumentException("Unknown or invalid token: " + token);
+ }
+ }
+
+ if (mSelectionStart == -1 || mSelectionEnd == -1) {
+ if (mSelectionEnd != -1) {
+ throw new IllegalArgumentException(
+ "Selection start position doesn't exist.");
+ } else if (mSelectionStart != -1) {
+ throw new IllegalArgumentException(
+ "Selection end position doesn't exist.");
+ } else {
+ throw new IllegalArgumentException(
+ "At least cursor position or selection range must be specified.");
+ }
+ } else if (mSelectionStart > mSelectionEnd) {
+ throw new IllegalArgumentException(
+ "Selection start position appears after end position.");
+ }
+
+ final Spannable spannable = new SpannableString(sb.toString());
+
+ if (replacementSpanStart != -1 || replacementSpanEnd != -1) {
+ if (replacementSpanStart == -1) {
+ throw new IllegalArgumentException(
+ "ReplacementSpan start position doesn't exist.");
+ }
+ if (replacementSpanEnd == -1) {
+ throw new IllegalArgumentException(
+ "ReplacementSpan end position doesn't exist.");
+ }
+ if (replacementSpanStart > replacementSpanEnd) {
+ throw new IllegalArgumentException(
+ "ReplacementSpan start position appears after end position.");
+ }
+ spannable.setSpan(new MockReplacementSpan(), replacementSpanStart, replacementSpanEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ mText = Editable.Factory.getInstance().newEditable(spannable);
+ }
+
+ public void assertEquals(String string) {
+ EditorState expected = new EditorState();
+ expected.setByString(string);
+
+ Assert.assertEquals(expected.mText.toString(), mText.toString());
+ Assert.assertEquals(expected.mSelectionStart, mSelectionStart);
+ Assert.assertEquals(expected.mSelectionEnd, mSelectionEnd);
+ }
+}
+
diff --git a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
new file mode 100644
index 000000000000..4b4e7afdb636
--- /dev/null
+++ b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
@@ -0,0 +1,62 @@
+/*
+ * 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.method;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.text.format.DateUtils;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextViewActivity;
+
+import com.android.frameworks.coretests.R;
+
+public abstract class KeyListenerTestCase extends
+ ActivityInstrumentationTestCase2<TextViewActivity> {
+
+ protected TextViewActivity mActivity;
+ protected Instrumentation mInstrumentation;
+ protected EditText mTextView;
+
+ public KeyListenerTestCase() {
+ super(TextViewActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mInstrumentation = getInstrumentation();
+ mTextView = (EditText) mActivity.findViewById(R.id.textview);
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ // Ensure that the screen is on for this test.
+ mTextView.setKeepScreenOn(true);
+ }
+ });
+
+ assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
+ }
+
+ protected static KeyEvent getKey(int keycode, int metaState) {
+ long currentTime = System.currentTimeMillis();
+ return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode,
+ 0 /* repeat */, metaState);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivity.java b/core/tests/coretests/src/android/widget/TextViewActivity.java
index d4945ba94dd4..03358a826723 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivity.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivity.java
@@ -20,15 +20,58 @@ import com.android.frameworks.coretests.R;
import android.app.Activity;
import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
/**
* An activity for testing the TextView widget.
+ *
+ * This class is copied from {@link android.text.method.cts.KeyListenerCtsActivity} in
+ * CtsTextTestCase. The original class is located at
+ * cts/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
*/
public class TextViewActivity extends Activity {
+ private boolean mHasWindowFocus = false;
+ private Object mHasWindowFocusLock = new Object();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_view);
}
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (!hasFocus) {
+ Log.w("TextViewActivity", "TextViewActivity lost window focus");
+ }
+ synchronized(mHasWindowFocusLock) {
+ mHasWindowFocus = hasFocus;
+ mHasWindowFocusLock.notify();
+ }
+ }
+
+ /**
+ * Blocks the calling thread until the {@link KeyListenerCtsActivity} has window focus or the
+ * specified duration (in milliseconds) has passed.
+ */
+ public boolean waitForWindowFocus(long durationMillis) {
+ long elapsedMillis = SystemClock.elapsedRealtime();
+ synchronized(mHasWindowFocusLock) {
+ mHasWindowFocus = hasWindowFocus();
+ while (!mHasWindowFocus && durationMillis > 0) {
+ long newElapsedMillis = SystemClock.elapsedRealtime();
+ durationMillis -= (newElapsedMillis - elapsedMillis);
+ elapsedMillis = newElapsedMillis;
+ if (durationMillis > 0) {
+ try {
+ mHasWindowFocusLock.wait(durationMillis);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ return mHasWindowFocus;
+ }
+ }
}
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 d133a12cc141..ac020e48355a 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -20,11 +20,14 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Parcel;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LocaleList;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import android.view.inputmethod.InputMethodSubtype;
@@ -34,6 +37,10 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.isIn;
+import static org.hamcrest.Matchers.not;
+
public class InputMethodUtilsTest extends InstrumentationTestCase {
private static final boolean IS_AUX = true;
private static final boolean IS_DEFAULT = true;
@@ -184,6 +191,9 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+ final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN",
+ SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+ IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
@@ -217,7 +227,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
// selected no matter what locale is specified.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoEnUS);
subtypes.add(nonAutoEnGB);
subtypes.add(nonAutoJa);
@@ -230,7 +240,8 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_EN_US), imi);
assertEquals(1, result.size());
verifyEquality(autoSubtype, result.get(0));
}
@@ -239,7 +250,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// selected as long as there is no no automatic subtype
// (overridesImplicitlyEnabledSubtype:true) in the given list.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoEnUS); // locale == "en_US"
subtypes.add(nonAutoEnGB);
subtypes.add(nonAutoJa);
@@ -251,8 +262,8 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
- assertEquals(1, result.size());
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_EN_US), imi);
verifyEquality(nonAutoEnUS, result.get(0));
}
@@ -260,7 +271,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// selected as long as there is no automatic subtype
// (overridesImplicitlyEnabledSubtype:true) in the given list.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoEnUS);
subtypes.add(nonAutoEnGB); // locale == "en_GB"
subtypes.add(nonAutoJa);
@@ -271,7 +282,8 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_GB, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_EN_GB), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoEnGB, result.get(0));
}
@@ -281,7 +293,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// try to find a subtype whose language is equal to the language part of the given locale.
// Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoFrCA); // locale == "fr_CA"
subtypes.add(nonAutoJa);
subtypes.add(nonAutoFil);
@@ -292,13 +304,14 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_FR), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoFrCA, result.get(0));
}
// Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoFr); // locale == "fr"
subtypes.add(nonAutoJa);
subtypes.add(nonAutoFil);
@@ -309,7 +322,8 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR_CA, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_FR_CA), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoFrCA, result.get(0));
}
@@ -317,7 +331,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
// extra value is selected if and only if all other selected IMEs are not AsciiCapable.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoEnUS);
subtypes.add(nonAutoJa); // not ASCII capable
subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
@@ -327,7 +341,8 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_JA_JP, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_JA_JP), imi);
assertEquals(3, result.size());
verifyEquality(nonAutoJa, result.get(0));
verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
@@ -336,7 +351,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that 3-letter language code can be handled.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoEnUS);
subtypes.add(nonAutoFil);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -344,7 +359,8 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FIL_PH, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_FIL_PH), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoFil, result.get(0));
}
@@ -352,7 +368,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
// Also make sure that the first subtype will be used as the last-resort candidate.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoJa);
subtypes.add(nonAutoEnUS);
subtypes.add(nonAutoFil);
@@ -361,14 +377,15 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FI, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_FI), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoJa, result.get(0));
}
// Make sure that "in" and "id" conversion is taken into account.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoIn);
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -376,12 +393,13 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_IN), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoIn, result.get(0));
}
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoIn);
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -389,12 +407,13 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_ID), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoIn, result.get(0));
}
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoId);
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -402,12 +421,13 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_IN), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoId, result.get(0));
}
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoId);
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -415,10 +435,37 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_ID), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoId, result.get(0));
}
+
+ // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system
+ // provides multiple locales, we try to enable multiple subtypes.
+ {
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+ subtypes.add(nonAutoEnUS);
+ subtypes.add(nonAutoFrCA);
+ subtypes.add(nonAutoIn);
+ subtypes.add(nonAutoJa);
+ subtypes.add(nonAutoFil);
+ subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+ subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+ final InputMethodInfo imi = createDummyInputMethodInfo(
+ "com.android.apps.inputmethod.latin",
+ "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+ subtypes);
+ final ArrayList<InputMethodSubtype> result =
+ InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
+ assertThat(nonAutoFrCA, isIn(result));
+ assertThat(nonAutoEnUS, isIn(result));
+ assertThat(nonAutoJa, isIn(result));
+ assertThat(nonAutoIn, not(isIn(result)));
+ assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
+ assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
+ }
}
@SmallTest
@@ -445,7 +492,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
final boolean CHECK_COUNTRY = true;
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
"com.android.apps.inputmethod.latin",
@@ -477,7 +524,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that 3-letter language code ("fil") can be handled.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoFil);
final InputMethodInfo imi = createDummyInputMethodInfo(
"com.android.apps.inputmethod.latin",
@@ -504,7 +551,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that 3-letter language code ("fil_PH") can be handled.
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoFilPH);
final InputMethodInfo imi = createDummyInputMethodInfo(
"com.android.apps.inputmethod.latin",
@@ -531,7 +578,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that a subtype whose locale is "in" can be queried with "id".
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoIn);
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -550,7 +597,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// Make sure that a subtype whose locale is "id" can be queried with "in".
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(nonAutoId);
subtypes.add(nonAutoEnUS);
final InputMethodInfo imi = createDummyInputMethodInfo(
@@ -568,24 +615,11 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
}
}
- private ArrayList<InputMethodSubtype> callGetImplicitlyApplicableSubtypesLockedWithLocale(
- final Locale locale, final InputMethodInfo imi) {
- final Context context = getInstrumentation().getTargetContext();
- final Locale initialLocale = context.getResources().getConfiguration().locale;
- try {
- context.getResources().getConfiguration().setLocale(locale);
- return InputMethodUtils.getImplicitlyApplicableSubtypesLocked(context.getResources(),
- imi);
- } finally {
- context.getResources().getConfiguration().setLocale(initialLocale);
- }
- }
-
private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
final Locale systemLocale, final boolean isSystemReady, String... expectedImeNames) {
- final Context context = getInstrumentation().getTargetContext();
- final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesWithLocale(
- context, isSystemReady, preinstalledImes, systemLocale));
+ final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
+ final String[] actualImeNames = getPackageNames(
+ InputMethodUtils.getDefaultEnabledImes(context, isSystemReady, preinstalledImes));
assertEquals(expectedImeNames.length, actualImeNames.length);
for (int i = 0; i < expectedImeNames.length; ++i) {
assertEquals(expectedImeNames[i], actualImeNames[i]);
@@ -606,16 +640,16 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
}
}
- private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesWithLocale(
- final Context context, final boolean isSystemReady,
- final ArrayList<InputMethodInfo> imis, final Locale locale) {
- final Locale initialLocale = context.getResources().getConfiguration().locale;
- try {
- context.getResources().getConfiguration().setLocale(locale);
- return InputMethodUtils.getDefaultEnabledImes(context, isSystemReady, imis);
- } finally {
- context.getResources().getConfiguration().setLocale(initialLocale);
- }
+ private Context createTargetContextWithLocales(final LocaleList locales) {
+ final Configuration resourceConfiguration = new Configuration();
+ resourceConfiguration.setLocales(locales);
+ return getInstrumentation()
+ .getTargetContext()
+ .createConfigurationContext(resourceConfiguration);
+ }
+
+ private Resources getResourcesForLocales(Locale... locales) {
+ return createTargetContextWithLocales(new LocaleList(locales)).getResources();
}
private String[] getPackageNames(final ArrayList<InputMethodInfo> imis) {
@@ -692,7 +726,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
private static ArrayList<InputMethodInfo> getImesWithDefaultVoiceIme() {
ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -709,7 +743,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
private static ArrayList<InputMethodInfo> getImesWithoutDefaultVoiceIme() {
ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -720,7 +754,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
}
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -731,7 +765,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
}
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -739,7 +773,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
"dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
}
{
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -767,7 +801,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// a dummy Voice IME
{
final boolean isDefaultIme = false;
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX,
IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -778,7 +812,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// a dummy Hindi IME
{
final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString);
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
// TODO: This subtype should be marked as IS_ASCII_CAPABLE
subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
@@ -794,7 +828,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// a dummy Pinyin IME
{
final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -806,7 +840,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// a dummy Korean IME
{
final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -819,7 +853,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
{
final boolean isDefaultIme = contains(
new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
@@ -840,7 +874,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
// a dummy Japanese IME
{
final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
!IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
!IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
new file mode 100644
index 000000000000..b9c2da75f55c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.inputmethod;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.LocaleList;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class LocaleUtilsTest extends InstrumentationTestCase {
+
+ private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper =
+ new LocaleUtils.LocaleExtractor<Locale>() {
+ @Override
+ public Locale get(Locale source) {
+ return source;
+ }
+ };
+
+ @SmallTest
+ public void testFilterByLanguageEmptyLanguageList() throws Exception {
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("in"));
+ availableLocales.add(Locale.forLanguageTag("ja"));
+ availableLocales.add(Locale.forLanguageTag("fil"));
+
+ final LocaleList preferredLocales = LocaleList.getEmptyLocaleList();
+
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(0, dest.size());
+ }
+
+ @SmallTest
+ public void testFilterByLanguageEmptySource() throws Exception {
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("fr,en-US,ja-JP");
+
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(0, dest.size());
+ }
+
+ @SmallTest
+ public void testFilterByLanguageNullAvailableLocales() throws Exception {
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(null);
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(0, dest.size());
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(null);
+ availableLocales.add(null);
+ availableLocales.add(null);
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(0, dest.size());
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(null);
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ availableLocales.add(null);
+ availableLocales.add(null);
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "en-US"
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(null);
+ availableLocales.add(Locale.forLanguageTag("en"));
+ availableLocales.add(null);
+ availableLocales.add(null);
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "en"
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(null);
+ availableLocales.add(Locale.forLanguageTag("ja-JP"));
+ availableLocales.add(null);
+ availableLocales.add(null);
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(0, dest.size());
+ }
+ }
+
+ @SmallTest
+ public void testFilterByLanguage() throws Exception {
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("in"));
+ availableLocales.add(Locale.forLanguageTag("ja"));
+ availableLocales.add(Locale.forLanguageTag("fil"));
+
+ final LocaleList preferredLocales = LocaleList.forLanguageTags("fr,en-US,ja-JP");
+
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(3, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "fr-CA"
+ assertEquals(availableLocales.get(0), dest.get(1)); // "en-US"
+ assertEquals(availableLocales.get(3), dest.get(2)); // "ja"
+ }
+
+ @SmallTest
+ public void testFilterByLanguageTheSameLanguage() throws Exception {
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("en-US"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "en-US"
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("en"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "en"
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("en-CA"));
+ availableLocales.add(Locale.forLanguageTag("en-IN"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(2), dest.get(0)); // "en-IN"
+ }
+ {
+ final LocaleList preferredLocales =
+ LocaleList.forLanguageTags("en-AU,en-GB,en-US,en-IN");
+ final ArrayList<Locale> availableLocales = new ArrayList<>();
+ availableLocales.add(Locale.forLanguageTag("fr-CA"));
+ availableLocales.add(Locale.forLanguageTag("en-CA"));
+ availableLocales.add(Locale.forLanguageTag("en-NZ"));
+ availableLocales.add(Locale.forLanguageTag("en-BZ"));
+ final ArrayList<Locale> dest = new ArrayList<>();
+ LocaleUtils.filterByLanguage(availableLocales, sIdentityMapper, preferredLocales, dest);
+ assertEquals(1, dest.size());
+ assertEquals(availableLocales.get(1), dest.get(0)); // "en-CA"
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
new file mode 100644
index 000000000000..1c3cd3872d78
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -0,0 +1,745 @@
+/*
+ * 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.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsServTest extends TestCase {
+ private static final String TAG = "BatteryStatsServTest";
+
+ public static class TestServ extends BatteryStatsImpl.Uid.Pkg.Serv {
+ TestServ(MockBatteryStatsImpl bsi) {
+ super(bsi);
+ }
+
+ void populate() {
+ mStartTime = 1010;
+ mRunningSince = 2021;
+ mRunning = true;
+ mStarts = 4042;
+ mLaunchedTime = 5053;
+ mLaunchedSince = 6064;
+ mLaunched = true;
+ mLaunches = 8085;
+ mLoadedStartTime = 9096;
+ mLoadedStarts = 10017;
+ mLoadedLaunches = 11118;
+ mLastStartTime = 12219;
+ mLastStarts = 13310;
+ mLastLaunches = 14411;
+ mUnpluggedStartTime = 15512;
+ mUnpluggedStarts = 16613;
+ mUnpluggedLaunches = 17714;
+ }
+
+ long getStartTime() {
+ return mStartTime;
+ }
+
+ long getRunningSince() {
+ return mRunningSince;
+ }
+
+ void setRunning(boolean val) {
+ mRunning = val;
+ }
+
+ boolean getRunning() {
+ return mRunning;
+ }
+
+ int getStarts() {
+ return mStarts;
+ }
+
+ long getLaunchedTime() {
+ return mLaunchedTime;
+ }
+
+ long getLaunchedSince() {
+ return mLaunchedSince;
+ }
+
+ void setLaunched(boolean val) {
+ mLaunched = val;
+ }
+
+ boolean getLaunched() {
+ return mLaunched;
+ }
+
+ int getLaunches() {
+ return mLaunches;
+ }
+
+ long getLoadedStartTime() {
+ return mLoadedStartTime;
+ }
+
+ int getLoadedStarts() {
+ return mLoadedStarts;
+ }
+
+ int getLoadedLaunches() {
+ return mLoadedLaunches;
+ }
+
+ long getLastStartTime() {
+ return mLastStartTime;
+ }
+
+ int getLastStarts() {
+ return mLastStarts;
+ }
+
+ int getLastLaunches() {
+ return mLastLaunches;
+ }
+
+ long getUnpluggedStartTime() {
+ return mUnpluggedStartTime;
+ }
+
+ int getUnpluggedStarts() {
+ return mUnpluggedStarts;
+ }
+
+ int getUnpluggedLaunches() {
+ return mUnpluggedLaunches;
+ }
+ }
+
+ /**
+ * Test that the constructor and detach methods touch the time bast observer list.
+ */
+ @SmallTest
+ public void testConstructAndDetach() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+
+ TestServ serv = new TestServ(bsi);
+ Assert.assertTrue(bsi.getOnBatteryTimeBase().hasObserver(serv));
+
+ serv.detach();
+ Assert.assertFalse(bsi.getOnBatteryTimeBase().hasObserver(serv));
+ }
+
+ /**
+ * Test OnTimeStarted
+ */
+ @SmallTest
+ public void testOnTimeStarted() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+ serv.onTimeStarted(111111, 20000, 222222);
+ Assert.assertEquals(18989, serv.getUnpluggedStartTime());
+ Assert.assertEquals(4042, serv.getUnpluggedStarts());
+ Assert.assertEquals(8085, serv.getUnpluggedLaunches());
+
+ serv.populate();
+ serv.setRunning(false);
+ serv.onTimeStarted(111111, 20000, 222222);
+ Assert.assertEquals(1010, serv.getUnpluggedStartTime());
+ Assert.assertEquals(4042, serv.getUnpluggedStarts());
+ Assert.assertEquals(8085, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test parceling and unparceling.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ orig = new TestServ(bsi);
+ orig.populate();
+
+ Parcel parcel = Parcel.obtain();
+ orig.writeToParcelLocked(parcel);
+
+ parcel.setDataPosition(0);
+
+ TestServ serv = new TestServ(bsi);
+ serv.readFromParcelLocked(parcel);
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(0, serv.getLastStartTime());
+ Assert.assertEquals(0, serv.getLastStarts());
+ Assert.assertEquals(0, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test getLaunchTimeToNow()
+ */
+ @SmallTest
+ public void testLaunchTimeToNow() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+ Assert.assertEquals(8989, serv.getLaunchTimeToNowLocked(10000));
+
+ serv.populate();
+ serv.setLaunched(false);
+ Assert.assertEquals(5053, serv.getLaunchTimeToNowLocked(10000));
+
+ }
+
+ /**
+ * Test getStartTimeToNow()
+ */
+ @SmallTest
+ public void testStartTimeToNow() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+ Assert.assertEquals(18989, serv.getStartTimeToNowLocked(20000));
+
+ serv.populate();
+ serv.setRunning(false);
+ Assert.assertEquals(1010, serv.getStartTimeToNowLocked(20000));
+ }
+
+ /**
+ * Test startLaunchedLocked while not previously launched
+ */
+ @SmallTest
+ public void testStartLaunchedLockedWhileLaunched() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+ serv.startLaunchedLocked();
+
+ // No changes
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test startLaunchedLocked while previously launched
+ */
+ @SmallTest
+ public void testStartLaunchedLockedWhileNotLaunched() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(false);
+ serv.startLaunchedLocked();
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(777777L, serv.getLaunchedSince()); // <-- changed
+ Assert.assertTrue(serv.getLaunched()); // <-- changed
+ Assert.assertEquals(8086, serv.getLaunches()); // <-- changed
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopLaunchedLocked when not previously launched.
+ */
+ @SmallTest
+ public void testStopLaunchedLockedWhileNotLaunched() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(false);
+
+ serv.stopLaunchedLocked();
+
+ // No changes
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertFalse(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopLaunchedLocked when previously launched, with measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopLaunchedLockedWhileLaunchedNormal() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+
+ serv.stopLaunchedLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertFalse(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopLaunchedLocked when previously launched, with no measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopLaunchedLockedWhileLaunchedTooQuick() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 6064L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setLaunched(true);
+
+ serv.stopLaunchedLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertFalse(serv.getLaunched());
+ Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test startRunningLocked while previously running
+ */
+ @SmallTest
+ public void testStartRunningLockedWhileRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+
+ serv.startRunningLocked();
+
+ // no change
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test startRunningLocked while not previously launched
+ */
+ @SmallTest
+ public void testStartRunningLockedWhileNotRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(false);
+
+ serv.startRunningLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(777777L, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042+1, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopRunningLocked when previously launched, with measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopRunningLockedWhileRunningNormal() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 777777L;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+
+ serv.stopRunningLocked();
+
+ Assert.assertEquals(777777L-2021+1010, serv.getStartTime()); // <-- changed
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertFalse(serv.getRunning()); // <-- changed
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test stopRunningLocked when previously launched, with measurable time between
+ * start and stop.
+ */
+ @SmallTest
+ public void testStopRunningLockedWhileRunningTooQuick() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
+ @Override
+ public long getBatteryUptimeLocked() {
+ return 2021;
+ }
+ };
+ TestServ serv = new TestServ(bsi);
+
+ serv.populate();
+ serv.setRunning(true);
+
+ serv.stopRunningLocked();
+
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertFalse(serv.getRunning()); // <-- changed
+ Assert.assertEquals(4042-1, serv.getStarts()); // <-- changed
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test that getBatteryStats returns the BatteryStatsImpl passed in to the contstructor.
+ */
+ @SmallTest
+ public void testGetBatteryStats() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+
+ Assert.assertEquals(bsi, serv.getBatteryStats());
+ }
+
+ /**
+ * Test getLaunches
+ */
+ @SmallTest
+ public void testGetLaunches() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+
+ Assert.assertEquals(8085, serv.getLaunches(BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(8085-11118, serv.getLaunches(BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(8085-17714, serv.getLaunches(BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test getStartTime while running
+ */
+ @SmallTest
+ public void testGetStartTimeRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+ serv.setRunning(true);
+
+ final long startTimeToNow = 1010 + 20000 - 2021;
+
+ Assert.assertEquals(startTimeToNow,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(startTimeToNow-9096,
+ serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(startTimeToNow-15512,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+ /**
+ * Test getStartTime while not running
+ */
+ @SmallTest
+ public void testGetStartTimeNotRunning() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+ serv.setRunning(false);
+
+ final long startTimeToNow = 1010;
+
+ Assert.assertEquals(startTimeToNow,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(startTimeToNow-9096,
+ serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(startTimeToNow-15512,
+ serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertFalse(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+
+ /**
+ * Test getStarts
+ */
+ @SmallTest
+ public void testGetStarts() throws Exception {
+ MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
+ TestServ serv = new TestServ(bsi);
+ serv.populate();
+
+ Assert.assertEquals(4042, serv.getStarts(BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(4042-10017, serv.getStarts(BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(4042-16613, serv.getStarts(BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ // No change to fields
+ Assert.assertEquals(1010, serv.getStartTime());
+ Assert.assertEquals(2021, serv.getRunningSince());
+ Assert.assertTrue(serv.getRunning());
+ Assert.assertEquals(4042, serv.getStarts());
+ Assert.assertEquals(5053, serv.getLaunchedTime());
+ Assert.assertEquals(6064, serv.getLaunchedSince());
+ Assert.assertTrue(serv.getLaunched());
+ Assert.assertEquals(8085, serv.getLaunches());
+ Assert.assertEquals(9096, serv.getLoadedStartTime());
+ Assert.assertEquals(10017, serv.getLoadedStarts());
+ Assert.assertEquals(11118, serv.getLoadedLaunches());
+ Assert.assertEquals(12219, serv.getLastStartTime());
+ Assert.assertEquals(13310, serv.getLastStarts());
+ Assert.assertEquals(14411, serv.getLastLaunches());
+ Assert.assertEquals(15512, serv.getUnpluggedStartTime());
+ Assert.assertEquals(16613, serv.getUnpluggedStarts());
+ Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
new file mode 100644
index 000000000000..05aa53cacbc5
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -0,0 +1,15 @@
+package com.android.internal.os;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ BatteryStatsServTest.class,
+ BatteryStatsTimeBaseTest.class,
+ BatteryStatsTimerTest.class,
+ BatteryStatsUidTest.class,
+ })
+public class BatteryStatsTests {
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
new file mode 100644
index 000000000000..ab92f158db84
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -0,0 +1,339 @@
+/*
+ * 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.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsTimeBaseTest extends TestCase {
+ private static final String TAG = "BatteryStatsTimeBaseTest";
+
+ static class TestTimeBase extends BatteryStatsImpl.TimeBase {
+
+ public void populate(long uptime, long realtime, boolean running, long pastUptime,
+ long uptimeStart, long pastRealtime, long realtimeStart,
+ long unpluggedUptime, long unpluggedRealtime) {
+ mUptime = uptime;
+ mRealtime = realtime;
+ mRunning = running;
+ mPastUptime = pastUptime;
+ mUptimeStart = uptimeStart;
+ mPastRealtime = pastRealtime;
+ mRealtimeStart = realtimeStart;
+ mUnpluggedUptime = unpluggedUptime;
+ mUnpluggedRealtime = unpluggedRealtime;
+ }
+
+ public void verify(long uptime, long realtime, boolean running, long pastUptime,
+ long uptimeStart, long pastRealtime, long realtimeStart,
+ long unpluggedUptime, long unpluggedRealtime) {
+ Assert.assertEquals(uptime, mUptime);
+ Assert.assertEquals(realtime, mRealtime);
+ Assert.assertEquals(running, mRunning);
+ Assert.assertEquals(pastUptime, mPastUptime);
+ Assert.assertEquals(uptimeStart, mUptimeStart);
+ Assert.assertEquals(pastRealtime, mPastRealtime);
+ Assert.assertEquals(realtimeStart, mRealtimeStart);
+ Assert.assertEquals(unpluggedUptime, mUnpluggedUptime);
+ Assert.assertEquals(unpluggedRealtime, mUnpluggedRealtime);
+ }
+ }
+
+ /**
+ * Test the observers and the setRunning call.
+ */
+ @SmallTest
+ public void testRunning() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ // Toggle running once, to accumulate past uptime and past realtime
+ // so the test values aren't 0.
+ tb.setRunning(true, 100, 10000);
+ tb.setRunning(false, 200, 11000);
+ Assert.assertEquals(100, tb.getUptimeStart());
+ Assert.assertEquals(10000, tb.getRealtimeStart());
+
+ // Create some observers
+ BatteryStatsImpl.TimeBaseObs observer1 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+ BatteryStatsImpl.TimeBaseObs observer2 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+ BatteryStatsImpl.TimeBaseObs observer3 = Mockito.mock(BatteryStatsImpl.TimeBaseObs.class);
+
+ // Add them
+ tb.add(observer1);
+ tb.add(observer2);
+ tb.add(observer3);
+ Assert.assertTrue(tb.hasObserver(observer1));
+ Assert.assertTrue(tb.hasObserver(observer2));
+ Assert.assertTrue(tb.hasObserver(observer3));
+
+ // Remove one
+ tb.remove(observer3);
+ Assert.assertTrue(tb.hasObserver(observer1));
+ Assert.assertTrue(tb.hasObserver(observer2));
+ Assert.assertFalse(tb.hasObserver(observer3));
+
+ // Start running, make sure we get a started call on the two active observers
+ // and not the third.
+ tb.setRunning(true, 250, 14000);
+
+ Assert.assertTrue(tb.isRunning());
+
+ if (false) {
+ Log.d(TAG, "mUptimeStart=" + tb.getUptimeStart()
+ + " mRealtimeStart=" + tb.getRealtimeStart()
+ + " mUptime=" + tb.getUptime(250)
+ + " mRealtime=" + tb.getRealtime(14000)
+ + " isRunning=" + tb.isRunning());
+ }
+
+ Assert.assertEquals(250, tb.getUptimeStart());
+ Assert.assertEquals(14000, tb.getRealtimeStart());
+ Assert.assertEquals(100, tb.getUptime(250));
+ Assert.assertEquals(1000, tb.getRealtime(14000));
+
+ Mockito.verify(observer1).onTimeStarted(14000, 100, 1000);
+ Mockito.verify(observer1, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer1);
+ Mockito.verify(observer2).onTimeStarted(14000, 100, 1000);
+ Mockito.verify(observer2, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer2);
+
+ Mockito.reset(observer1);
+ Mockito.reset(observer2);
+ Mockito.reset(observer3);
+
+ // Advance the "timer" and make sure the getters account for the current time passed in
+ Assert.assertEquals(400, tb.getUptime(550));
+ Assert.assertEquals(1555, tb.getRealtime(14555));
+
+ // Stop running, make sure we get a stopped call on the two active observers
+ // and not the third.
+ tb.setRunning(false, 402, 14002);
+
+ Assert.assertFalse(tb.isRunning());
+
+ if (false) {
+ Log.d(TAG, "mUptimeStart=" + tb.getUptimeStart()
+ + " mRealtimeStart=" + tb.getRealtimeStart()
+ + " mUptime=" + tb.getUptime(250)
+ + " mRealtime=" + tb.getRealtime(14000)
+ + " isRunning=" + tb.isRunning());
+ }
+
+ Assert.assertEquals(252, tb.getUptime(402));
+ Assert.assertEquals(1002, tb.getRealtime(14002));
+
+ Mockito.verify(observer1).onTimeStopped(14002, 252, 1002);
+ Mockito.verify(observer1, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer1);
+ Mockito.verify(observer2).onTimeStopped(14002, 252, 1002);
+ Mockito.verify(observer2, Mockito.never()).onTimeStopped(-1, -1, -1);
+ Mockito.verifyNoMoreInteractions(observer2);
+
+ // Advance the "timer" and make sure the getters account for the current time passed in
+ // is the same as the time when running went to false.
+ Assert.assertEquals(252, tb.getUptime(600));
+ Assert.assertEquals(1002, tb.getRealtime(17000));
+ }
+
+ /**
+ * Test that reset while running updates the plugged and unplugged times
+ */
+ @SmallTest
+ public void testResetWhileRunning() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+ tb.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+ tb.reset(666, 6666);
+
+ // Not sure if this is a bug: reset while running does not
+ // reset mPastUptime, but while it is running it does.
+ tb.verify(100, 200, true, 300, 666, 500, 6666, 300, 500);
+ }
+
+ /**
+ * Test that reset while running updates the plugged and unplugged times
+ */
+ @SmallTest
+ public void testResetWhileNotRunning() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+ tb.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+ tb.reset(666, 6666);
+
+ tb.verify(100, 200, false, 0, 400, 0, 600, 700, 800);
+ }
+
+ /**
+ * Test init
+ */
+ @SmallTest
+ public void testInit() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+ tb.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+ tb.init(666, 6666);
+
+ tb.verify(0, 0, false, 0, 666, 0, 6666, 0, 0);
+ }
+
+ /**
+ * Test writeToParcel and readFromParcel
+ */
+ @SmallTest
+ public void testParcellingWhileRunning() throws Exception {
+ TestTimeBase tb1 = new TestTimeBase();
+
+ tb1.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+ Parcel parcel = Parcel.obtain();
+ tb1.writeToParcel(parcel, 666, 6666);
+
+ parcel.setDataPosition(0);
+
+ TestTimeBase tb2 = new TestTimeBase();
+ tb2.readFromParcel(parcel);
+
+ // Running is not preserved across parceling
+ tb2.verify(100, 200, false, 300+666-400, 400, 500+6666-600, 600, 700, 800);
+ }
+
+ /**
+ * Test writeToParcel and readFromParcel
+ */
+ @SmallTest
+ public void testParcellingWhileNotRunning() throws Exception {
+ TestTimeBase tb1 = new TestTimeBase();
+
+ tb1.populate(100, 200, false, 300, 400, 500, 600, 700, 800);
+
+ Parcel parcel = Parcel.obtain();
+ tb1.writeToParcel(parcel, 666, 6666);
+
+ parcel.setDataPosition(0);
+
+ TestTimeBase tb2 = new TestTimeBase();
+ tb2.readFromParcel(parcel);
+
+ tb2.verify(100, 200, false, 300, 400, 500, 600, 700, 800);
+ }
+
+ /**
+ * Test writeSummaryToParcel and readSummaryFromParcel
+ */
+ @SmallTest
+ public void testSummary() throws Exception {
+ TestTimeBase tb1 = new TestTimeBase();
+
+ tb1.populate(100, 200, true, 300, 400, 500, 600, 700, 800);
+
+ Parcel parcel = Parcel.obtain();
+ tb1.writeSummaryToParcel(parcel, 666, 6666);
+
+ parcel.setDataPosition(0);
+
+ TestTimeBase tb2 = new TestTimeBase();
+
+ // readSummaryFromParcel doesn't affect the other fields.
+ // Not sure if this is deliberate
+ tb2.populate(1, 2, true, 3, 4, 5, 6, 7, 8);
+
+ tb2.readSummaryFromParcel(parcel);
+
+ tb2.verify(666, 6766, true, 3, 4, 5, 6, 7, 8);
+ }
+
+ /**
+ * Test computeUptime
+ */
+ @SmallTest
+ public void testComputeUptime() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+ Assert.assertEquals(100+300+666-400,
+ tb.computeUptime(666, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(300+666-400,
+ tb.computeUptime(666, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(300+666-400-50,
+ tb.computeUptime(666, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ Assert.assertEquals(0, tb.computeUptime(666, 6000));
+ }
+
+ /**
+ * Test computeUptime
+ */
+ @SmallTest
+ public void testComputeRealtime() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+ Assert.assertEquals(200+500+6666-600,
+ tb.computeRealtime(6666, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(500+6666-600,
+ tb.computeRealtime(6666, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(500+6666-600-60,
+ tb.computeRealtime(6666, BatteryStats.STATS_SINCE_UNPLUGGED));
+
+ Assert.assertEquals(0, tb.computeUptime(666, 6000));
+ }
+
+ /**
+ * Test dump
+ */
+ @SmallTest
+ public void testDump() throws Exception {
+ TestTimeBase tb = new TestTimeBase();
+
+ tb.populate(100, 200, true, 300, 400, 500, 600, 50, 60);
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+
+ tb.dump(pw, "+++++ ");
+
+ pw.close();
+
+ // note the spaces at the ends of the lines which come from formatTimeMs.
+ final String CORRECT = "+++++ mRunning=true\n"
+ + "+++++ mUptime=0ms \n"
+ + "+++++ mRealtime=0ms \n"
+ + "+++++ mPastUptime=0ms mUptimeStart=0ms mUnpluggedUptime=0ms \n"
+ + "+++++ mPastRealtime=0ms mRealtimeStart=0ms mUnpluggedRealtime=0ms \n";
+
+ Assert.assertEquals(CORRECT, sw.toString());
+ }
+
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
new file mode 100644
index 000000000000..3e17fcb8843d
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -0,0 +1,487 @@
+/*
+ * 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.os;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.StringBuilderPrinter;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl.Clocks;
+import com.android.internal.os.BatteryStatsImpl.TimeBase;
+import com.android.internal.os.BatteryStatsImpl.Timer;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsTimerTest extends TestCase {
+ private static final String TAG = "BatteryStatsTest";
+
+ class TestTimer extends Timer {
+ long nextComputeRunTime;
+ long lastComputeRunTimeRealtime;
+
+ int nextComputeCurrentCount;
+
+ TestTimer(Clocks clocks, int type, TimeBase timeBase, Parcel in) {
+ super(clocks, type, timeBase, in);
+ }
+
+ TestTimer(Clocks clocks, int type, TimeBase timeBase) {
+ super(clocks, type, timeBase);
+ }
+
+ protected long computeRunTimeLocked(long curBatteryRealtime) {
+ lastComputeRunTimeRealtime = curBatteryRealtime;
+ return nextComputeRunTime;
+ }
+
+ protected int computeCurrentCountLocked() {
+ return nextComputeCurrentCount;
+ }
+
+ public int getCount() {
+ return mCount;
+ }
+
+ public void setCount(int val) {
+ mCount = val;
+ }
+
+ public int getLoadedCount() {
+ return mLoadedCount;
+ }
+
+ public void setLoadedCount(int val) {
+ mLoadedCount = val;
+ }
+
+ public int getLastCount() {
+ return mLastCount;
+ }
+
+ public void setLastCount(int val) {
+ mLastCount = val;
+ }
+
+ public int getUnpluggedCount() {
+ return mUnpluggedCount;
+ }
+
+ public void setUnpluggedCount(int val) {
+ mUnpluggedCount = val;
+ }
+
+ public long getTotalTime() {
+ return mTotalTime;
+ }
+
+ public void setTotalTime(long val) {
+ mTotalTime = val;
+ }
+
+ public long getLoadedTime() {
+ return mLoadedTime;
+ }
+
+ public void setLoadedTime(long val) {
+ mLoadedTime = val;
+ }
+
+ public long getLastTime() {
+ return mLastTime;
+ }
+
+ public void setLastTime(long val) {
+ mLastTime = val;
+ }
+
+ public long getUnpluggedTime() {
+ return mUnpluggedTime;
+ }
+
+ public void setUnpluggedTime(long val) {
+ mUnpluggedTime = val;
+ }
+
+ public long getTimeBeforeMark() {
+ return mTimeBeforeMark;
+ }
+
+ public void setTimeBeforeMark(long val) {
+ mTimeBeforeMark = val;
+ }
+ }
+
+ /**
+ * Tests that the flow through TimeBase.setRunning propagates through
+ * to the timer.
+ */
+ @SmallTest
+ public void testRunning() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.nextComputeCurrentCount = 3000;
+
+ // Test that starting the timer counts the unplugged time and counters
+ timer.nextComputeRunTime = 4;
+ timer.onTimeStarted(10, 20, 50);
+ Assert.assertEquals(50, timer.lastComputeRunTimeRealtime);
+ Assert.assertEquals(4, timer.getUnpluggedTime());
+ Assert.assertEquals(0, timer.getUnpluggedCount());
+
+ // Test that stopping the timer updates mTotalTime and mCount
+ timer.nextComputeRunTime = 17;
+ timer.onTimeStopped(100, 130, 170);
+ Assert.assertEquals(17, timer.getTotalTime());
+ Assert.assertEquals(3000, timer.getCount());
+ }
+
+ /**
+ * Tests that the parcel can be parceled and unparceled without losing anything.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ // Test write then read
+ TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
+ timer1.setCount(1);
+ timer1.setLoadedCount(2);
+ timer1.setLastCount(3);
+ timer1.setUnpluggedCount(4);
+ timer1.setTotalTime(9223372036854775807L);
+ timer1.setLoadedTime(9223372036854775806L);
+ timer1.setLastTime(9223372036854775805L);
+ timer1.setUnpluggedTime(9223372036854775804L);
+ timer1.setTimeBeforeMark(9223372036854775803L);
+ timer1.nextComputeRunTime = 201;
+
+ Parcel parcel = Parcel.obtain();
+ Timer.writeTimerToParcel(parcel, timer1, 77);
+
+ parcel.setDataPosition(0);
+ Assert.assertTrue("parcel null object", parcel.readInt() != 0);
+
+ TestTimer timer2 = new TestTimer(clocks, 0, timeBase, parcel);
+ Assert.assertEquals(1, timer2.getCount());
+ Assert.assertEquals(2, timer2.getLoadedCount());
+ Assert.assertEquals(0, timer2.getLastCount()); // NOT saved
+ Assert.assertEquals(4, timer2.getUnpluggedCount());
+ Assert.assertEquals(201, timer2.getTotalTime()); // from computeRunTimeLocked()
+ Assert.assertEquals(9223372036854775806L, timer2.getLoadedTime());
+ Assert.assertEquals(0, timer2.getLastTime()); // NOT saved
+ Assert.assertEquals(9223372036854775804L, timer2.getUnpluggedTime());
+ Assert.assertEquals(9223372036854775803L, timer2.getTimeBeforeMark());
+
+ parcel.recycle();
+ }
+
+ /**
+ * Tests that the parcel can be parceled and unparceled without losing anything.
+ */
+ @SmallTest
+ public void testParcelingNull() throws Exception {
+ // Test writing null
+ Parcel parcel = Parcel.obtain();
+ Timer.writeTimerToParcel(parcel, null, 88);
+
+ parcel.setDataPosition(0);
+ Assert.assertEquals(0, parcel.readInt());
+
+ parcel.recycle();
+ }
+
+ /**
+ * Tests that reset() clears the correct times.
+ */
+ @SmallTest
+ public void testResetNoDetach() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(9223372036854775807L);
+ timer.setLoadedTime(9223372036854775806L);
+ timer.setLastTime(9223372036854775805L);
+ timer.setUnpluggedTime(9223372036854775804L);
+ timer.setTimeBeforeMark(9223372036854775803L);
+
+ timer.reset(false);
+
+ Assert.assertEquals(0, timer.getCount());
+ Assert.assertEquals(0, timer.getLoadedCount());
+ Assert.assertEquals(0, timer.getLastCount());
+ Assert.assertEquals(4, timer.getUnpluggedCount());
+ Assert.assertEquals(0, timer.getTotalTime());
+ Assert.assertEquals(0, timer.getLoadedTime());
+ Assert.assertEquals(0, timer.getLastTime());
+ Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
+ Assert.assertEquals(0, timer.getTimeBeforeMark());
+
+ // reset(false) shouldn't remove it from the list
+ Assert.assertEquals(true, timeBase.hasObserver(timer));
+ }
+
+ /**
+ * Tests that reset() clears the correct times.
+ */
+ @SmallTest
+ public void testResetDetach() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(9223372036854775807L);
+ timer.setLoadedTime(9223372036854775806L);
+ timer.setLastTime(9223372036854775805L);
+ timer.setUnpluggedTime(9223372036854775804L);
+ timer.setTimeBeforeMark(9223372036854775803L);
+
+ timer.reset(true);
+
+ Assert.assertEquals(0, timer.getCount());
+ Assert.assertEquals(0, timer.getLoadedCount());
+ Assert.assertEquals(0, timer.getLastCount());
+ Assert.assertEquals(4, timer.getUnpluggedCount());
+ Assert.assertEquals(0, timer.getTotalTime());
+ Assert.assertEquals(0, timer.getLoadedTime());
+ Assert.assertEquals(0, timer.getLastTime());
+ Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
+ Assert.assertEquals(0, timer.getTimeBeforeMark());
+
+ // reset(true) should remove it from the list
+ Assert.assertEquals(false, timeBase.hasObserver(timer));
+ }
+
+ /**
+ * Tests reading and writing the summary to a parcel
+ */
+ @SmallTest
+ public void testSummaryParceling() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+ // the past uptime is 35 and the past runtime is 40
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
+ timer1.setCount(1);
+ timer1.setLoadedCount(2);
+ timer1.setLastCount(3);
+ timer1.setUnpluggedCount(4);
+ timer1.setTotalTime(9223372036854775807L);
+ timer1.setLoadedTime(9223372036854775806L);
+ timer1.setLastTime(9223372036854775805L);
+ timer1.setUnpluggedTime(9223372036854775804L);
+ timer1.setTimeBeforeMark(9223372036854775803L);
+
+ Parcel parcel = Parcel.obtain();
+ timer1.nextComputeRunTime = 9223372036854775800L;
+ timer1.writeSummaryFromParcelLocked(parcel, 201);
+ Assert.assertEquals(40, timer1.lastComputeRunTimeRealtime);
+
+ TestTimer timer2 = new TestTimer(clocks, 0, timeBase);
+
+ // Make sure that all the values get touched
+ timer2.setCount(666);
+ timer2.setLoadedCount(666);
+ timer2.setLastCount(666);
+ timer2.setUnpluggedCount(666);
+ timer2.setTotalTime(666);
+ timer2.setLoadedTime(666);
+ timer2.setLastTime(666);
+ timer2.setUnpluggedTime(666);
+ timer2.setTimeBeforeMark(666);
+
+ parcel.setDataPosition(0);
+
+ parcel.setDataPosition(0);
+ timer2.readSummaryFromParcelLocked(parcel);
+
+ Assert.assertEquals(1, timer2.getCount());
+ Assert.assertEquals(1, timer2.getLoadedCount());
+ Assert.assertEquals(0, timer2.getLastCount());
+ Assert.assertEquals(1, timer2.getUnpluggedCount());
+ Assert.assertEquals(9223372036854775800L, timer2.getTotalTime());
+ Assert.assertEquals(9223372036854775800L, timer2.getLoadedTime());
+ Assert.assertEquals(0, timer2.getLastTime());
+ Assert.assertEquals(9223372036854775800L, timer2.getUnpluggedTime());
+ Assert.assertEquals(9223372036854775800L, timer2.getTimeBeforeMark());
+
+ parcel.recycle();
+ }
+
+ /**
+ * Tests getTotalTimeLocked
+ */
+ @SmallTest
+ public void testGetTotalTimeLocked() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+
+ timer.nextComputeRunTime = 10000;
+
+ // Timer.getTotalTimeLocked(STATS_SINCE_CHARGED)
+ timer.lastComputeRunTimeRealtime = -1;
+ Assert.assertEquals(10000,
+ timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_CHARGED));
+ Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+
+ // Timer.getTotalTimeLocked(STATS_CURRENT)
+ timer.lastComputeRunTimeRealtime = -1;
+ Assert.assertEquals(9800, timer.getTotalTimeLocked(66, BatteryStats.STATS_CURRENT));
+ Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+
+ // Timer.getTotalTimeLocked(STATS_SINCE_UNPLUGGED)
+ timer.lastComputeRunTimeRealtime = -1;
+ Assert.assertEquals(9600, timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_UNPLUGGED));
+ Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
+ }
+
+ /**
+ * Tests getCountLocked
+ */
+ @SmallTest
+ public void testGetCountLocked() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+
+ // Timer.getCountLocked(STATS_SINCE_CHARGED)
+ timer.nextComputeCurrentCount = 10000;
+ Assert.assertEquals(10000, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+ // Timer.getCountLocked(STATS_CURRENT)
+ timer.nextComputeCurrentCount = 10000;
+ Assert.assertEquals(9998, timer.getCountLocked(BatteryStats.STATS_CURRENT));
+
+ // Timer.getCountLocked(STATS_SINCE_UNPLUGGED)
+ timer.nextComputeCurrentCount = 10000;
+ Assert.assertEquals(9996, timer.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
+ }
+
+ /**
+ * Tests getTimeSinceMarkLocked
+ */
+ @SmallTest
+ public void testGetTimeSinceMarked() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ timeBase.setRunning(true, 10, 20);
+ timeBase.setRunning(false, 45, 60);
+ Assert.assertEquals(40, timeBase.getRealtime(200));
+
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+
+ timer.nextComputeRunTime = 10000;
+ Assert.assertEquals(9500, timer.getTimeSinceMarkLocked(666));
+ }
+
+ /**
+ * Tests logState
+ */
+ @SmallTest
+ public void testLogState() throws Exception {
+ TimeBase timeBase = new TimeBase();
+ MockClocks clocks = new MockClocks();
+
+ TestTimer timer = new TestTimer(clocks, 0, timeBase);
+ timer.setTotalTime(100);
+ timer.setLoadedTime(200);
+ timer.setLastTime(300);
+ timer.setUnpluggedTime(400);
+ timer.setTimeBeforeMark(500);
+ timer.setCount(1);
+ timer.setLoadedCount(2);
+ timer.setLastCount(3);
+ timer.setUnpluggedCount(4);
+ timer.setTotalTime(9223372036854775807L);
+ timer.setLoadedTime(9223372036854775806L);
+ timer.setLastTime(9223372036854775805L);
+ timer.setUnpluggedTime(9223372036854775804L);
+ timer.setTimeBeforeMark(9223372036854775803L);
+
+ StringBuilder sb = new StringBuilder();
+ StringBuilderPrinter pw = new StringBuilderPrinter(sb);
+
+ timer.logState(pw, " ");
+
+ Assert.assertEquals(
+ " mCount=1 mLoadedCount=2 mLastCount=3 mUnpluggedCount=4\n"
+ + " mTotalTime=9223372036854775807 mLoadedTime=9223372036854775806\n"
+ + " mLastTime=9223372036854775805 mUnpluggedTime=9223372036854775804\n",
+ sb.toString());
+ }
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
new file mode 100644
index 000000000000..a7e75a248eda
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for android.os.BatteryStats.
+ */
+public class BatteryStatsUidTest extends TestCase {
+ private static final String TAG = "BatteryStatsTimeBaseTest";
+
+ static class TestBsi extends BatteryStatsImpl {
+ TestBsi(MockClocks clocks) {
+ super(clocks);
+ }
+ }
+
+ /**
+ * Test the observers and the setRunning call.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ }
+}
+
diff --git a/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 7088650792ef..392448976229 100644
--- a/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2010 The Android Open Source Project
+/*
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,30 +14,38 @@
* limitations under the License.
*/
-package com.android.internal.util;
+package com.android.internal.os;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
-import android.os.Debug;
+import android.os.BatteryStats;
+import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import junit.framework.Assert;
import junit.framework.TestCase;
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.mockito.Mockito;
+
/**
- * Test for AsyncChannel.
+ * Mocks a BatteryStatsImpl object.
*/
-public class AsyncChannelTest extends TestCase {
- private static final boolean DBG = true;
- private static final boolean WAIT_FOR_DEBUGGER = false;
- private static final String TAG = "AsyncChannelTest";
-
- @SmallTest
- public void test1() throws Exception {
- if (DBG) log("test1");
- if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
- assertTrue(1 == 1);
+public class MockBatteryStatsImpl extends BatteryStatsImpl {
+ public BatteryStatsImpl.Clocks clocks;
+
+ MockBatteryStatsImpl() {
+ super(new MockClocks());
+ this.clocks = mClocks;
}
- protected void log(String s) {
- Log.d(TAG, s);
+ public TimeBase getOnBatteryTimeBase() {
+ return mOnBatteryTimeBase;
}
+
}
+
diff --git a/core/tests/coretests/src/com/android/internal/os/MockClocks.java b/core/tests/coretests/src/com/android/internal/os/MockClocks.java
new file mode 100644
index 000000000000..f750c3746d26
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MockClocks.java
@@ -0,0 +1,32 @@
+/*
+ * 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.os;
+
+public class MockClocks implements BatteryStatsImpl.Clocks {
+ public long realtime;
+ public long uptime;
+
+ @Override
+ public long elapsedRealtime() {
+ return realtime;
+ }
+
+ @Override
+ public long uptimeMillis() {
+ return uptime;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
index 49ae10401983..4845c4ef28f8 100644
--- a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -180,6 +180,22 @@ public class LineBreakBufferedWriterTest extends TestCase {
assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
}
+ public void testMoreThenInitialCapacitySimpleWrites() {
+ // This check is different from testMoreThanBufferSizeChar. The initial capacity is lower
+ // than the maximum buffer size here.
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 1024, 3);
+
+ for(int i = 0; i < 10; i++) {
+ lw.print('$');
+ }
+ for(int i = 0; i < 10; i++) {
+ lw.print('%');
+ }
+ lw.flush();
+
+ assertOutput("$$$$$$$$$$%%%%%%%%%%");
+ }
+
private void assertOutput(String... golden) {
List<String> goldList = createTestGolden(golden);
assertEquals(goldList, mWriter.getStrings());
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index edeecb2f62c3..26f768b96f11 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -29,6 +29,8 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
LOCAL_DEX_PREOPT := false
+LOCAL_JAVACFLAGS := -nowarn
+
mainDexList:= \
$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java
index 5e931bc86375..8d065a43ac61 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/Test.java
@@ -15,14 +15,13 @@
*/
package com.android.multidexlegacyandexception;
-import android.test.ActivityInstrumentationTestCase2;
-
/**
* Run the tests with: <code>adb shell am instrument -w
com.android.multidexlegacyandexception/android.test.InstrumentationTestRunner
</code>
*/
-public class Test extends ActivityInstrumentationTestCase2<MainActivity> {
+@SuppressWarnings("deprecation")
+public class Test extends android.test.ActivityInstrumentationTestCase2<MainActivity> {
public Test() {
super(MainActivity.class);
}
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
index ff5a5359af12..994131a22ab3 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
@@ -32,6 +32,8 @@ LOCAL_SRC_FILES:= \
# All of the shard libraries we link against.
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 67b12d775828..99cf587af2a6 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
static jint
-add(JNIEnv *env, jobject thiz, jint a, jint b) {
+add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
ALOGI("%d + %d = %d", a, b, result);
return result;
@@ -82,7 +82,7 @@ typedef union {
void* venv;
} UnionJNIEnvToVoid;
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
index abb1d9f6ca9f..6c2679b30bfb 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
@@ -34,6 +34,8 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libutils liblog
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index 342b3bc0ac9a..0b6d7501dcae 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
static jint
-add(JNIEnv *env, jobject thiz, jint a, jint b) {
+add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
ALOGI("%d + %d = %d", a, b, result);
return result;
@@ -82,7 +82,7 @@ typedef union {
void* venv;
} UnionJNIEnvToVoid;
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
index ae8e636caf4b..d668f29456c8 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
@@ -33,6 +33,8 @@ LOCAL_SRC_FILES:= \
LOCAL_LDLIBS = -llog
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 9b38e3e4c437..3947e21a77bd 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
static jint
-add(JNIEnv *env, jobject thiz, jint a, jint b) {
+add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
ALOGI("%d + %d = %d", a, b, result);
return result;
@@ -82,7 +82,7 @@ typedef union {
void* venv;
} UnionJNIEnvToVoid;
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index 9f01a28fd332..0c20876c6520 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -12,6 +12,7 @@ LOCAL_DX_FLAGS := --core-library
LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
LOCAL_CERTIFICATE := platform
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
new file mode 100644
index 000000000000..3c6c32ec0d27
--- /dev/null
+++ b/core/tests/utiltests/Android.mk
@@ -0,0 +1,24 @@
+#########################################################################
+# Build FrameworksUtilTests package
+#########################################################################
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ mockito-target
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworksUtilTests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/utiltests/AndroidManifest.xml b/core/tests/utiltests/AndroidManifest.xml
new file mode 100644
index 000000000000..fecaf8e20c3f
--- /dev/null
+++ b/core/tests/utiltests/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.utiltests">
+
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+ <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.utiltests"
+ android:label="Frameworks Utility Tests" />
+
+</manifest>
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index 433d4d214b97..433d4d214b97 100644
--- a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java b/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
index 306f58fcce2e..306f58fcce2e 100644
--- a/core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
index c53f4cc7ee52..c53f4cc7ee52 100644
--- a/core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
index 55d186c292f6..55d186c292f6 100644
--- a/core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
index be7116dffb89..5f36c2d0c29b 100644
--- a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
@@ -42,6 +42,6 @@ public class FastXmlSerializerTest extends TestCase {
out.endDocument();
assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- + "<string name=\"meow\"></string>", stream.toString());
+ + "<string name=\"meow\"></string>\n", stream.toString());
}
}
diff --git a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
index 3f9e62e7b180..3f9e62e7b180 100644
--- a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java b/core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java
index 67736124f175..67736124f175 100644
--- a/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java
diff --git a/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
new file mode 100644
index 000000000000..32b969a8d1b5
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.*;
+
+import com.android.internal.util.MessageUtils;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+
+import org.junit.Test;
+
+
+class A {
+ // Should not see these.
+ private int mMember;
+ public final int CMD_NOT_STATIC = 7;
+ private static final String CMD_NOT_INT = "not an integer";
+ public static int CMD_NOT_FINAL = 34;
+ public static final int kWrongPrefix = 99;
+
+ // Should see these.
+ private static final int CMD_DO_SOMETHING = 12;
+ public static final int EVENT_SOMETHING_HAPPENED = 45;
+}
+
+class B {
+ public static final int CMD_FOO = 56;
+ public static final int EVENT_BAR = 55;
+ public static final int NOTIFICATION_BAZ = 12;
+}
+
+/**
+ * Unit tests for {@link com.android.util.MessageUtils}.
+ */
+@SmallTest
+public class MessageUtilsTest {
+
+ private static final Class[] CLASSES = { A.class, B.class };
+
+ private SparseArray<String> makeSparseArray(int[] keys, String[] values) throws Exception {
+ assertEquals("Must specify same number of keys and values", keys.length, values.length);
+ SparseArray<String> out = new SparseArray<>();
+ for (int i = 0; i < keys.length; i++) {
+ out.put(keys[i], values[i]);
+ }
+ return out;
+ }
+
+ private void assertSparseArrayEquals(
+ SparseArray<String> a1, SparseArray<String> a2) throws Exception {
+ String msg = String.format("%s != %s", a1.toString(), a2.toString());
+ assertEquals(msg, a1.size(), a2.size());
+ int size = a1.size();
+ for (int i = 0; i < size; i++) {
+ assertEquals(msg, a1.keyAt(i), a2.keyAt(i));
+ assertEquals(msg, a1.valueAt(i), a2.valueAt(i));
+ }
+ }
+
+ @Test
+ public void basicOperation() throws Exception {
+ SparseArray<String> expected = makeSparseArray(
+ new int[]{12, 45, 55, 56},
+ new String[]{"CMD_DO_SOMETHING", "EVENT_SOMETHING_HAPPENED", "EVENT_BAR", "CMD_FOO"});
+ assertSparseArrayEquals(expected, MessageUtils.findMessageNames(CLASSES));
+ }
+
+ @Test
+ public void withPrefixes() throws Exception {
+ SparseArray<String> expected = makeSparseArray(
+ new int[]{45, 55},
+ new String[]{"EVENT_SOMETHING_HAPPENED", "EVENT_BAR"});
+ assertSparseArrayEquals(expected, MessageUtils.findMessageNames(CLASSES,
+ new String[]{"EVENT_"}));
+ }
+
+ @Test(expected=MessageUtils.DuplicateConstantError.class)
+ public void duplicateConstants() {
+ MessageUtils.findMessageNames(CLASSES, new String[]{"CMD_", "NOTIFICATION_"});
+ }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/PredicatesTest.java b/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
index c46ff051dd33..c46ff051dd33 100644
--- a/core/tests/coretests/src/com/android/internal/util/PredicatesTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
index b6da1954ba79..b6da1954ba79 100644
--- a/core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index 302aa879b694..302aa879b694 100644
--- a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
new file mode 100644
index 000000000000..da8bc1d0945d
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Unit tests for {@link com.android.internal.util.WakeupMessage}.
+ */
+@SmallTest
+public class WakeupMessageTest {
+ private static final String TEST_CMD_NAME = "TEST cmd Name";
+ private static final int TEST_CMD = 18;
+ private static final int TEST_ARG1 = 33;
+ private static final int TEST_ARG2 = 182;
+
+ @Mock AlarmManager mAlarmManager;
+ WakeupMessage mMessage;
+ // Make a spy so that we can verify calls to it
+ @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler();
+
+ ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+
+ /**
+ * A Handler that will capture the most recent message sent to it.
+ *
+ * This handler is setup on the main Looper
+ */
+ public static class MessageCapturingHandler extends Handler {
+ private Message mLastMessage;
+
+ public MessageCapturingHandler() {
+ super(Looper.getMainLooper(), /* Nothing is actually dispatched on this Looper */
+ null, false);
+ }
+
+ @Override
+ public void handleMessage(Message m) {
+ // need to copy since it will be recycled after this method returns
+ mLastMessage = Message.obtain(m);
+ }
+
+ public Message getLastMessage() {
+ return mLastMessage;
+ }
+ }
+
+ /**
+ * Sets up the test.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ Context context = mock(Context.class);
+ when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+ // capture the listener for each AlarmManager.setExact call
+ doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class),
+ mListenerCaptor.capture(), any(Handler.class));
+
+ mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
+ TEST_ARG2);
+ }
+
+ /**
+ * Ensure the test is cleaned up and ready for the next test.
+ */
+ @After
+ public void cleanup() {
+ validateMockitoUsage();
+ }
+
+ private void scheduleAndVerifyAlarm(long when) {
+ mMessage.schedule(when);
+ verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
+ eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
+ }
+
+ private void verifyMessageDispatchedOnce() {
+ verify(mHandler, times(1)).handleMessage(any(Message.class));
+ assertEquals("what", TEST_CMD, mHandler.getLastMessage().what);
+ assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1);
+ assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2);
+ }
+
+ /**
+ * Schedule and deliver a single message
+ */
+ @Test
+ public void scheduleAndDeliverMessage() {
+ final long when = 1001;
+ scheduleAndVerifyAlarm(when);
+ verify(mHandler, never()).handleMessage(any(Message.class));
+ mListenerCaptor.getValue().onAlarm();
+ verifyMessageDispatchedOnce();
+ }
+
+ /**
+ * Check that the message is not delivered if cancel is called it after its alarm fires but
+ * before onAlarm is called.
+ *
+ * This ensures that if cancel is called on the handler thread, any previously-scheduled message
+ * is guaranteed not to be delivered.
+ */
+ @Test
+ public void scheduleAndCancelMessage() {
+ final long when = 1010;
+ scheduleAndVerifyAlarm(when);
+ mMessage.cancel();
+ mListenerCaptor.getValue().onAlarm();
+ verify(mHandler, never()).handleMessage(any(Message.class));
+ }
+
+ /**
+ * Verify nothing happens when cancel is called without a schedule
+ */
+ @Test
+ public void cancelWithoutSchedule() {
+ mMessage.cancel();
+ }
+
+ /**
+ * Verify that the message is silently rescheduled if schedule is called twice without the
+ * message being dispatched first.
+ */
+ @Test
+ public void scheduleTwiceWithoutMessageDispatched() {
+ final long when1 = 1011;
+ final long when2 = 1012;
+ scheduleAndVerifyAlarm(when1);
+ scheduleAndVerifyAlarm(when2);
+ mListenerCaptor.getValue().onAlarm();
+ verifyMessageDispatchedOnce();
+ }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
index 2596ecefe53d..2596ecefe53d 100644
--- a/core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
diff --git a/docs/html/guide/components/services.jd b/docs/html/guide/components/services.jd
index 8da1694b77b5..4053769995b3 100644
--- a/docs/html/guide/components/services.jd
+++ b/docs/html/guide/components/services.jd
@@ -336,14 +336,11 @@ public class HelloIntentService extends IntentService {
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
- long endTime = System.currentTimeMillis() + 5*1000;
- while (System.currentTimeMillis() &lt; endTime) {
- synchronized (this) {
- try {
- wait(endTime - System.currentTimeMillis());
- } catch (Exception e) {
- }
- }
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ // Restore interrupt status.
+ Thread.currentThread().interrupt();
}
}
}
@@ -405,14 +402,11 @@ public class HelloService extends Service {
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
- long endTime = System.currentTimeMillis() + 5*1000;
- while (System.currentTimeMillis() &lt; endTime) {
- synchronized (this) {
- try {
- wait(endTime - System.currentTimeMillis());
- } catch (Exception e) {
- }
- }
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ // Restore interrupt status.
+ Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index f3f2e5e7e780..e99c15a14e6f 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -631,6 +631,16 @@
</ul>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/security/index.html">
+ <span class="en">Security</span>
+ </a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/topics/security/security-config.html">
+ <span class="en">Network Security Config</span>
+ </a></li>
+ </ul>
+ </li>
</ul>
diff --git a/docs/html/guide/topics/security/index.jd b/docs/html/guide/topics/security/index.jd
new file mode 100644
index 000000000000..22fb775c47f8
--- /dev/null
+++ b/docs/html/guide/topics/security/index.jd
@@ -0,0 +1,7 @@
+page.title=Security
+page.landing=true
+page.landing.intro=Configure the security of your application.
+
+@jd:body
+<div class="landing-docs">
+</div>
diff --git a/docs/html/guide/topics/security/security-config.jd b/docs/html/guide/topics/security/security-config.jd
new file mode 100644
index 000000000000..4cee2536b904
--- /dev/null
+++ b/docs/html/guide/topics/security/security-config.jd
@@ -0,0 +1,539 @@
+page.title=Network Security Config
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+<li><a href="#SupportedFeatures">Features</a></li>
+<li><a href="#Examples">Examples</a>
+ <ol>
+ <li><a href="#TrustingCustomCas">Trusting Custom CAs</a>
+ <ol>
+ <li><a href="#TrustingACustomCa">Trusting a Custom CA</a></li>
+ <li><a href="#LimitingCas">Limiting the Set of Trusted CAs</a></li>
+ <li><a href="#TrustingAdditionalCas">Trusting Additional CAs</a></li>
+ </ol>
+ </li>
+ <li><a href="#TrustingDebugCa">Debugging-only CAs</a></li>
+ <li><a href="#UsesCleartextTraffic">Cleartext Traffic Opt-Out</a></li>
+ <li><a href="#CertificatePinning">Certificate Pinning</a></li>
+ <li><a href="#ConfigInheritance">Configuration Inheritance</a></li>
+ </ol>
+</li>
+<li><a href="#FileFormat">Configuration File Format</a></li>
+</ol>
+</div>
+</div>
+
+<p>The Android Network Security Config lets apps customize their network security settings
+in a safe, declarative configuration file without modifying application code.
+These settings can be configured for specific domains and app-wide.</p>
+
+<h2 id="SupportedFeatures">Features</h2>
+<ul>
+<li><b>Custom trust anchors.</b> Lets an application customize which Certificate Authorities (CA) are trusted
+for its secure connections. For example, trusting particular self-signed certificates or restricting the set of public
+CAs that the app trusts.
+</li>
+<li><b>Debug-only overrides.</b> Lets an application developer safely debug secure connections of their
+application without added risk to the installed base.
+</li>
+<li><b>Cleartext traffic opt-out.</b> Lets an application protect itself from accidental usage of cleartext traffic.</li>
+<li><b>Certificate pinning.</b> An advanced feature that lets an application restrict pin its secure connection
+to particular certificates.</li>
+</ul>
+
+<h2 id="Examples">Examples</h2>
+<h3 id="TrustingCustomCas">Trusting Custom CAs</h3>
+<p>An application may want to trust a custom set of CAs instead of the platform
+default. The most common reasons of this are:
+<ul>
+<li>Connecting to a host with a custom certificate authority(self-signed, issued by an internal corporate CA, etc).</li>
+<li>Limiting the set of CAs to only the CAs you trust instead of every preinstalled CA.</li>
+<li>Trusting additional CAs not included in the system.</li>
+</ul>
+</p>
+<p>By default secure (e.g. TLS, HTTPS) connections from all applications trust the pre-installed system CAs, and
+applications targeting API level 23 (Android M) and below also trust the user-added CA store by default.
+An application can customize its own connections using {@code base-config} (for app-wide customization) or
+{@code domain-config} (for per-domain customization).</p>
+
+<h4 id="TrustingACustomCa">Trusting a Custom CA</h4>
+<p>Assume you want to connect to your host which uses a self-signed SSL certificate or to
+a host whose SSL certificate is issued by a non-public CA which you trust, e.g., your company's internal
+CA.</p>
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;domain-config&gt;
+ &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="@raw/my_ca"/&gt;
+ &lt;/trust-anchors&gt;
+ &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>Add the self-signed or non-public CA certificate, in PEM or DER format, to {@code res/raw/my_ca}.</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+<h4 id="LimitingCas">Limiting the Set of Trusted CAs</h4>
+<p>An application that does not want to trust all CAs trusted by system can instead specify its own
+reduced set of CAs to trust. This protects the application from fradulent certificates issued by any
+of the other CAs.</p>
+
+<p>The config to limit the set of trusted CAs is similar to <a href="#TrustingACustomCa">trusting a custom CA</a>
+for a specific domain except that multiple CAs are provided in the resource.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;domain-config&gt;
+ &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+ &lt;domain includeSubdomains="true"&gt;cdn.example.com&lt;/domain&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="@raw/trusted_roots"/&gt;
+ &lt;/trust-anchors&gt;
+ &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>Add the trusted CAs, in PEM or DER format, to {@code res/raw/trusted_roots}.
+Note that if using PEM format the file must contain <em>only</em> PEM data and no extra text.
+You can also provide multiple <a href="certificates"><code>&lt;certificates&gt;</code></a> elements instead
+of one.</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+
+<h4 id="TrustingAdditionalCas">Trusting Additional CAs</h4>
+<p>An application may want to trust additional CAs not trusted by the system, this could be due to
+the system not yet including the CA or a CA that does not meet the requirements for inclusion into
+the Android system. An application can do this by specifying multiple certificate sources for a configuration.
+</p>
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;base-config&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="@raw/extracas"/&gt;
+ &lt;certificates src="system"/&gt;
+ &lt;/trust-anchors&gt;
+ &lt;/base-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+
+<h3 id="TrustingDebugCa">Debugging-only CAs</h3>
+<p>When debugging an application that connects over HTTPS you may want to connect to a local development
+server, which does not have the SSL certificate for your production server. In order to support this
+without any modification to your application's code you can specify debug-only CAs that are
+<i>only</i> trusted when <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
+is {@code true} by using {@code debug-overrides}. Normally IDEs and build tools set this flag automatically for non-release builds.</p>
+<p>This is safer than the usual conditional code because, as a security precaution, application stores
+do not accept applications which are marked debuggable.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;debug-overrides&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="@raw/debug_cas"/&gt;
+ &lt;/trust-anchors&gt;
+ &lt;/debug-overrides&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+
+<h3 id="UsesCleartextTraffic">Cleartext Traffic Opt-Out</h3>
+<p>Applications which intend to connect to destinations using only secure connections can opt-out
+of supporting cleartext (i.e. plain HTTP instead of HTTPS) to those destinations. This helps prevent
+accidental regressions in applications due to changes in URLs provided by external sources such as
+backend servers.</p>
+<p>See {a href="{@docRoot}reference/android/security/NetworkSecurityPolicy.html#isCleartextTrafficPermitted()} for more details.</p>
+
+<p>For example, an application may want to ensure that all connections to {@code secure.example.com} are always
+done over HTTPS to protect sensitive traffic from hostile networks.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;domain-config usesCleartextTraffic="false"&gt;
+ &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+ &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+
+<h3 id="CertificatePinning">Certificate Pinning</h3>
+<p>Normally an application trusts all preinstalled CAs. If any of these CAs were to issue a fradulent certificate
+the application would be at risk from a MiTM attack. Some applications choose to limit the set of
+certificates they accept by either limiting the set of CAs they trust or by certificate pinning.</p>
+
+<p>Certificate pinning is done by providing a set of certificates by hash of the public key (SubjectPublicKeyInfo
+of the X.509 certificate). A certificate chain is then only valid if the certificate chain contains at least
+one of the pinned public keys.</p>
+
+<p>Note that when using certificate pinning you should always include a backup key so that if you
+are forced to switch to new keys, or change CAs (when pinning to a CA certificate or an intermediate of that CA),
+your application's connectivity is unaffected. Otherwise you will have to push out an update to the
+application to restore connectivity.</p>
+
+<p>Additionally it is possible to set an expiration time for pins after which pinning will not be
+performed. This helps prevent connectivity issues in applications which have not been updated.
+However, setting an expiration time on pins may enable pinning bypass.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;domain-config&gt;
+ &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+ &lt;pin-set expiration="2018-01-01"&gt;
+ &lt;pin digest="SHA-256"&gt;7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=&lt;/pin&gt;
+ &lt;!-- backup pin --&gt
+ &lt;pin digest="SHA-256"&gt;fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=&lt;/pin&gt;
+ &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+
+<h3 id="ConfigInheritance">Configuration Inheritance</h3>
+<p>Values not set in a specific config will be inherited.
+This allows more complex configurations while keeping the configuration file readable.</p>
+
+<p>If a value is not set in a specific entry then value from the next more general entry will be used.
+Values not set in a {@code domain-config} will be taken from the parent {@code domain-config}, if nested, or
+from the {@code base-config} if not. Values not set in the {@code base-config} will use
+the platform default values.
+
+<p>For example consider, where all connections to subdomains of {@code example.com}
+must use a custom set of CAs. Additonally cleartext traffic to these domains is permitted
+<em>except</em> when connecting to {@code secure.example.com}. By nesting the configuration
+for {@code secure.example.com} inside the configuration for {@code example.com} the
+{@code trust-anchors} does not need to be duplicated.</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;domain-config&gt;
+ &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="@raw/my_ca"/&gt;
+ &lt;/trust-anchors&gt;
+ &lt;domain-config cleartextTrafficPermitted="false"&gt;
+ &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+ &lt;/domain-config&gt;
+ &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+<p>
+In <code>AndroidManifest.xml</code> reference the above config
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+...
+&lt;application ...&gt;
+ &lt;meta-data android:name="android.security.net.config"
+ android:resource="@xml/network_security_config" /&gt;
+ ...
+</pre>
+</p>
+
+<h2 id="FileFormat">Configuration File Format</h2>
+<p>The configuration file is XML. Here is what it can contain:</p>
+</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+ &lt;base-config&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="..."/&gt;
+ ...
+ &lt;/trust-anchors&gt;
+ &lt;/base-config&gt;
+
+ &lt;domain-config&gt;
+ &lt;domain&gt;android.com&lt;/domain&gt;
+ ...
+ &lt;trust-anchors&gt;
+ &lt;certificates src="..."/&gt;
+ ...
+ &lt;/trust-anchors&gt;
+ &lt;pin-set&gt;
+ &lt;pin digest="..."&gt;...&lt;/pin&gt;
+ ...
+ &lt;/pin-set&gt;
+ &lt;/domain-config&gt;
+ ...
+ &lt;debug-overrides&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="..."/&gt;
+ ...
+ &lt;/trust-anchors&gt;
+ &lt;/debug-overrides&gt;
+&lt;/network-security-config&gt;
+</pre>
+
+<h3 id="network-security-config">&lt;network-security-config&gt;</h3>
+<dl class="xml">
+<dt>can contain:</dt>
+<dd>0 or 1 <code><a href="#base-config">&lt;base-config&gt;</a></code>
+<br/>Any number of <code><a href="#domain-config">&lt;domain-config&gt;</a></code>
+<br/>0 or 1<code><a href="#debug-overrides">&lt;debug-overrides&gt;</a></code>
+</dd>
+</dl>
+
+
+<h3 id="base-config">&lt;base-config&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;base-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
+ ...
+&lt;/base-config&gt;</pre></dd>
+<dt>can contain:</dt>
+<dd><code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code></dd>
+<dt>descrption:</dt>
+<dd>
+The default configuration used by all connections whose destination is not covered by a
+<a href="#domain-config"><code>domain-config</code></a>.
+
+<p>Any values that are not set will use the platform default values.
+The default configuration for applications targeting above API level 24 and above:
+<pre>
+&lt;base-config usesCleartextTraffic="true"&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="system" /&gt;
+ &lt;/trust-anchors&gt;
+&lt;/base-config&gt;
+</pre>
+The default configuration for applications targeting API level 23 and below is:
+<pre>
+&lt;base-config usesCleartextTraffic="true"&gt;
+ &lt;trust-anchors&gt;
+ &lt;certificates src="system" /&gt;
+ &lt;certificates src="user" /&gt;
+ &lt;/trust-anchors&gt;
+&lt;/base-config&gt;
+</pre>
+</p>
+</dd>
+</dl>
+
+<h3 id="domain-config">&lt;domain-config&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;domain-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
+ ...
+&lt;/domain-config&gt;</pre></dd>
+<dt>Can Contain:</dt>
+
+<dd>
+1 or more <code><a href="#domain">&lt;domain&gt;</a></code>
+<br/>0 or 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
+<br/>0 or 1 <code><a href="#pin-set">&lt;pin-set&gt;</code></a>
+<br/>Any number of nested <code>&lt;domain-config&gt;</code></dd>
+
+<dt>Descrption</dt>
+<dd>Configuration used for connections to specific destinations as the defined by {@code domain} elements.
+
+<p>Note that if multiple {@code domain-config} elements cover a destination the config with the most specific (longest)
+matching domain rule will be used.</p></dd>
+</dl>
+
+<h3 id="domain">&lt;domain&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;domain includeSubdomains=["true" | "false"]&gt;example.com&lt;/domain&gt;</pre></dd>
+<dt>Attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code includeSubdomains}</dt>
+<dd>If {@code "true"} then this domain rule will match the domain and all subdomains, including
+subdomains of subdomains, otherwise the rule only applies to exact matches.</dd>
+</dl>
+</dd>
+
+<dt>Descrption:</dt>
+</dl>
+
+<h3 id="debug-overrides">&lt;debug-overrides&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;debug-overrides&gt;
+ ...
+&lt;/debug-overrides&gt;</pre></dd>
+<dt>Can Contain:</dt>
+<dd>0 or 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code></dd>
+<dt>Description:</dt>
+<dd>Overrides to be applied when
+<a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a> is
+{@code "true"} which is normally the case for non-release builds generated by IDEs and build tools.
+Trust anchors specified in {@code debug-overrides} are added to all other configurations and certificate
+pinning is not performed when the server's certificate chain uses one of these debug-only trust anchors.
+If <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a> is
+{@code "false"} then this section is completely ignored.
+</dd>
+</dl>
+
+<h3 id="trust-anchors">&lt;trust-anchors&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">&lt;trust-anchors&gt;
+...
+&lt;/trust-anchors&gt;
+</pre></dd>
+<dt>Can Contain:</dt>
+<dd>Any number of <code><a href="#certificates">&lt;certificates&gt;</a></code></dd>
+<dt>Description:</dt>
+<dd>Set of trust anchors for secure connections.</dd>
+</dl>
+
+
+<h3 id="certificates">&lt;certificates&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;certificates src=["system" | "user" | "<i>raw resource</i>"]
+ overridePins=["true" | "false"] /&gt;
+</pre></dd>
+<dt>description:</dt>
+<dd>Set of X.509 certificates for {@code trust-anchors} elements.</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code src}</dt>
+<dd>
+The source of CA certificates, can be one of
+<ul>
+ <li>a raw resource id pointing to a file containing X.509 certificates. Certificates must be encoded in DER or PEM format.
+ In the case of PEM certificates the file <em>must not</em> contain extra non-PEM data such as comments.</li>
+ <li>{@code "system"} for the pre-installed system CA certificates</li>
+ <li>{@code "user"} for user-added CA certificates</li>
+</ul>
+</dd>
+
+<dt>{@code overridePins}</dt>
+<dd>
+Specifies if the CAs from this source bypass certificate pinning. If {@code "true"} then certificate chains which
+chain through one of the CAs from this source then pinning will not be performed. This can be useful
+for debug CAs or to support letting the user MiTM your app's secure traffic.
+<p>
+Default is {@code "false"} unless specified in a {@code debug-overrides} element, in which case the default is {@code "true"}.
+</p>
+</dd>
+</dl>
+</dd>
+
+<h3 id="pin-set">&lt;pin-set&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">&lt;pin-set expiration="date"&gt;
+...
+&lt;/pin-set&gt;
+</pre></dd>
+<dt>Can Contain:</dt>
+<dd>Any number of <code><a href="#pin">&lt;pin&gt;</a></code></dd>
+<dt>Description:</dt>
+<dd>A set of public key pins. For a secure connection to be trusted, one of the public keys in the chain of trust must
+be in the set of pins. See <code><a href="#pin">&lt;pin&gt;</a></code> for the format of pins.</dd>
+<dt>Attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code expiration}</dt>
+<dd>The date, in {@code yyyy-MM-dd} format, at and after which the pins expire, thus disabling pinning.
+If the attribute is not set then the pins do not expire.
+<p>Expiration helps prevent connectivity issues in applications which do not get updates to their
+pin set, for example because the user disabled application updates.</p>
+</dd>
+</dl>
+</dd>
+
+<h3 id="pin">&lt;pin&gt;</h3>
+<dl class="xml">
+<dt>syntax:</dt>
+<dd>
+<pre class="stx">&lt;pin digest=["SHA-256"]&gt;base64 encoded digest of X.509 SubjectPublicKeyInfo (SPKI)&lt;/pin&gt</pre></dd>
+<dt>Attributes:</dt>
+<dd><dl class="attr">
+<dt>{@code digest}</dt>
+<dd>The digest algorithm used to generate the pin. Currently only {@code "SHA-256"} is supported.</dd>
+</dl>
+</dd>
+</dl>
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index cab416341685..264e7410be07 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -393,7 +393,7 @@ affect camera apps running on the primary user.</li>
only affects notifications generated by applications in the managed profile.</li>
</ul>
</li>
- <li>The {@link android.app.admin.DevicePolicyManager#createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle) createAndInitializeUser()} and {@link android.app.admin.DevicePolicyManager#createUser(android.content.ComponentName, java.lang.String) createUser()} methods have been deprecated.</li>
+ <li>The {@link android.app.admin.DevicePolicyManager#createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int) createAndManageUser()} method replaces createAndInitializeUser(), which has been removed.</li>
<li>The {@link android.app.admin.DevicePolicyManager#setScreenCaptureDisabled(android.content.ComponentName, boolean) setScreenCaptureDisabled()}
method now also blocks the assist structure when an app of the given user is in the foreground. </li>
<li>{@link android.app.admin.DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d4f745d818bd..af99f79e4b3b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -91,8 +91,11 @@ public class Canvas {
// a Canvas object.
private static final long NATIVE_ALLOCATION_SIZE = 525;
- private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
- getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+ // Use a Holder to allow static initialization of Canvas in the boot image.
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+ }
// This field is used to finalize the native Canvas properly
private Runnable mFinalizer;
@@ -107,7 +110,8 @@ public class Canvas {
if (!isHardwareAccelerated()) {
// 0 means no native bitmap
mNativeCanvasWrapper = initRaster(null);
- mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+ mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mNativeCanvasWrapper);
} else {
mFinalizer = null;
}
@@ -128,7 +132,8 @@ public class Canvas {
}
throwIfCannotDraw(bitmap);
mNativeCanvasWrapper = initRaster(bitmap);
- mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+ mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mNativeCanvasWrapper);
mBitmap = bitmap;
mDensity = bitmap.mDensity;
}
@@ -139,7 +144,8 @@ public class Canvas {
throw new IllegalStateException();
}
mNativeCanvasWrapper = nativeCanvas;
- mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+ mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+ this, mNativeCanvasWrapper);
mDensity = Bitmap.getDefaultDensity();
}
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 6309ed36eb51..f741e3cb5f8d 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -18,6 +18,9 @@ package android.graphics;
import android.content.res.AssetManager;
+import java.nio.ByteBuffer;
+import java.util.List;
+
/**
* A family of typefaces with different styles.
*
@@ -62,8 +65,9 @@ public class FontFamily {
return nAddFont(mNativePtr, path, ttcIndex);
}
- public boolean addFontWeightStyle(String path, int ttcIndex, int weight, boolean style) {
- return nAddFontWeightStyle(mNativePtr, path, ttcIndex, weight, style);
+ public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes,
+ int weight, boolean style) {
+ return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
}
public boolean addFontFromAsset(AssetManager mgr, String path) {
@@ -73,8 +77,9 @@ public class FontFamily {
private static native long nCreateFamily(String lang, int variant);
private static native void nUnrefFamily(long nativePtr);
private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex);
- private static native boolean nAddFontWeightStyle(long nativeFamily, String path,
- int ttcIndex, int weight, boolean isItalic);
+ private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+ int ttcIndex, List<FontListParser.Axis> listOfAxis,
+ int weight, boolean isItalic);
private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
String path);
}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 774f6b8922e0..8f7c6a62a4a3 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Pattern;
/**
* Parser for font config files.
@@ -42,15 +43,26 @@ public class FontListParser {
public List<Alias> aliases;
}
+ public static class Axis {
+ Axis(int tag, float styleValue) {
+ this.tag = tag;
+ this.styleValue = styleValue;
+ }
+ public final int tag;
+ public final float styleValue;
+ }
+
public static class Font {
- Font(String fontName, int ttcIndex, int weight, boolean isItalic) {
+ Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
this.fontName = fontName;
this.ttcIndex = ttcIndex;
+ this.axes = axes;
this.weight = weight;
this.isItalic = isItalic;
}
public String fontName;
public int ttcIndex;
+ public final List<Axis> axes;
public int weight;
public boolean isItalic;
}
@@ -93,9 +105,10 @@ public class FontListParser {
parser.require(XmlPullParser.START_TAG, null, "familyset");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
- if (parser.getName().equals("family")) {
+ String tag = parser.getName();
+ if (tag.equals("family")) {
config.families.add(readFamily(parser));
- } else if (parser.getName().equals("alias")) {
+ } else if (tag.equals("alias")) {
config.aliases.add(readAlias(parser));
} else {
skip(parser);
@@ -114,14 +127,7 @@ public class FontListParser {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (tag.equals("font")) {
- String ttcIndexStr = parser.getAttributeValue(null, "index");
- int ttcIndex = ttcIndexStr == null ? 0 : Integer.parseInt(ttcIndexStr);
- String weightStr = parser.getAttributeValue(null, "weight");
- int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
- boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
- String filename = parser.nextText();
- String fullFilename = "/system/fonts/" + filename;
- fonts.add(new Font(fullFilename, ttcIndex, weight, isItalic));
+ fonts.add(readFont(parser));
} else {
skip(parser);
}
@@ -129,6 +135,70 @@ public class FontListParser {
return new Family(name, fonts, lang, variant);
}
+ /** Matches leading and trailing XML whitespace. */
+ private static final Pattern FILENAME_WHITESPACE_PATTERN =
+ Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
+
+ private static Font readFont(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String indexStr = parser.getAttributeValue(null, "index");
+ int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
+ List<Axis> axes = new ArrayList<Axis>();
+ String weightStr = parser.getAttributeValue(null, "weight");
+ int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
+ boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
+ StringBuilder filename = new StringBuilder();
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() == XmlPullParser.TEXT) {
+ filename.append(parser.getText());
+ }
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ String tag = parser.getName();
+ if (tag.equals("axis")) {
+ axes.add(readAxis(parser));
+ } else {
+ skip(parser);
+ }
+ }
+ String fullFilename = "/system/fonts/" +
+ FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
+ return new Font(fullFilename, index, axes, weight, isItalic);
+ }
+
+ /** The 'tag' attribute value is read as four character values between 0 and 255 inclusive. */
+ private static final Pattern TAG_PATTERN = Pattern.compile("[\\x00-\\xFF]{4}");
+
+ /** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
+ * '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
+ */
+ private static final Pattern STYLE_VALUE_PATTERN =
+ Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
+
+ private static Axis readAxis(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int tag = 0;
+ String tagStr = parser.getAttributeValue(null, "tag");
+ if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
+ tag = tagStr.charAt(0) << 24 +
+ tagStr.charAt(1) << 16 +
+ tagStr.charAt(2) << 8 +
+ tagStr.charAt(3);
+ } else {
+ throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
+ }
+
+ float styleValue = 0;
+ String styleValueStr = parser.getAttributeValue(null, "stylevalue");
+ if (styleValueStr != null && STYLE_VALUE_PATTERN.matcher(styleValueStr).matches()) {
+ styleValue = Float.parseFloat(styleValueStr);
+ } else {
+ throw new XmlPullParserException("Invalid styleValue attribute value.", parser, null);
+ }
+
+ skip(parser); // axis tag is empty, ignore any contents and consume end tag
+ return new Axis(tag, styleValue);
+ }
+
private static Alias readAlias(XmlPullParser parser)
throws XmlPullParserException, IOException {
Alias alias = new Alias();
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index aa404082715e..99fa9fe2b3b2 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -18,6 +18,7 @@ package android.graphics;
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
/**
@@ -176,6 +177,34 @@ public final class Outline {
}
/**
+ * Populates {@code outBounds} with the outline bounds, if set, and returns
+ * {@code true}. If no outline bounds are set, or if a path has been set
+ * via {@link #setConvexPath(Path)}, returns {@code false}.
+ *
+ * @param outRect the rect to populate with the outline bounds, if set
+ * @return {@code true} if {@code outBounds} was populated with outline
+ * bounds, or {@code false} if no outline bounds are set
+ */
+ public boolean getRect(@NonNull Rect outRect) {
+ if (mRect == null) {
+ return false;
+ }
+ outRect.set(mRect);
+ return true;
+ }
+
+ /**
+ * Returns the rounded rect radius, if set, or {@code -1} if a path has
+ * been set via {@link #setConvexPath(Path)}. A return value of {@code 0}
+ * indicates a non-rounded rect.
+ *
+ * @return the rounded rect radius or {@code -1}
+ */
+ public float getRadius() {
+ return mRadius;
+ }
+
+ /**
* Sets the outline to the oval defined by input rect.
*/
public void setOval(int left, int top, int right, int bottom) {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 534121a2e361..291fdc4f8e05 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -44,8 +44,11 @@ public class Paint {
// The approximate size of a native paint object.
private static final long NATIVE_PAINT_SIZE = 98;
- private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
- nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+ // Use a Holder to allow static initialization of Paint in the boot image.
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+ }
/**
* @hide
@@ -452,7 +455,7 @@ public class Paint {
*/
public Paint(int flags) {
mNativePaint = nInit();
- sRegistry.registerNativeAllocation(this, mNativePaint);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS);
// TODO: Turning off hinting has undesirable side effects, we need to
// revisit hinting once we add support for subpixel positioning
@@ -471,7 +474,7 @@ public class Paint {
*/
public Paint(Paint paint) {
mNativePaint = nInitWithPaint(paint.getNativeInstance());
- sRegistry.registerNativeAllocation(this, mNativePaint);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
setClassVariablesFrom(paint);
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 1294323ce69b..f15aff7de39c 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -17,7 +17,6 @@
package android.graphics;
import android.content.res.AssetManager;
-import android.graphics.FontListParser.Family;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
@@ -28,6 +27,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -259,10 +260,26 @@ public class Typeface {
mStyle = nativeGetStyle(ni);
}
- private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
+ private static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+ Map<String, ByteBuffer> bufferForPath) {
FontFamily fontFamily = new FontFamily(family.lang, family.variant);
for (FontListParser.Font font : family.fonts) {
- fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.weight, font.isItalic);
+ ByteBuffer fontBuffer = bufferForPath.get(font.fontName);
+ if (fontBuffer == null) {
+ try (FileInputStream file = new FileInputStream(font.fontName)) {
+ FileChannel fileChannel = file.getChannel();
+ long fontSize = fileChannel.size();
+ fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
+ bufferForPath.put(font.fontName, fontBuffer);
+ } catch (IOException e) {
+ Log.e(TAG, "Error mapping font file " + font.fontName);
+ continue;
+ }
+ }
+ if (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes,
+ font.weight, font.isItalic)) {
+ Log.e(TAG, "Error creating font " + font.fontName + "#" + font.ttcIndex);
+ }
}
return fontFamily;
}
@@ -280,13 +297,15 @@ public class Typeface {
FileInputStream fontsIn = new FileInputStream(configFilename);
FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
+ Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
+
List<FontFamily> familyList = new ArrayList<FontFamily>();
// Note that the default typeface is always present in the fallback list;
// this is an enhancement from pre-Minikin behavior.
for (int i = 0; i < fontConfig.families.size(); i++) {
- Family f = fontConfig.families.get(i);
+ FontListParser.Family f = fontConfig.families.get(i);
if (i == 0 || f.name == null) {
- familyList.add(makeFamilyFromParsed(f));
+ familyList.add(makeFamilyFromParsed(f, bufferForPath));
}
}
sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
@@ -295,14 +314,14 @@ public class Typeface {
Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
for (int i = 0; i < fontConfig.families.size(); i++) {
Typeface typeface;
- Family f = fontConfig.families.get(i);
+ FontListParser.Family f = fontConfig.families.get(i);
if (f.name != null) {
if (i == 0) {
// The first entry is the default typeface; no sense in
// duplicating the corresponding FontFamily.
typeface = sDefaultTypeface;
} else {
- FontFamily fontFamily = makeFamilyFromParsed(f);
+ FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
FontFamily[] families = { fontFamily };
typeface = Typeface.createFromFamiliesWithDefault(families);
}
@@ -324,11 +343,11 @@ public class Typeface {
Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
// TODO: normal in non-Minikin case, remove or make error when Minikin-only
} catch (FileNotFoundException e) {
- Log.e(TAG, "Error opening " + configFilename);
+ Log.e(TAG, "Error opening " + configFilename, e);
} catch (IOException e) {
- Log.e(TAG, "Error reading " + configFilename);
+ Log.e(TAG, "Error reading " + configFilename, e);
} catch (XmlPullParserException e) {
- Log.e(TAG, "XML parse exception for " + configFilename);
+ Log.e(TAG, "XML parse exception for " + configFilename, e);
}
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index af8ccf5018b9..3901af36be83 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -154,7 +154,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
/** Local, mutable animator set. */
- private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator();
+ private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorRT(this);
/**
* The resources against which this drawable was created. Used to attempt
@@ -164,8 +164,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
private AnimatedVectorDrawableState mAnimatedVectorState;
- /** Whether the animator set has been prepared. */
- private boolean mHasAnimatorSet;
+ /** The animator set that is parsed from the xml. */
+ private AnimatorSet mAnimatorSetFromXml = null;
private boolean mMutated;
@@ -234,13 +234,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
@Override
public void draw(Canvas canvas) {
- if (canvas.isHardwareAccelerated()) {
- mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas);
- }
+ mAnimatorSet.onDraw(canvas);
mAnimatedVectorState.mVectorDrawable.draw(canvas);
- if (isStarted()) {
- invalidateSelf();
- }
}
@Override
@@ -395,6 +390,24 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
mRes = state.mPendingAnims == null ? null : res;
}
+ /**
+ * Force to animate on UI thread.
+ * @hide
+ */
+ public void forceAnimationOnUI() {
+ if (mAnimatorSet instanceof VectorDrawableAnimatorRT) {
+ VectorDrawableAnimatorRT animator = (VectorDrawableAnimatorRT) mAnimatorSet;
+ if (animator.isRunning()) {
+ throw new UnsupportedOperationException("Cannot force Animated Vector Drawable to" +
+ " run on UI thread when the animation has started on RenderThread.");
+ }
+ mAnimatorSet = new VectorDrawableAnimatorUI(this);
+ if (mAnimatorSetFromXml != null) {
+ mAnimatorSet.init(mAnimatorSetFromXml);
+ }
+ }
+ }
+
@Override
public boolean canApplyTheme() {
return (mAnimatedVectorState != null && mAnimatedVectorState.canApplyTheme())
@@ -611,40 +624,28 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
return mAnimatorSet.isRunning();
}
- private boolean isStarted() {
- return mAnimatorSet.isStarted();
- }
-
/**
* Resets the AnimatedVectorDrawable to the start state as specified in the animators.
*/
public void reset() {
+ ensureAnimatorSet();
mAnimatorSet.reset();
- invalidateSelf();
}
@Override
public void start() {
ensureAnimatorSet();
-
- // If any one of the animator has not ended, do nothing.
- if (isStarted()) {
- return;
- }
-
mAnimatorSet.start();
- invalidateSelf();
}
@NonNull
private void ensureAnimatorSet() {
- if (!mHasAnimatorSet) {
+ if (mAnimatorSetFromXml == null) {
// TODO: Skip the AnimatorSet creation and init the VectorDrawableAnimator directly
// with a list of LocalAnimators.
- AnimatorSet set = new AnimatorSet();
- mAnimatedVectorState.prepareLocalAnimators(set, mRes);
- mHasAnimatorSet = true;
- mAnimatorSet.initWithAnimatorSet(set);
+ mAnimatorSetFromXml = new AnimatorSet();
+ mAnimatedVectorState.prepareLocalAnimators(mAnimatorSetFromXml, mRes);
+ mAnimatorSet.init(mAnimatorSetFromXml);
mRes = null;
}
}
@@ -671,7 +672,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
}
mAnimatorSet.reverse();
- invalidateSelf();
}
/**
@@ -740,7 +740,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
// A helper function to clean up the animator listener in the mAnimatorSet.
private void removeAnimatorSetListener() {
if (mAnimatorListener != null) {
- mAnimatorSet.removeListener();
+ mAnimatorSet.removeListener(mAnimatorListener);
mAnimatorListener = null;
}
}
@@ -770,10 +770,103 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
mAnimationCallbacks.clear();
}
+ private interface VectorDrawableAnimator {
+ void init(AnimatorSet set);
+ void start();
+ void end();
+ void reset();
+ void reverse();
+ boolean canReverse();
+ void setListener(AnimatorListener listener);
+ void removeListener(AnimatorListener listener);
+ void onDraw(Canvas canvas);
+ boolean isStarted();
+ boolean isRunning();
+ }
+
+ private static class VectorDrawableAnimatorUI implements VectorDrawableAnimator {
+ private AnimatorSet mSet = new AnimatorSet();
+ private final Drawable mDrawable;
+
+ VectorDrawableAnimatorUI(AnimatedVectorDrawable drawable) {
+ mDrawable = drawable;
+ }
+
+ @Override
+ public void init(AnimatorSet set) {
+ mSet = set;
+ }
+
+ @Override
+ public void start() {
+ if (mSet.isStarted()) {
+ return;
+ }
+ mSet.start();
+ invalidateOwningView();
+ }
+
+ @Override
+ public void end() {
+ mSet.end();
+ }
+
+ @Override
+ public void reset() {
+ start();
+ mSet.cancel();
+ }
+
+ @Override
+ public void reverse() {
+ mSet.reverse();
+ invalidateOwningView();
+ }
+
+ @Override
+ public boolean canReverse() {
+ return mSet.canReverse();
+ }
+
+ @Override
+ public void setListener(AnimatorListener listener) {
+ mSet.addListener(listener);
+ }
+
+ @Override
+ public void removeListener(AnimatorListener listener) {
+ mSet.removeListener(listener);
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (mSet.isStarted()) {
+ invalidateOwningView();
+ }
+ }
+
+ @Override
+ public boolean isStarted() {
+ return mSet.isStarted();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return mSet.isRunning();
+ }
+
+ private void invalidateOwningView() {
+ mDrawable.invalidateSelf();
+ }
+ }
+
/**
* @hide
*/
- public static class VectorDrawableAnimator {
+ public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator {
+ private static final int NONE = 0;
+ private static final int START_ANIMATION = 1;
+ private static final int REVERSE_ANIMATION = 2;
private AnimatorListener mListener = null;
private final LongArray mStartDelays = new LongArray();
private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -782,24 +875,26 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
private boolean mContainsSequentialAnimators = false;
private boolean mStarted = false;
private boolean mInitialized = false;
- private boolean mAnimationPending = false;
private boolean mIsReversible = false;
// This needs to be set before parsing starts.
private boolean mShouldIgnoreInvalidAnim;
// TODO: Consider using NativeAllocationRegistery to track native allocation
private final VirtualRefBasePtr mSetRefBasePtr;
- private WeakReference<RenderNode> mTarget = null;
private WeakReference<RenderNode> mLastSeenTarget = null;
+ private int mLastListenerId = 0;
+ private int mPendingAnimationAction = NONE;
+ private final Drawable mDrawable;
-
- VectorDrawableAnimator() {
+ VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
+ mDrawable = drawable;
mSetPtr = nCreateAnimatorSet();
// Increment ref count on native AnimatorSet, so it doesn't get released before Java
// side is done using it.
mSetRefBasePtr = new VirtualRefBasePtr(mSetPtr);
}
- private void initWithAnimatorSet(AnimatorSet set) {
+ @Override
+ public void init(AnimatorSet set) {
if (mInitialized) {
// Already initialized
throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
@@ -810,6 +905,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
mInitialized = true;
// Check reversible.
+ mIsReversible = true;
if (mContainsSequentialAnimators) {
mIsReversible = false;
} else {
@@ -821,14 +917,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
}
}
}
- mIsReversible = true;
}
private void parseAnimatorSet(AnimatorSet set, long startTime) {
ArrayList<Animator> animators = set.getChildAnimations();
boolean playTogether = set.shouldPlayTogether();
- // Convert AnimatorSet to VectorDrawableAnimator
+ // Convert AnimatorSet to VectorDrawableAnimatorRT
for (int i = 0; i < animators.size(); i++) {
Animator animator = animators.get(i);
// Here we only support ObjectAnimator
@@ -1042,51 +1137,45 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
* to the last seen RenderNode target and start right away.
*/
protected void recordLastSeenTarget(DisplayListCanvas canvas) {
- if (mAnimationPending) {
- mLastSeenTarget = new WeakReference<RenderNode>(
- RenderNodeAnimatorSetHelper.getTarget(canvas));
+ mLastSeenTarget = new WeakReference<RenderNode>(
+ RenderNodeAnimatorSetHelper.getTarget(canvas));
+ if (mPendingAnimationAction != NONE) {
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
Log.d(LOGTAG, "Target is set in the next frame");
}
- mAnimationPending = false;
- start();
- } else {
- mLastSeenTarget = new WeakReference<RenderNode>(
- RenderNodeAnimatorSetHelper.getTarget(canvas));
- }
-
- }
-
- private boolean setTarget(RenderNode node) {
- if (mTarget != null && mTarget.get() != null) {
- // TODO: Maybe we want to support target change.
- throw new IllegalStateException("Target already set!");
+ if (mPendingAnimationAction == START_ANIMATION) {
+ start();
+ } else if (mPendingAnimationAction == REVERSE_ANIMATION) {
+ reverse();
+ }
+ mPendingAnimationAction = NONE;
}
-
- node.addAnimator(this);
- mTarget = new WeakReference<RenderNode>(node);
- return true;
}
private boolean useLastSeenTarget() {
- if (mLastSeenTarget != null && mLastSeenTarget.get() != null) {
- setTarget(mLastSeenTarget.get());
- return true;
+ if (mLastSeenTarget != null) {
+ final RenderNode target = mLastSeenTarget.get();
+ if (target != null && target.isAttached()) {
+ target.addAnimator(this);
+ return true;
+ }
}
return false;
}
+ private void invalidateOwningView() {
+ mDrawable.invalidateSelf();
+ }
+
+ @Override
public void start() {
if (!mInitialized) {
return;
}
- if (mStarted) {
- return;
- }
-
if (!useLastSeenTarget()) {
- mAnimationPending = true;
+ invalidateOwningView();
+ mPendingAnimationAction = START_ANIMATION;
return;
}
@@ -1094,81 +1183,110 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
}
- nStart(mSetPtr, this);
+ mStarted = true;
+ nStart(mSetPtr, this, ++mLastListenerId);
+ invalidateOwningView();
if (mListener != null) {
mListener.onAnimationStart(null);
}
- mStarted = true;
}
+ @Override
public void end() {
- if (mInitialized && mStarted) {
+ if (mInitialized && useLastSeenTarget()) {
+ // If no target has ever been set, no-op
nEnd(mSetPtr);
- onAnimationEnd();
+ invalidateOwningView();
}
}
- void reset() {
- if (!mInitialized) {
- return;
+ @Override
+ public void reset() {
+ if (mInitialized && useLastSeenTarget()) {
+ // If no target has ever been set, no-op
+ nReset(mSetPtr);
+ invalidateOwningView();
}
- // TODO: Need to implement reset.
- Log.w(LOGTAG, "Reset is yet to be implemented");
- nReset(mSetPtr);
}
// Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
// animators or when the animator set has a start delay
- void reverse() {
- if (!mIsReversible) {
+ @Override
+ public void reverse() {
+ if (!mIsReversible || !mInitialized) {
+ return;
+ }
+ if (!useLastSeenTarget()) {
+ invalidateOwningView();
+ mPendingAnimationAction = REVERSE_ANIMATION;
return;
}
- // TODO: Need to support reverse (non-public API)
- Log.w(LOGTAG, "Reverse is yet to be implemented");
- nReverse(mSetPtr, this);
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+ }
+ mStarted = true;
+ nReverse(mSetPtr, this, ++mLastListenerId);
+ invalidateOwningView();
+ if (mListener != null) {
+ mListener.onAnimationStart(null);
+ }
}
public long getAnimatorNativePtr() {
return mSetPtr;
}
- boolean canReverse() {
+ @Override
+ public boolean canReverse() {
return mIsReversible;
}
- boolean isStarted() {
+ @Override
+ public boolean isStarted() {
return mStarted;
}
- boolean isRunning() {
+ @Override
+ public boolean isRunning() {
if (!mInitialized) {
return false;
}
return mStarted;
}
- void setListener(AnimatorListener listener) {
+ @Override
+ public void setListener(AnimatorListener listener) {
mListener = listener;
}
- void removeListener() {
+ @Override
+ public void removeListener(AnimatorListener listener) {
mListener = null;
}
- private void onAnimationEnd() {
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (canvas.isHardwareAccelerated()) {
+ recordLastSeenTarget((DisplayListCanvas) canvas);
+ }
+ }
+
+ private void onAnimationEnd(int listenerId) {
+ if (listenerId != mLastListenerId) {
+ return;
+ }
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.d(LOGTAG, "on finished called from native");
+ }
mStarted = false;
if (mListener != null) {
mListener.onAnimationEnd(null);
}
- mTarget = null;
}
// onFinished: should be called from native
- private static void callOnFinished(VectorDrawableAnimator set) {
- if (DBG_ANIMATION_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "on finished called from native");
- }
- set.onAnimationEnd();
+ private static void callOnFinished(VectorDrawableAnimatorRT set, int id) {
+ set.onAnimationEnd(id);
}
}
@@ -1188,8 +1306,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
float endValue);
private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
- private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set);
- private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set);
+ private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
+ private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
private static native void nEnd(long animatorSetPtr);
private static native void nReset(long animatorSetPtr);
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index daf25815d1ac..bffbc751ee83 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -641,16 +641,22 @@ public class BitmapDrawable extends Drawable {
@Override
public void setTintList(ColorStateList tint) {
- mBitmapState.mTint = tint;
- mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
- invalidateSelf();
+ final BitmapState state = mBitmapState;
+ if (state.mTint != tint) {
+ state.mTint = tint;
+ mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
+ invalidateSelf();
+ }
}
@Override
public void setTintMode(PorterDuff.Mode tintMode) {
- mBitmapState.mTintMode = tintMode;
- mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
- invalidateSelf();
+ final BitmapState state = mBitmapState;
+ if (state.mTintMode != tintMode) {
+ state.mTintMode = tintMode;
+ mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
+ invalidateSelf();
+ }
}
/**
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index d05c66a8437c..3b0e7e8c704e 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -898,19 +898,19 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
* @param res the resources used to inflate density-dependent values
*/
final void updateDensity(Resources res) {
- if (mSourceRes != null) {
+ if (res != null) {
mSourceRes = res;
- }
- // The density may have changed since the last update (if any). Any
- // dimension-type attributes will need their default values scaled.
- final int targetDensity = Drawable.resolveDensity(res, mDensity);
- final int sourceDensity = mDensity;
- mDensity = targetDensity;
+ // The density may have changed since the last update (if any). Any
+ // dimension-type attributes will need their default values scaled.
+ final int targetDensity = Drawable.resolveDensity(res, mDensity);
+ final int sourceDensity = mDensity;
+ mDensity = targetDensity;
- if (sourceDensity != targetDensity) {
- mCheckedConstantSize = false;
- mCheckedPadding = false;
+ if (sourceDensity != targetDensity) {
+ mCheckedConstantSize = false;
+ mCheckedPadding = false;
+ }
}
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index bfbdfa5f5255..681653967aa1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -66,11 +66,16 @@ import java.util.Collection;
public class NinePatchDrawable extends Drawable {
// dithering helps a lot, and is pretty cheap, so default is true
private static final boolean DEFAULT_DITHER = false;
+
+ /** Temporary rect used for density scaling. */
+ private Rect mTempRect;
+
private NinePatchState mNinePatchState;
- private NinePatch mNinePatch;
private PorterDuffColorFilter mTintFilter;
private Rect mPadding;
private Insets mOpticalInsets = Insets.NONE;
+ private Rect mOutlineInsets;
+ private float mOutlineRadius;
private Paint mPaint;
private boolean mMutated;
@@ -86,8 +91,9 @@ public class NinePatchDrawable extends Drawable {
/**
* Create drawable from raw nine-patch data, not dealing with density.
+ *
* @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
- * to ensure that the drawable has correctly set its target density.
+ * to ensure that the drawable has correctly set its target density.
*/
@Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
@@ -101,7 +107,6 @@ public class NinePatchDrawable extends Drawable {
public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -114,16 +119,17 @@ public class NinePatchDrawable extends Drawable {
Rect padding, Rect opticalInsets, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Create drawable from existing nine-patch, not dealing with density.
+ *
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
- * to ensure that the drawable has correctly set its target density.
+ * to ensure that the drawable has correctly set its target
+ * density.
*/
@Deprecated
- public NinePatchDrawable(NinePatch patch) {
+ public NinePatchDrawable(@NonNull NinePatch patch) {
this(new NinePatchState(patch, new Rect()), null);
}
@@ -131,9 +137,8 @@ public class NinePatchDrawable extends Drawable {
* Create drawable from existing nine-patch, setting initial target density
* based on the display metrics of the resources.
*/
- public NinePatchDrawable(Resources res, NinePatch patch) {
+ public NinePatchDrawable(@Nullable Resources res, @NonNull NinePatch patch) {
this(new NinePatchState(patch, new Rect()), res);
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
@@ -146,7 +151,7 @@ public class NinePatchDrawable extends Drawable {
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(Canvas canvas) {
+ public void setTargetDensity(@NonNull Canvas canvas) {
setTargetDensity(canvas.getDensity());
}
@@ -158,7 +163,7 @@ public class NinePatchDrawable extends Drawable {
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(DisplayMetrics metrics) {
+ public void setTargetDensity(@NonNull DisplayMetrics metrics) {
setTargetDensity(metrics.densityDpi);
}
@@ -171,78 +176,24 @@ public class NinePatchDrawable extends Drawable {
* @see android.graphics.Bitmap#getDensity()
*/
public void setTargetDensity(int density) {
- if (density != mTargetDensity) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- if (mNinePatch != null) {
- computeBitmapSize();
- }
- invalidateSelf();
+ if (density == 0) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
}
- }
-
- private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
- int left = Drawable.scaleFromDensity(insets.left, sdensity, tdensity, true);
- int top = Drawable.scaleFromDensity(insets.top, sdensity, tdensity, true);
- int right = Drawable.scaleFromDensity(insets.right, sdensity, tdensity, true);
- int bottom = Drawable.scaleFromDensity(insets.bottom, sdensity, tdensity, true);
- return Insets.of(left, top, right, bottom);
- }
- private void computeBitmapSize() {
- final int sdensity = mNinePatch.getDensity();
- final int tdensity = mTargetDensity;
- if (sdensity == tdensity) {
- mBitmapWidth = mNinePatch.getWidth();
- mBitmapHeight = mNinePatch.getHeight();
- mOpticalInsets = mNinePatchState.mOpticalInsets;
- } else {
- mBitmapWidth = Drawable.scaleFromDensity(
- mNinePatch.getWidth(), sdensity, tdensity, true);
- mBitmapHeight = Drawable.scaleFromDensity(
- mNinePatch.getHeight(), sdensity, tdensity, true);
- if (mNinePatchState.mPadding != null && mPadding != null) {
- Rect dest = mPadding;
- Rect src = mNinePatchState.mPadding;
- if (dest == src) {
- mPadding = dest = new Rect(src);
- }
- dest.left = Drawable.scaleFromDensity(src.left, sdensity, tdensity, true);
- dest.top = Drawable.scaleFromDensity(src.top, sdensity, tdensity, true);
- dest.right = Drawable.scaleFromDensity(src.right, sdensity, tdensity, true);
- dest.bottom = Drawable.scaleFromDensity(src.bottom, sdensity, tdensity, true);
- }
- mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity);
- }
- }
+ if (mTargetDensity != density) {
+ mTargetDensity = density;
- /**
- * Sets the nine patch used by this drawable.
- *
- * @param ninePatch the nine patch for this drawable
- */
- public void setNinePatch(NinePatch ninePatch) {
- if (mNinePatch != ninePatch) {
- mNinePatch = ninePatch;
- if (ninePatch != null) {
- computeBitmapSize();
- } else {
- mBitmapWidth = mBitmapHeight = -1;
- mOpticalInsets = Insets.NONE;
- }
+ computeBitmapSize();
invalidateSelf();
}
}
- /**
- * @return the nine patch used by this drawable
- */
- public NinePatch getNinePatch() {
- return mNinePatch;
- }
-
@Override
public void draw(Canvas canvas) {
- final Rect bounds = getBounds();
+ final NinePatchState state = mNinePatchState;
+
+ Rect bounds = getBounds();
+ int restoreToCount = -1;
final boolean clearColorFilter;
if (mTintFilter != null && getPaint().getColorFilter() == null) {
@@ -252,22 +203,52 @@ public class NinePatchDrawable extends Drawable {
clearColorFilter = false;
}
- final boolean needsMirroring = needsMirroring();
- if (needsMirroring) {
- // Mirror the 9patch
- canvas.translate(bounds.right - bounds.left, 0);
- canvas.scale(-1.0f, 1.0f);
- }
-
final int restoreAlpha;
- if (mNinePatchState.mBaseAlpha != 1.0f) {
- restoreAlpha = mPaint.getAlpha();
- mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
+ if (state.mBaseAlpha != 1.0f) {
+ restoreAlpha = getPaint().getAlpha();
+ mPaint.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
} else {
restoreAlpha = -1;
}
- mNinePatch.draw(canvas, bounds, mPaint);
+ final boolean needsDensityScaling = canvas.getDensity() == 0;
+ if (needsDensityScaling) {
+ restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+ // Apply density scaling.
+ final float scale = mTargetDensity / (float) state.mNinePatch.getDensity();
+ final float px = bounds.left;
+ final float py = bounds.top;
+ canvas.scale(scale, scale, px, py);
+
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+
+ // Scale the bounds to match.
+ final Rect scaledBounds = mTempRect;
+ scaledBounds.left = bounds.left;
+ scaledBounds.top = bounds.top;
+ scaledBounds.right = bounds.left + Math.round(bounds.width() / scale);
+ scaledBounds.bottom = bounds.top + Math.round(bounds.height() / scale);
+ bounds = scaledBounds;
+ }
+
+ final boolean needsMirroring = needsMirroring();
+ if (needsMirroring) {
+ restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
+
+ // Mirror the 9patch.
+ final float cx = (bounds.left + bounds.right) / 2.0f;
+ final float cy = (bounds.top + bounds.bottom) / 2.0f;
+ canvas.scale(-1.0f, 1.0f, cx, cy);
+ }
+
+ state.mNinePatch.draw(canvas, bounds, mPaint);
+
+ if (restoreToCount >= 0) {
+ canvas.restoreToCount(restoreToCount);
+ }
if (clearColorFilter) {
mPaint.setColorFilter(null);
@@ -284,38 +265,36 @@ public class NinePatchDrawable extends Drawable {
}
@Override
- public boolean getPadding(Rect padding) {
- final Rect scaledPadding = mPadding;
- if (scaledPadding != null) {
- if (needsMirroring()) {
- padding.set(scaledPadding.right, scaledPadding.top,
- scaledPadding.left, scaledPadding.bottom);
- } else {
- padding.set(scaledPadding);
- }
+ public boolean getPadding(@NonNull Rect padding) {
+ if (mPadding != null) {
+ padding.set(mPadding);
return (padding.left | padding.top | padding.right | padding.bottom) != 0;
+ } else {
+ return super.getPadding(padding);
}
- return false;
}
@Override
public void getOutline(@NonNull Outline outline) {
final Rect bounds = getBounds();
- if (bounds.isEmpty()) return;
+ if (bounds.isEmpty()) {
+ return;
+ }
- if (mNinePatchState != null) {
- NinePatch.InsetStruct insets = mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
+ if (mNinePatchState != null && mOutlineInsets != null) {
+ final NinePatch.InsetStruct insets =
+ mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
if (insets != null) {
- final Rect outlineInsets = insets.outlineRect;
- outline.setRoundRect(bounds.left + outlineInsets.left,
- bounds.top + outlineInsets.top,
- bounds.right - outlineInsets.right,
- bounds.bottom - outlineInsets.bottom,
- insets.outlineRadius);
+ outline.setRoundRect(bounds.left + mOutlineInsets.left,
+ bounds.top + mOutlineInsets.top,
+ bounds.right - mOutlineInsets.right,
+ bounds.bottom - mOutlineInsets.bottom,
+ mOutlineRadius);
outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
return;
}
}
+
super.getOutline(outline);
}
@@ -324,11 +303,12 @@ public class NinePatchDrawable extends Drawable {
*/
@Override
public Insets getOpticalInsets() {
+ final Insets opticalInsets = mOpticalInsets;
if (needsMirroring()) {
- return Insets.of(mOpticalInsets.right, mOpticalInsets.top,
- mOpticalInsets.left, mOpticalInsets.bottom);
+ return Insets.of(opticalInsets.right, opticalInsets.top,
+ opticalInsets.left, opticalInsets.bottom);
} else {
- return mOpticalInsets;
+ return opticalInsets;
}
}
@@ -352,7 +332,7 @@ public class NinePatchDrawable extends Drawable {
}
@Override
- public void setColorFilter(ColorFilter colorFilter) {
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
if (mPaint == null && colorFilter == null) {
// Fast common case -- leave at no color filter.
return;
@@ -362,14 +342,14 @@ public class NinePatchDrawable extends Drawable {
}
@Override
- public void setTintList(ColorStateList tint) {
+ public void setTintList(@Nullable ColorStateList tint) {
mNinePatchState.mTint = tint;
mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
invalidateSelf();
}
@Override
- public void setTintMode(PorterDuff.Mode tintMode) {
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
mNinePatchState.mTintMode = tintMode;
mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
invalidateSelf();
@@ -409,10 +389,7 @@ public class NinePatchDrawable extends Drawable {
@Override
public boolean isFilterBitmap() {
- if (mPaint == null) {
- return false;
- }
- return getPaint().isFilterBitmap();
+ return mPaint != null && getPaint().isFilterBitmap();
}
@Override
@@ -430,7 +407,7 @@ public class NinePatchDrawable extends Drawable {
/**
* Updates the constant state from the values in the typed array.
*/
- private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException {
final Resources r = a.getResources();
final NinePatchState state = mNinePatchState;
@@ -491,12 +468,10 @@ public class NinePatchDrawable extends Drawable {
if (tint != null) {
state.mTint = tint;
}
-
- state.mTargetDensity = Drawable.resolveDensity(r, state.mTargetDensity);
}
@Override
- public void applyTheme(Theme t) {
+ public void applyTheme(@NonNull Theme t) {
super.applyTheme(t);
final NinePatchState state = mNinePatchState;
@@ -528,6 +503,7 @@ public class NinePatchDrawable extends Drawable {
return mNinePatchState != null && mNinePatchState.canApplyTheme();
}
+ @NonNull
public Paint getPaint() {
if (mPaint == null) {
mPaint = new Paint();
@@ -536,45 +512,26 @@ public class NinePatchDrawable extends Drawable {
return mPaint;
}
- /**
- * Retrieves the width of the source .png file (before resizing).
- */
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
- /**
- * Retrieves the height of the source .png file (before resizing).
- */
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
@Override
- public int getMinimumWidth() {
- return mBitmapWidth;
- }
-
- @Override
- public int getMinimumHeight() {
- return mBitmapHeight;
- }
-
- /**
- * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
- * value of OPAQUE or TRANSLUCENT.
- */
- @Override
public int getOpacity() {
- return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
- PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+ return mNinePatchState.mNinePatch.hasAlpha()
+ || (mPaint != null && mPaint.getAlpha() < 255) ?
+ PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
}
@Override
public Region getTransparentRegion() {
- return mNinePatch.getTransparentRegion(getBounds());
+ return mNinePatchState.mNinePatch.getTransparentRegion(getBounds());
}
@Override
@@ -587,7 +544,6 @@ public class NinePatchDrawable extends Drawable {
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mNinePatchState = new NinePatchState(mNinePatchState);
- mNinePatch = mNinePatchState.mNinePatch;
mMutated = true;
}
return this;
@@ -619,8 +575,9 @@ public class NinePatchDrawable extends Drawable {
}
final static class NinePatchState extends ConstantState {
+ int mChangingConfigurations;
+
// Values loaded during inflation.
- int[] mThemeAttrs = null;
NinePatch mNinePatch = null;
ColorStateList mTint = null;
Mode mTintMode = DEFAULT_TINT_MODE;
@@ -628,10 +585,9 @@ public class NinePatchDrawable extends Drawable {
Insets mOpticalInsets = Insets.NONE;
float mBaseAlpha = 1.0f;
boolean mDither = DEFAULT_DITHER;
- int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean mAutoMirrored = false;
- int mChangingConfigurations;
+ int[] mThemeAttrs;
NinePatchState() {
// Empty constructor.
@@ -655,27 +611,24 @@ public class NinePatchDrawable extends Drawable {
mAutoMirrored = autoMirror;
}
- // Copy constructor
-
- NinePatchState(@NonNull NinePatchState state) {
- // We don't deep-copy any fields because they are all immutable.
- mNinePatch = state.mNinePatch;
- mTint = state.mTint;
- mTintMode = state.mTintMode;
- mThemeAttrs = state.mThemeAttrs;
- mPadding = state.mPadding;
- mOpticalInsets = state.mOpticalInsets;
- mBaseAlpha = state.mBaseAlpha;
- mDither = state.mDither;
- mChangingConfigurations = state.mChangingConfigurations;
- mTargetDensity = state.mTargetDensity;
- mAutoMirrored = state.mAutoMirrored;
+ NinePatchState(@NonNull NinePatchState orig) {
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mNinePatch = orig.mNinePatch;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
+ mPadding = orig.mPadding;
+ mOpticalInsets = orig.mOpticalInsets;
+ mBaseAlpha = orig.mBaseAlpha;
+ mDither = orig.mDither;
+ mAutoMirrored = orig.mAutoMirrored;
+ mThemeAttrs = orig.mThemeAttrs;
}
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null
- || (mTint != null && mTint.canApplyTheme());
+ || (mTint != null && mTint.canApplyTheme())
+ || super.canApplyTheme();
}
@Override
@@ -704,44 +657,98 @@ public class NinePatchDrawable extends Drawable {
}
}
+ private void computeBitmapSize() {
+ final NinePatch ninePatch = mNinePatchState.mNinePatch;
+ if (ninePatch == null) {
+ return;
+ }
+
+ final int sourceDensity = ninePatch.getDensity();
+ final int targetDensity = mTargetDensity;
+
+ final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
+ if (sourceOpticalInsets != Insets.NONE) {
+ final int left = Drawable.scaleFromDensity(
+ sourceOpticalInsets.left, sourceDensity, targetDensity, true);
+ final int top = Drawable.scaleFromDensity(
+ sourceOpticalInsets.top, sourceDensity, targetDensity, true);
+ final int right = Drawable.scaleFromDensity(
+ sourceOpticalInsets.right, sourceDensity, targetDensity, true);
+ final int bottom = Drawable.scaleFromDensity(
+ sourceOpticalInsets.bottom, sourceDensity, targetDensity, true);
+ mOpticalInsets = Insets.of(left, top, right, bottom);
+ } else {
+ mOpticalInsets = Insets.NONE;
+ }
+
+ final Rect sourcePadding = mNinePatchState.mPadding;
+ if (sourcePadding != null) {
+ if (mPadding == null) {
+ mPadding = new Rect();
+ }
+ mPadding.left = Drawable.scaleFromDensity(
+ sourcePadding.left, sourceDensity, targetDensity, false);
+ mPadding.top = Drawable.scaleFromDensity(
+ sourcePadding.top, sourceDensity, targetDensity, false);
+ mPadding.right = Drawable.scaleFromDensity(
+ sourcePadding.right, sourceDensity, targetDensity, false);
+ mPadding.bottom = Drawable.scaleFromDensity(
+ sourcePadding.bottom, sourceDensity, targetDensity, false);
+ } else {
+ mPadding = null;
+ }
+
+ mBitmapHeight = Drawable.scaleFromDensity(
+ ninePatch.getHeight(), sourceDensity, targetDensity, true);
+ mBitmapWidth = Drawable.scaleFromDensity(
+ ninePatch.getWidth(), sourceDensity, targetDensity, true);
+
+ final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets();
+ if (insets != null) {
+ if (mOutlineInsets == null) {
+ mOutlineInsets = new Rect();
+ }
+ final Rect outlineInsets = insets.outlineRect;
+ mOutlineInsets.left = Drawable.scaleFromDensity(
+ outlineInsets.left, sourceDensity, targetDensity, false);
+ mOutlineInsets.top = Drawable.scaleFromDensity(
+ outlineInsets.top, sourceDensity, targetDensity, false);
+ mOutlineInsets.right = Drawable.scaleFromDensity(
+ outlineInsets.right, sourceDensity, targetDensity, false);
+ mOutlineInsets.bottom = Drawable.scaleFromDensity(
+ outlineInsets.bottom, sourceDensity, targetDensity, false);
+ mOutlineRadius = Drawable.scaleFromDensity(
+ insets.outlineRadius, sourceDensity, targetDensity);
+ } else {
+ mOutlineInsets = null;
+ }
+ }
+
/**
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
+ *
+ * @param state constant state to assign to the new drawable
*/
- private NinePatchDrawable(NinePatchState state, Resources res) {
+ private NinePatchDrawable(@NonNull NinePatchState state, @Nullable Resources res) {
mNinePatchState = state;
updateLocalState(res);
-
- // Push density applied by setNinePatchState into state.
- mNinePatchState.mTargetDensity = mTargetDensity;
}
/**
* Initializes local dynamic properties from state.
*/
- private void updateLocalState(Resources res) {
+ private void updateLocalState(@Nullable Resources res) {
final NinePatchState state = mNinePatchState;
- if (res != null) {
- final int densityDpi = res.getDisplayMetrics().densityDpi;
- mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
- } else {
- mTargetDensity = state.mTargetDensity;
- }
-
-
// If we can, avoid calling any methods that initialize Paint.
if (state.mDither != DEFAULT_DITHER) {
setDither(state.mDither);
}
- // Make a local copy of the padding.
- if (state.mPadding != null) {
- mPadding = new Rect(state.mPadding);
- }
-
+ mTargetDensity = Drawable.resolveDensity(res, mTargetDensity);
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
- setNinePatch(state.mNinePatch);
+ computeBitmapSize();
}
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 9c691e508535..ee0861ae60f5 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -251,6 +251,7 @@ public class RippleDrawable extends LayerDrawable {
boolean enabled = false;
boolean pressed = false;
boolean focused = false;
+ boolean hovered = false;
for (int state : stateSet) {
if (state == R.attr.state_enabled) {
@@ -259,11 +260,13 @@ public class RippleDrawable extends LayerDrawable {
focused = true;
} else if (state == R.attr.state_pressed) {
pressed = true;
+ } else if (state == R.attr.state_hovered) {
+ hovered = true;
}
}
setRippleActive(enabled && pressed);
- setBackgroundActive(focused || (enabled && pressed), focused);
+ setBackgroundActive(hovered || focused || (enabled && pressed), focused || hovered);
return changed;
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index bdbf3c04b000..9e0f1b460839 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -1482,8 +1482,9 @@ public class VectorDrawable extends Drawable {
if (mThemeAttrs != null) {
return true;
}
- boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
- boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+
+ boolean fillCanApplyTheme = canComplexColorApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canComplexColorApplyTheme(mStrokeColors);
if (fillCanApplyTheme || strokeCanApplyTheme) {
return true;
}
@@ -1493,30 +1494,42 @@ public class VectorDrawable extends Drawable {
@Override
public void applyTheme(Theme t) {
+ // Resolve the theme attributes directly referred by the VectorDrawable.
if (mThemeAttrs != null) {
final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
updateStateFromTypedArray(a);
a.recycle();
}
- boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
- boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+ // Resolve the theme attributes in-directly referred by the VectorDrawable, for example,
+ // fillColor can refer to a color state list which itself needs to apply theme.
+ // And this is the reason we still want to keep partial update for the path's properties.
+ boolean fillCanApplyTheme = canComplexColorApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canComplexColorApplyTheme(mStrokeColors);
+
if (fillCanApplyTheme) {
mFillColors = mFillColors.obtainForTheme(t);
- nUpdateFullPathFillGradient(mNativePtr,
- ((GradientColor)mFillColors).getShader().getNativeInstance());
+ if (mFillColors instanceof GradientColor) {
+ nUpdateFullPathFillGradient(mNativePtr,
+ ((GradientColor) mFillColors).getShader().getNativeInstance());
+ } else if (mFillColors instanceof ColorStateList) {
+ nSetFillColor(mNativePtr, mFillColors.getDefaultColor());
+ }
}
if (strokeCanApplyTheme) {
mStrokeColors = mStrokeColors.obtainForTheme(t);
- nUpdateFullPathStrokeGradient(mNativePtr,
- ((GradientColor)mStrokeColors).getShader().getNativeInstance());
+ if (mStrokeColors instanceof GradientColor) {
+ nUpdateFullPathStrokeGradient(mNativePtr,
+ ((GradientColor) mStrokeColors).getShader().getNativeInstance());
+ } else if (mStrokeColors instanceof ColorStateList) {
+ nSetStrokeColor(mNativePtr, mStrokeColors.getDefaultColor());
+ }
}
}
- private boolean canGradientApplyTheme(ComplexColor complexColor) {
- return complexColor != null && complexColor.canApplyTheme()
- && complexColor instanceof GradientColor;
+ private boolean canComplexColorApplyTheme(ComplexColor complexColor) {
+ return complexColor != null && complexColor.canApplyTheme();
}
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index c8333c87c69c..302b0bd73065 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -20,9 +20,11 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
+
import com.android.org.bouncycastle.util.io.pem.PemObject;
import com.android.org.bouncycastle.util.io.pem.PemReader;
import com.android.org.bouncycastle.util.io.pem.PemWriter;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -147,20 +149,23 @@ public class Credentials {
Reader reader = new InputStreamReader(bai, StandardCharsets.US_ASCII);
PemReader pr = new PemReader(reader);
- CertificateFactory cf = CertificateFactory.getInstance("X509");
-
- List<X509Certificate> result = new ArrayList<X509Certificate>();
- PemObject o;
- while ((o = pr.readPemObject()) != null) {
- if (o.getType().equals("CERTIFICATE")) {
- Certificate c = cf.generateCertificate(new ByteArrayInputStream(o.getContent()));
- result.add((X509Certificate) c);
- } else {
- throw new IllegalArgumentException("Unknown type " + o.getType());
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
+
+ List<X509Certificate> result = new ArrayList<X509Certificate>();
+ PemObject o;
+ while ((o = pr.readPemObject()) != null) {
+ if (o.getType().equals("CERTIFICATE")) {
+ Certificate c = cf.generateCertificate(new ByteArrayInputStream(o.getContent()));
+ result.add((X509Certificate) c);
+ } else {
+ throw new IllegalArgumentException("Unknown type " + o.getType());
+ }
}
+ return result;
+ } finally {
+ pr.close();
}
- pr.close();
- return result;
}
private static Credentials singleton;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 1b87a419941d..3090ac1c6180 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -19,7 +19,6 @@ package android.security;
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
-
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
@@ -32,6 +31,7 @@ import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterBlob;
+import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import android.security.keystore.KeyExpiredException;
@@ -615,6 +615,17 @@ public class KeyStore {
return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
}
+ public int attestKey(
+ String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
+ try {
+ return mBinder.attestKey(alias, params, outChain);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return SYSTEM_ERROR;
+ }
+ }
+
+
/**
* Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
* code.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index e6276a46bc3a..b234d0f81a89 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -233,7 +233,9 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
// not set up).
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds());
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment());
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -271,7 +273,9 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
KeymasterUtils.addUserAuthArgs(args,
spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds());
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 65460b5ceb29..1818f52c4fda 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -22,6 +22,7 @@ import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
@@ -46,6 +47,8 @@ import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import libcore.util.EmptyArray;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
@@ -57,14 +60,17 @@ import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -166,6 +172,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mOriginalKeymasterAlgorithm = keymasterAlgorithm;
}
+ @SuppressWarnings("deprecation")
@Override
public void initialize(int keysize, SecureRandom random) {
throw new IllegalArgumentException(
@@ -173,6 +180,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
+ " required to initialize this KeyPairGenerator");
}
+ @SuppressWarnings("deprecation")
@Override
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
@@ -336,7 +344,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
// not set up).
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds());
+ mSpec.getUserAuthenticationValidityDurationSeconds(),
+ mSpec.isUserAuthenticationValidWhileOnBody(),
+ mSpec.isInvalidatedByBiometricEnrollment());
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -447,6 +457,69 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
+ ", but the user has not yet entered the credential");
}
+ byte[] additionalEntropy =
+ KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
+ mRng, (mKeySizeBits + 7) / 8);
+
+ Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
+ final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
+ boolean success = false;
+ try {
+ generateKeystoreKeyPair(
+ privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
+ KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
+
+ storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
+
+ success = true;
+ return keyPair;
+ } finally {
+ if (!success) {
+ Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
+ }
+ }
+ }
+
+ private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
+ throws ProviderException {
+ byte[] challenge = mSpec.getAttestationChallenge();
+ if (challenge != null) {
+ KeymasterArguments args = new KeymasterArguments();
+ args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
+ return getAttestationChain(privateKeyAlias, keyPair, args);
+ }
+
+ // Very short certificate chain in the non-attestation case.
+ return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
+ }
+
+ private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
+ byte[] additionalEntropy, final int flags) throws ProviderException {
+ KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
+ int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
+ mEntryUid, flags, resultingKeyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new ProviderException(
+ "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+ }
+ }
+
+ private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
+ try {
+ KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ mKeyStore, privateKeyAlias, mEntryUid);
+ if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
+ throw new ProviderException(
+ "Generated key pair algorithm does not match requested algorithm: "
+ + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
+ }
+ return result;
+ } catch (UnrecoverableKeyException e) {
+ throw new ProviderException("Failed to load generated key pair from keystore", e);
+ }
+ }
+
+ private KeymasterArguments constructKeyGenerationArguments() {
KeymasterArguments args = new KeymasterArguments();
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
@@ -458,7 +531,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
KeymasterUtils.addUserAuthArgs(args,
mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds());
+ mSpec.getUserAuthenticationValidityDurationSeconds(),
+ mSpec.isUserAuthenticationValidWhileOnBody(),
+ mSpec.isInvalidatedByBiometricEnrollment());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
@@ -466,73 +541,72 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.getKeyValidityForConsumptionEnd());
addAlgorithmSpecificParameters(args);
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, (mKeySizeBits + 7) / 8);
+ if (mSpec.isUniqueIdIncluded())
+ args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
- final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
- boolean success = false;
- try {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.generateKey(
- privateKeyAlias,
- args,
- additionalEntropy,
- mEntryUid,
- flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(
- "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
- }
+ return args;
+ }
- KeyPair result;
- try {
- result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- mKeyStore, privateKeyAlias, mEntryUid);
- } catch (UnrecoverableKeyException e) {
- throw new ProviderException("Failed to load generated key pair from keystore", e);
- }
+ private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
+ throws ProviderException {
+ Iterator<byte[]> iter = iterable.iterator();
+ storeCertificate(
+ Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
- if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
- throw new ProviderException(
- "Generated key pair algorithm does not match requested algorithm: "
- + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
- }
+ if (!iter.hasNext()) {
+ return;
+ }
- final X509Certificate cert;
- try {
- cert = generateSelfSignedCertificate(result.getPrivate(), result.getPublic());
- } catch (Exception e) {
- throw new ProviderException("Failed to generate self-signed certificate", e);
- }
+ ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
+ while (iter.hasNext()) {
+ byte[] data = iter.next();
+ certificateConcatenationStream.write(data, 0, data.length);
+ }
- byte[] certBytes;
- try {
- certBytes = cert.getEncoded();
- } catch (CertificateEncodingException e) {
- throw new ProviderException(
- "Failed to obtain encoded form of self-signed certificate", e);
- }
+ storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
+ flags, "Failed to store attestation CA certificate");
+ }
- int insertErrorCode = mKeyStore.insert(
- Credentials.USER_CERTIFICATE + mEntryAlias,
- certBytes,
- mEntryUid,
- flags);
- if (insertErrorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to store self-signed certificate",
- KeyStore.getKeyStoreException(insertErrorCode));
- }
+ private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
+ String failureMessage) throws ProviderException {
+ int insertErrorCode = mKeyStore.insert(
+ prefix + mEntryAlias,
+ certificateBytes,
+ mEntryUid,
+ flags);
+ if (insertErrorCode != KeyStore.NO_ERROR) {
+ throw new ProviderException(failureMessage,
+ KeyStore.getKeyStoreException(insertErrorCode));
+ }
+ }
- success = true;
- return result;
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- }
+ private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
+ try {
+ return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
+ .getEncoded();
+ } catch (IOException | CertificateParsingException e) {
+ throw new ProviderException("Failed to generate self-signed certificate", e);
+ } catch (CertificateEncodingException e) {
+ throw new ProviderException(
+ "Failed to obtain encoded form of self-signed certificate", e);
+ }
+ }
+
+ private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
+ KeyPair keyPair, KeymasterArguments args)
+ throws ProviderException {
+ KeymasterCertificateChain outChain = new KeymasterCertificateChain();
+ int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new ProviderException("Failed to generate attestation certificate chain",
+ KeyStore.getKeyStoreException(errorCode));
+ }
+ Collection<byte[]> chain = outChain.getCertificates();
+ if (chain.size() < 2) {
+ throw new ProviderException("Attestation certificate chain contained "
+ + chain.size() + " entries. At least two are required.");
}
+ return chain;
}
private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
@@ -548,8 +622,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
}
- private X509Certificate generateSelfSignedCertificate(
- PrivateKey privateKey, PublicKey publicKey) throws Exception {
+ private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
+ PublicKey publicKey) throws CertificateParsingException, IOException {
String signatureAlgorithm =
getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
if (signatureAlgorithm == null) {
@@ -587,7 +661,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
@SuppressWarnings("deprecation")
private X509Certificate generateSelfSignedCertificateWithFakeSignature(
- PublicKey publicKey) throws Exception {
+ PublicKey publicKey) throws IOException, CertificateParsingException {
V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
ASN1ObjectIdentifier sigAlgOid;
AlgorithmIdentifier sigAlgId;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 8d606bf97d0c..0379863e8ca1 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -17,10 +17,12 @@
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.KeymasterDefs;
+import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.ProviderException;
import java.security.spec.InvalidKeySpecException;
@@ -91,6 +93,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
@KeyProperties.BlockModeEnum String[] blockModes;
int keymasterSwEnforcedUserAuthenticators;
int keymasterHwEnforcedUserAuthenticators;
+ List<BigInteger> keymasterSecureUserIds;
try {
if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
insideSecureHardware = true;
@@ -147,6 +150,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
keymasterHwEnforcedUserAuthenticators =
keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+ keymasterSecureUserIds =
+ keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
} catch (IllegalArgumentException e) {
throw new ProviderException("Unsupported key characteristic", e);
}
@@ -167,6 +172,17 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
&& (keymasterHwEnforcedUserAuthenticators != 0)
&& (keymasterSwEnforcedUserAuthenticators == 0);
+ boolean userAuthenticationValidWhileOnBody =
+ keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+
+ boolean invalidatedByBiometricEnrollment = false;
+ if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT
+ || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) {
+ // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
+ invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
+ && !keymasterSecureUserIds.isEmpty()
+ && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
+ }
return new KeyInfo(entryAlias,
insideSecureHardware,
@@ -182,7 +198,17 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
blockModes,
userAuthenticationRequired,
(int) userAuthenticationValidityDurationSeconds,
- userAuthenticationRequirementEnforcedBySecureHardware);
+ userAuthenticationRequirementEnforcedBySecureHardware,
+ userAuthenticationValidWhileOnBody,
+ invalidatedByBiometricEnrollment);
+ }
+
+ private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
+ try {
+ return BigInteger.valueOf(GateKeeper.getSecureUserId());
+ } catch (IllegalStateException e) {
+ throw new ProviderException("Failed to get GateKeeper secure user ID", e);
+ }
}
@Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index cdcc7a2db5b2..d7d4f1c50e32 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -498,7 +498,9 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
KeymasterUtils.addUserAuthArgs(importArgs,
spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds());
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody(),
+ spec.isInvalidatedByBiometricEnrollment());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -692,7 +694,9 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
KeymasterUtils.addUserAuthArgs(args,
params.isUserAuthenticationRequired(),
- params.getUserAuthenticationValidityDurationSeconds());
+ params.getUserAuthenticationValidityDurationSeconds(),
+ params.isUserAuthenticationValidWhileOnBody(),
+ params.isInvalidatedByBiometricEnrollment());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index add199f139a0..127d756a2cff 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -250,6 +250,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final byte[] mAttestationChallenge;
+ private final boolean mUniqueIdIncluded;
+ private final boolean mUserAuthenticationValidWhileOnBody;
+ private final boolean mInvalidatedByBiometricEnrollment;
/**
* @hide should be built with Builder
@@ -273,7 +277,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
@KeyProperties.BlockModeEnum String[] blockModes,
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ byte[] attestationChallenge,
+ boolean uniqueIdIncluded,
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -315,6 +323,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
+ mUniqueIdIncluded = uniqueIdIncluded;
+ mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+ mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
}
/**
@@ -539,6 +551,78 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
}
/**
+ * Returns the attestation challenge value that will be placed in attestation certificate for
+ * this key pair.
+ *
+ * <p>If this method returns non-{@code null}, the public key certificate for this key pair will
+ * contain an extension that describes the details of the key's configuration and
+ * authorizations, including the content of the attestation challenge value. If the key is in
+ * secure hardware, and if the secure hardware supports attestation, the certificate will be
+ * signed by a chain of certificates rooted at a trustworthy CA key. Otherwise the chain will
+ * be rooted at an untrusted certificate.
+ *
+ * <p>If this method returns {@code null}, and the spec is used to generate an asymmetric (RSA
+ * or EC) key pair, the public key will have a self-signed certificate if it has purpose {@link
+ * KeyProperties#PURPOSE_SIGN} (see {@link #KeyGenParameterSpec(String, int)). If does not have
+ * purpose {@link KeyProperties#PURPOSE_SIGN}, it will have a fake certificate.
+ *
+ * <p>Symmetric keys, such as AES and HMAC keys, do not have public key certificates. If a
+ * {@link KeyGenParameterSpec} with {@link #hasAttestationCertificate()} returning
+ * non-{@code null} is used to generate a symmetric (AES or HMAC) key,
+ * {@link KeyGenerator#generateKey())} will throw
+ * {@link java.security.InvalidAlgorithmParameterException}.
+ *
+ * @see Builder#setAttestationChallenge(byte[])
+ */
+ /*
+ * TODO(swillden): Update this documentation to describe the hardware and software root keys,
+ * including information about CRL/OCSP services for discovering revocations, and to link to
+ * documentation of the extension format and content.
+ */
+ public byte[] getAttestationChallenge() {
+ return Utils.cloneIfNotNull(mAttestationChallenge);
+ }
+
+ /**
+ * @hide This is a system-only API
+ *
+ * Returns {@code true} if the attestation certificate will contain a unique ID field.
+ */
+ public boolean isUniqueIdIncluded() {
+ return mUniqueIdIncluded;
+ }
+
+ /**
+ * Returns {@code true} if the key will remain authorized while the device is on the user's
+ * body, even after the validity duration has expired. This option has no effect on keys that
+ * don't have an authentication validity duration, and has no effect if the device lacks a
+ * secure on-body sensor.
+ *
+ * <p>Authorization applies only to secret key and private key operations. Public key operations
+ * are not restricted.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setUserAuthenticationValidWhileOnBody(boolean)
+ */
+ public boolean isUserAuthenticationValidWhileOnBody() {
+ return mUserAuthenticationValidWhileOnBody;
+ }
+
+ /**
+ * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
+ * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
+ * require fingerprint user authentication for every use.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setInvalidatedByBiometricEnrollment(boolean)
+ */
+ public boolean isInvalidatedByBiometricEnrollment() {
+ return mInvalidatedByBiometricEnrollment;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -562,6 +646,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private byte[] mAttestationChallenge = null;
+ private boolean mUniqueIdIncluded = false;
+ private boolean mUserAuthenticationValidWhileOnBody;
+ private boolean mInvalidatedByBiometricEnrollment = true;
/**
* Creates a new instance of the {@code Builder}.
@@ -895,8 +983,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
* Additionally, if the key requires that user authentication takes place for every use of
* the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
- * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
- * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
+ * no more fingerprints are enrolled, unless {@link
+ * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
+ * enrollment. Attempts to initialize cryptographic operations using such keys will throw
+ * {@link KeyPermanentlyInvalidatedException}.</li>
* </ul>
*
* <p>This authorization applies only to secret key and private key operations. Public key
@@ -957,6 +1047,111 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
return this;
}
+ /*
+ * TODO(swillden): Update this documentation to describe the hardware and software root
+ * keys, including information about CRL/OCSP services for discovering revocations, and to
+ * link to documentation of the extension format and content.
+ */
+ /**
+ * Sets whether an attestation certificate will be generated for this key pair, and what
+ * challenge value will be placed in the certificate. The attestation certificate chain
+ * can be retrieved with with {@link java.security.KeyStore#getCertificateChain(String)}.
+ *
+ * <p>If {@code attestationChallenge} is not {@code null}, the public key certificate for
+ * this key pair will contain an extension that describes the details of the key's
+ * configuration and authorizations, including the {@code attestationChallenge} value. If
+ * the key is in secure hardware, and if the secure hardware supports attestation, the
+ * certificate will be signed by a chain of certificates rooted at a trustworthy CA key.
+ * Otherwise the chain will be rooted at an untrusted certificate.
+ *
+ * <p>The purpose of the challenge value is to enable relying parties to verify that the key
+ * was created in response to a specific request. If attestation is desired but no
+ * challenged is needed, any non-{@code null} value may be used, including an empty byte
+ * array.
+ *
+ * <p>If {@code attestationChallenge} is {@code null}, and this spec is used to generate an
+ * asymmetric (RSA or EC) key pair, the public key certificate will be self-signed if the
+ * key has purpose {@link KeyProperties#PURPOSE_SIGN} (see
+ * {@link #KeyGenParameterSpec(String, int)). If the key does not have purpose
+ * {@link KeyProperties#PURPOSE_SIGN}, it is not possible to use the key to sign a
+ * certificate, so the public key certificate will contain a dummy signature.
+ *
+ * <p>Symmetric keys, such as AES and HMAC keys, do not have public key certificates. If a
+ * {@code getAttestationChallenge} returns non-{@code null} and the spec is used to
+ * generate a symmetric (AES or HMAC) key, {@link KeyGenerator#generateKey()} will throw
+ * {@link java.security.InvalidAlgorithmParameterException}.
+ *
+ * @see Builder#setAttestationChallenge(String attestationChallenge)
+ */
+ @NonNull
+ public Builder setAttestationChallenge(byte[] attestationChallenge) {
+ mAttestationChallenge = attestationChallenge;
+ return this;
+ }
+
+ /**
+ * @hide Only system apps can use this method.
+ *
+ * Sets whether to include a temporary unique ID field in the attestation certificate.
+ */
+ @NonNull
+ public Builder setUniqueIdIncluded(boolean uniqueIdIncluded) {
+ mUniqueIdIncluded = uniqueIdIncluded;
+ return this;
+ }
+
+ /**
+ * Sets whether the key is authorized for use after the authentication validity period is
+ * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link
+ * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the
+ * device has not been removed from the user's body since the last successful
+ * authentication.
+ *
+ * <p>On devices that do not have a secure on-body sensor, creating a key with this
+ * parameter set to {@code true} will have no effect; the private or secret key will no
+ * longer be authorized for use after the validity period ends, and a fresh authentication
+ * will be required to use it again.
+ *
+ * <p>Note that "secure" on-body sensors are required by Android to have a secure path to
+ * the secure hardware, but the sensors themselves may not be difficult to fool. It is
+ * recommended that this feature be used to increase slightly the security of keys which
+ * would otherwise have to allow unauthenticated access, or have a very long validity
+ * period. Keys that require high assurance of user authorization should not use this
+ * feature and should set a short validity period.
+ *
+ * @param remainsValid if {@code true}, and if the device supports secure on-body detection,
+ * key will remain valid after authentication validity duration has expired.
+ */
+ @NonNull
+ public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
+ mUserAuthenticationValidWhileOnBody = remainsValid;
+ return this;
+ }
+
+ /**
+ * Sets whether this key should be invalidated on fingerprint enrollment. This
+ * applies only to keys which require user authentication (see {@link
+ * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
+ * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
+ * valid for fingerprint authentication only.
+ *
+ * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
+ * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
+ * fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
+ * changed by calling this method with {@code invalidateKey} set to {@code false}.
+ *
+ * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+ * improves security by ensuring that an unauthorized person who obtains the password can't
+ * gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
+ * invalidating keys makes key-dependent operations impossible, requiring some fallback
+ * procedure to authenticate the user and set up a new key.
+ */
+ @NonNull
+ public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
+ mInvalidatedByBiometricEnrollment = invalidateKey;
+ return this;
+ }
+
/**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@@ -981,7 +1176,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mAttestationChallenge,
+ mUniqueIdIncluded,
+ mUserAuthenticationValidWhileOnBody,
+ mInvalidatedByBiometricEnrollment);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index d72688079d0e..fa6d8b3517f6 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -79,6 +79,8 @@ public class KeyInfo implements KeySpec {
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
+ private final boolean mUserAuthenticationValidWhileOnBody;
+ private final boolean mInvalidatedByBiometricEnrollment;
/**
* @hide
@@ -97,7 +99,9 @@ public class KeyInfo implements KeySpec {
@KeyProperties.BlockModeEnum String[] blockModes,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationRequirementEnforcedBySecureHardware) {
+ boolean userAuthenticationRequirementEnforcedBySecureHardware,
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
mKeystoreAlias = keystoreKeyAlias;
mInsideSecureHardware = insideSecureHardware;
mOrigin = origin;
@@ -116,6 +120,8 @@ public class KeyInfo implements KeySpec {
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
mUserAuthenticationRequirementEnforcedBySecureHardware =
userAuthenticationRequirementEnforcedBySecureHardware;
+ mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+ mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
}
/**
@@ -277,4 +283,22 @@ public class KeyInfo implements KeySpec {
public boolean isUserAuthenticationRequirementEnforcedBySecureHardware() {
return mUserAuthenticationRequirementEnforcedBySecureHardware;
}
+
+ /**
+ * Returns {@code true} if this key will remain usable after its specified validity duration
+ * for as long as the device remains on the user's body. This is possible only for keys with
+ * a specified validity duration. Always returns {@code false} on devices that lack a secure
+ * on-body sensor.
+ */
+ public boolean isUserAuthenticationValidWhileOnBody() {
+ return mUserAuthenticationValidWhileOnBody;
+ }
+
+ /**
+ * Returns {@code true} if the key will be invalidated by enrollment of a new fingerprint or
+ * removal of all fingerprints.
+ */
+ public boolean isInvalidatedByBiometricEnrollment() {
+ return mInvalidatedByBiometricEnrollment;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index c98443978105..fa57bdb52b32 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -214,6 +214,8 @@ public final class KeyProtection implements ProtectionParameter {
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final boolean mUserAuthenticationValidWhileOnBody;
+ private final boolean mInvalidatedByBiometricEnrollment;
private KeyProtection(
Date keyValidityStart,
@@ -226,7 +228,9 @@ public final class KeyProtection implements ProtectionParameter {
@KeyProperties.BlockModeEnum String[] blockModes,
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -240,6 +244,8 @@ public final class KeyProtection implements ProtectionParameter {
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+ mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
}
/**
@@ -392,6 +398,36 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Returns {@code true} if the key will remain authorized while the device is on the user's
+ * body, even after the validity duration has expired. This option has no effect on keys that
+ * don't have an authentication validity duration, and has no effect if the device lacks a
+ * secure on-body sensor.
+ *
+ * <p>Authorization applies only to secret key and private key operations. Public key operations
+ * are not restricted.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setUserAuthenticationValidWhileOnBody(boolean)
+ */
+ public boolean isUserAuthenticationValidWhileOnBody() {
+ return mUserAuthenticationValidWhileOnBody;
+ }
+
+ /**
+ * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
+ * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
+ * require fingerprint user authentication for every use.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setInvalidatedByBiometricEnrollment(boolean)
+ */
+ public boolean isInvalidatedByBiometricEnrollment() {
+ return mInvalidatedByBiometricEnrollment;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -407,6 +443,8 @@ public final class KeyProtection implements ProtectionParameter {
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private boolean mUserAuthenticationValidWhileOnBody;
+ private boolean mInvalidatedByBiometricEnrollment = true;
/**
* Creates a new instance of the {@code Builder}.
@@ -617,9 +655,10 @@ public final class KeyProtection implements ProtectionParameter {
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
* Additionally, if the key requires that user authentication takes place for every use of
* the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
- * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
- * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
- * </ul>
+ * no more fingerprints are enrolled, unless {@link
+ * #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
+ * enrollment. Attempts to initialize cryptographic operations using such keys will throw
+ * {@link KeyPermanentlyInvalidatedException}.</li> </ul>
*
* <p>This authorization applies only to secret key and private key operations. Public key
* operations are not restricted.
@@ -680,6 +719,58 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Sets whether the key is authorized for use after the authentication validity period is
+ * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link
+ * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the
+ * device has not been removed from the user's body since the last successful
+ * authentication.
+ *
+ * <p>On devices that do not have a secure on-body sensor, creating a key with this
+ * parameter set to {@code true} will have no effect; the private or secret key will no
+ * longer be authorized for use after the validity period ends, and a fresh authentication
+ * will be required to use it again.
+ *
+ * <p>Note that "secure" on-body sensors are required by Android to have a secure path to
+ * the secure hardware, but the sensors themselves may not be difficult to fool. It is
+ * recommended that this feature be used to increase slightly the security of keys which
+ * would otherwise have to allow unauthenticated access, or have a very long validity
+ * period. Keys that require high assurance of user authorization should not use this
+ * feature and should set a short validity period.
+ *
+ * @param remainsValid if {@code true}, and if the device supports secure on-body detection,
+ * key will remain valid after authentication validity duration has expired.
+ */
+ @NonNull
+ public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
+ mUserAuthenticationValidWhileOnBody = remainsValid;
+ return this;
+ }
+
+ /**
+ * Sets whether this key should be invalidated on fingerprint enrollment. This
+ * applies only to keys which require user authentication (see {@link
+ * #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
+ * set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
+ * valid for fingerprint authentication only.
+ *
+ * <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
+ * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
+ * fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
+ * changed by calling this method with {@code invalidateKey} set to {@code false}.
+ *
+ * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+ * improves security by ensuring that an unauthorized person who obtains the password can't
+ * gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
+ * invalidating keys makes key-dependent operations impossible, requiring some fallback
+ * procedure to authenticate the user and set up a new key.
+ */
+ @NonNull
+ public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
+ mInvalidatedByBiometricEnrollment = invalidateKey;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -697,7 +788,9 @@ public final class KeyProtection implements ProtectionParameter {
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mUserAuthenticationValidWhileOnBody,
+ mInvalidatedByBiometricEnrollment);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index feafbfa65394..f5272aa233e9 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -96,7 +96,9 @@ public abstract class KeymasterUtils {
*/
public static void addUserAuthArgs(KeymasterArguments args,
boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean userAuthenticationValidWhileOnBody,
+ boolean invalidatedByBiometricEnrollment) {
if (!userAuthenticationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
@@ -116,23 +118,38 @@ public abstract class KeymasterUtils {
"At least one fingerprint must be enrolled to create keys requiring user"
+ " authentication for every use");
}
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(fingerprintOnlySid));
+
+ long sid;
+ if (invalidatedByBiometricEnrollment) {
+ // The fingerprint-only SID will change on fingerprint enrollment or removal of all,
+ // enrolled fingerprints, invalidating the key.
+ sid = fingerprintOnlySid;
+ } else {
+ // The root SID will *not* change on fingerprint enrollment, or removal of all
+ // enrolled fingerprints, allowing the key to remain valid.
+ sid = getRootSid();
+ }
+
+ args.addUnsignedLong(
+ KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
+ if (userAuthenticationValidWhileOnBody) {
+ throw new ProviderException("Key validity extension while device is on-body is not "
+ + "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 = GateKeeper.getSecureUserId();
- if (rootSid == 0) {
- throw new IllegalStateException("Secure lock screen must be enabled"
- + " to create keys requiring user authentication");
- }
+ long rootSid = getRootSid();
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
KeymasterArguments.toUint64(rootSid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
userAuthenticationValidityDurationSeconds);
+ if (userAuthenticationValidWhileOnBody) {
+ args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+ }
}
}
@@ -176,4 +193,13 @@ public abstract class KeymasterUtils {
break;
}
}
+
+ private static long getRootSid() {
+ long rootSid = GateKeeper.getSecureUserId();
+ if (rootSid == 0) {
+ throw new IllegalStateException("Secure lock screen must be enabled"
+ + " to create keys requiring user authentication");
+ }
+ return rootSid;
+ }
}
diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java
index 9bec6821c252..5722c7b53ef4 100644
--- a/keystore/java/android/security/keystore/Utils.java
+++ b/keystore/java/android/security/keystore/Utils.java
@@ -29,4 +29,8 @@ abstract class Utils {
static Date cloneIfNotNull(Date value) {
return (value != null) ? (Date) value.clone() : null;
}
+
+ static byte[] cloneIfNotNull(byte[] value) {
+ return (value != null) ? value.clone() : null;
+ }
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1d9fe35bac35..3277c36c8a33 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2236,7 +2236,7 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
// See if any of the regions is better than the other
const int region_comparison = localeDataCompareRegions(
country, o.country,
- language, localeScript, requested->country);
+ language, requested->localeScript, requested->country);
if (region_comparison != 0) {
return (region_comparison > 0);
}
@@ -2526,17 +2526,34 @@ bool ResTable_config::match(const ResTable_config& settings) const {
// For backward compatibility and supporting private-use locales, we
// fall back to old behavior if we couldn't determine the script for
- // either of the desired locale or the provided locale.
- if (localeScript[0] == '\0' || localeScript[1] == '\0') {
+ // either of the desired locale or the provided locale. But if we could determine
+ // the scripts, they should be the same for the locales to match.
+ bool countriesMustMatch = false;
+ char computed_script[4];
+ const char* script;
+ if (settings.localeScript[0] == '\0') { // could not determine the request's script
+ countriesMustMatch = true;
+ } else {
+ if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
+ localeDataComputeScript(computed_script, language, country);
+ if (computed_script[0] == '\0') { // we could not compute the script
+ countriesMustMatch = true;
+ } else {
+ script = computed_script;
+ }
+ } else { // script was provided, so just use it
+ script = localeScript;
+ }
+ }
+
+ if (countriesMustMatch) {
if (country[0] != '\0'
&& (country[0] != settings.country[0]
|| country[1] != settings.country[1])) {
return false;
}
} else {
- // But if we could determine the scripts, they should be the same
- // for the locales to match.
- if (memcmp(localeScript, settings.localeScript, sizeof(localeScript)) != 0) {
+ if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
return false;
}
}
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 7b386404fe8c..4b8d65cf86b4 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -371,6 +371,19 @@ TEST(ConfigLocaleTest, match) {
EXPECT_TRUE(supported.match(requested));
}
+TEST(ConfigLocaleTest, match_emptyScript) {
+ ResTable_config supported, requested;
+
+ fillIn("fr", "FR", NULL, NULL, &supported);
+ fillIn("fr", "CA", NULL, NULL, &requested);
+
+ // emulate packages built with older AAPT
+ memset(supported.localeScript, '\0', 4);
+ supported.localeScriptWasProvided = false;
+
+ EXPECT_TRUE(supported.match(requested));
+}
+
TEST(ConfigLocaleTest, isLocaleBetterThan_basics) {
ResTable_config config1, config2, request;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1f242a36e80e..54b453d044b4 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,12 +2,12 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-HWUI_NEW_OPS := true
+HWUI_NEW_OPS := 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 := \
font/CacheTexture.cpp \
@@ -119,6 +119,7 @@ ifeq (true, $(HWUI_NEW_OPS))
BakedOpState.cpp \
FrameBuilder.cpp \
LayerBuilder.cpp \
+ OpDumper.cpp \
RecordingCanvas.cpp
hwui_cflags += -DHWUI_NEW_OPS
@@ -144,20 +145,8 @@ hwui_c_includes += \
external/skia/include/private \
external/skia/src/core
-hwui_shared_libraries := \
- liblog \
- libcutils \
- libutils \
- libEGL \
- libGLESv2 \
- libskia \
- libui \
- libgui \
- libprotobuf-cpp-lite \
-
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
- hwui_shared_libraries += libRS libRScpp
hwui_c_includes += \
$(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
frameworks/rs/cpp \
@@ -180,12 +169,15 @@ include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE := libhwui_static
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := $(hwui_cflags)
LOCAL_SRC_FILES := $(hwui_src_files)
LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(hwui_c_includes) \
+ $(call hwui_proto_include)
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_STATIC_LIBRARY)
# ------------------------
@@ -196,7 +188,6 @@ include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE := libhwui_static_null_gpu
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := \
$(hwui_cflags) \
-DHWUI_NULL_GPU
@@ -205,8 +196,12 @@ LOCAL_SRC_FILES := \
debug/nullegl.cpp \
debug/nullgles.cpp
LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(hwui_c_includes) \
+ $(call hwui_proto_include)
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_STATIC_LIBRARY)
# ------------------------
@@ -218,8 +213,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE := libhwui
LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_SHARED_LIBRARY)
# ------------------------
@@ -230,7 +226,6 @@ include $(CLEAR_VARS)
LOCAL_MODULE := hwui_unit_tests
LOCAL_MODULE_TAGS := tests
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_STATIC_LIBRARIES := libhwui_static_null_gpu
LOCAL_CFLAGS := \
$(hwui_cflags) \
@@ -238,7 +233,6 @@ LOCAL_CFLAGS := \
LOCAL_SRC_FILES += \
$(hwui_test_common_src_files) \
- tests/unit/BufferPoolTests.cpp \
tests/unit/CanvasStateTests.cpp \
tests/unit/ClipAreaTests.cpp \
tests/unit/CrashHandlerInjector.cpp \
@@ -248,6 +242,7 @@ LOCAL_SRC_FILES += \
tests/unit/GpuMemoryTrackerTests.cpp \
tests/unit/LayerUpdateQueueTests.cpp \
tests/unit/LinearAllocatorTests.cpp \
+ tests/unit/MatrixTests.cpp \
tests/unit/OffscreenBufferPoolTests.cpp \
tests/unit/SkiaBehaviorTests.cpp \
tests/unit/StringUtilsTests.cpp \
@@ -260,9 +255,11 @@ ifeq (true, $(HWUI_NEW_OPS))
tests/unit/BakedOpStateTests.cpp \
tests/unit/FrameBuilderTests.cpp \
tests/unit/LeakCheckTests.cpp \
+ tests/unit/OpDumperTests.cpp \
tests/unit/RecordingCanvasTests.cpp
endif
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_NATIVE_TEST)
# ------------------------
@@ -278,7 +275,6 @@ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := hwuitest
LOCAL_MODULE_STEM_64 := hwuitest64
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := $(hwui_cflags)
# set to libhwui_static_null_gpu to skip actual GL commands
@@ -289,6 +285,7 @@ LOCAL_SRC_FILES += \
tests/macrobench/TestSceneRunner.cpp \
tests/macrobench/main.cpp
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_EXECUTABLE)
# ------------------------
@@ -303,7 +300,6 @@ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := hwuimicro
LOCAL_MODULE_STEM_64 := hwuimicro64
-LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
LOCAL_CFLAGS := \
$(hwui_cflags) \
-DHWUI_NULL_GPU
@@ -325,6 +321,5 @@ ifeq (true, $(HWUI_NEW_OPS))
tests/microbench/FrameBuilderBench.cpp
endif
-LOCAL_CLANG := true # workaround gcc bug
-
+include $(LOCAL_PATH)/hwui_static_deps.mk
include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 7bd2b24bf56b..bd71e0d579f8 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -33,6 +33,7 @@ namespace uirenderer {
BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
: mTarget(nullptr)
+ , mStagingTarget(nullptr)
, mFinalValue(finalValue)
, mDeltaValue(0)
, mFromValue(0)
@@ -42,7 +43,8 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
, mStartTime(0)
, mDuration(300)
, mStartDelay(0)
- , mMayRunAsync(true) {
+ , mMayRunAsync(true)
+ , mPlayTime(0) {
}
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -81,26 +83,133 @@ void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
}
void BaseRenderNodeAnimator::attach(RenderNode* target) {
- mTarget = target;
+ mStagingTarget = target;
onAttached();
}
+void BaseRenderNodeAnimator::start() {
+ mStagingPlayState = PlayState::Running;
+ mStagingRequests.push_back(Request::Start);
+ onStagingPlayStateChanged();
+}
+
+void BaseRenderNodeAnimator::cancel() {
+ mStagingPlayState = PlayState::Finished;
+ mStagingRequests.push_back(Request::Cancel);
+ onStagingPlayStateChanged();
+}
+
+void BaseRenderNodeAnimator::reset() {
+ mStagingPlayState = PlayState::Finished;
+ mStagingRequests.push_back(Request::Reset);
+ onStagingPlayStateChanged();
+}
+
+void BaseRenderNodeAnimator::reverse() {
+ mStagingPlayState = PlayState::Reversing;
+ mStagingRequests.push_back(Request::Reverse);
+ onStagingPlayStateChanged();
+}
+
+void BaseRenderNodeAnimator::end() {
+ mStagingPlayState = PlayState::Finished;
+ mStagingRequests.push_back(Request::End);
+ onStagingPlayStateChanged();
+}
+
+void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
+ switch (request) {
+ case Request::Start:
+ mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
+ mPlayTime : 0;
+ mPlayState = PlayState::Running;
+ break;
+ case Request::Reverse:
+ mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
+ mPlayTime : mDuration;
+ mPlayState = PlayState::Reversing;
+ break;
+ case Request::Reset:
+ mPlayTime = 0;
+ mPlayState = PlayState::Finished;
+ break;
+ case Request::Cancel:
+ mPlayState = PlayState::Finished;
+ break;
+ case Request::End:
+ mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
+ mPlayState = PlayState::Finished;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
+ };
+}
+
void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
+ if (mStagingTarget) {
+ RenderNode* oldTarget = mTarget;
+ mTarget = mStagingTarget;
+ mStagingTarget = nullptr;
+ if (oldTarget && oldTarget != mTarget) {
+ oldTarget->onAnimatorTargetChanged(this);
+ }
+ }
+
if (!mHasStartValue) {
doSetStartValue(getValue(mTarget));
}
- if (mStagingPlayState > mPlayState) {
- if (mStagingPlayState == PlayState::Restarted) {
- mStagingPlayState = PlayState::Running;
+
+ if (!mStagingRequests.empty()) {
+ // No interpolator was set, use the default
+ if (mPlayState == PlayState::NotStarted && !mInterpolator) {
+ mInterpolator.reset(Interpolator::createDefaultInterpolator());
}
- mPlayState = mStagingPlayState;
- // Oh boy, we're starting! Man the battle stations!
- if (mPlayState == PlayState::Running) {
- transitionToRunning(context);
- } else if (mPlayState == PlayState::Finished) {
+ // Keep track of the play state and play time before they are changed when
+ // staging requests are resolved.
+ nsecs_t currentPlayTime = mPlayTime;
+ PlayState prevFramePlayState = mPlayState;
+
+ // Resolve staging requests one by one.
+ for (Request request : mStagingRequests) {
+ resolveStagingRequest(request);
+ }
+ mStagingRequests.clear();
+
+ if (mStagingPlayState == PlayState::Finished) {
+ // Set the staging play time and end the animation
+ updatePlayTime(mPlayTime);
callOnFinishedListener(context);
+ } else if (mStagingPlayState == PlayState::Running
+ || mStagingPlayState == PlayState::Reversing) {
+ bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
+ if (prevFramePlayState != mStagingPlayState) {
+ transitionToRunning(context);
+ }
+ if (changed) {
+ // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
+ // requested from UI thread). It is achieved by modifying mStartTime, such that
+ // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
+ // case of reversing)
+ nsecs_t currentFrameTime = context.frameTimeMs();
+ if (mPlayState == PlayState::Reversing) {
+ // Reverse is not supported for animations with a start delay, so here we
+ // assume no start delay.
+ mStartTime = currentFrameTime - (mDuration - mPlayTime);
+ } else {
+ // Animation should play forward
+ if (mPlayTime == 0) {
+ // If the request is to start from the beginning, include start delay.
+ mStartTime = currentFrameTime + mStartDelay;
+ } else {
+ // If the request is to seek to a non-zero play time, then we skip start
+ // delay.
+ mStartTime = currentFrameTime - mPlayTime;
+ }
+ }
+ }
}
}
+ onPushStaging();
}
void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
@@ -117,10 +226,6 @@ void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
// Set to 0 so that the animate() basically instantly finishes
mStartTime = 0;
}
- // No interpolator was set, use the default
- if (!mInterpolator) {
- mInterpolator.reset(Interpolator::createDefaultInterpolator());
- }
if (mDuration < 0 || mDuration > 50000) {
ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
}
@@ -136,37 +241,37 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
// This should be set before setValue() so animators can query this time when setValue
// is called.
- nsecs_t currentFrameTime = context.frameTimeMs();
- onPlayTimeChanged(currentFrameTime - mStartTime);
+ nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
+ bool finished = updatePlayTime(currentPlayTime);
+ if (finished && mPlayState != PlayState::Finished) {
+ mPlayState = PlayState::Finished;
+ callOnFinishedListener(context);
+ }
+ return finished;
+}
+bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
+ mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
+ onPlayTimeChanged(mPlayTime);
// If BaseRenderNodeAnimator is handling the delay (not typical), then
// because the staging properties reflect the final value, we always need
// to call setValue even if the animation isn't yet running or is still
// being delayed as we need to override the staging value
- if (mStartTime > context.frameTimeMs()) {
+ if (playTime < 0) {
setValue(mTarget, mFromValue);
return false;
}
float fraction = 1.0f;
-
- if (mPlayState == PlayState::Running && mDuration > 0) {
- fraction = (float)(currentFrameTime - mStartTime) / mDuration;
- }
- if (fraction >= 1.0f) {
- fraction = 1.0f;
- mPlayState = PlayState::Finished;
+ if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
+ fraction = mPlayTime / (float) mDuration;
}
+ fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
fraction = mInterpolator->interpolate(fraction);
setValue(mTarget, mFromValue + (mDeltaValue * fraction));
- if (mPlayState == PlayState::Finished) {
- callOnFinishedListener(context);
- return true;
- }
-
- return false;
+ return playTime >= mDuration;
}
void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
@@ -215,18 +320,36 @@ RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float fi
void RenderPropertyAnimator::onAttached() {
if (!mHasStartValue
- && mTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
- setStartValue((mTarget->stagingProperties().*mPropertyAccess->getter)());
+ && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+ setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
}
}
void RenderPropertyAnimator::onStagingPlayStateChanged() {
if (mStagingPlayState == PlayState::Running) {
- (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
+ if (mStagingTarget) {
+ (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
+ } else {
+ // In the case of start delay where stagingTarget has been sync'ed over and null'ed
+ // we delay the properties update to push staging.
+ mShouldUpdateStagingProperties = true;
+ }
} else if (mStagingPlayState == PlayState::Finished) {
// We're being canceled, so make sure that whatever values the UI thread
// is observing for us is pushed over
+ mShouldSyncPropertyFields = true;
+ }
+}
+
+void RenderPropertyAnimator::onPushStaging() {
+ if (mShouldUpdateStagingProperties) {
+ (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
+ mShouldUpdateStagingProperties = false;
+ }
+
+ if (mShouldSyncPropertyFields) {
mTarget->setPropertyFieldsDirty(dirtyMask());
+ mShouldSyncPropertyFields = false;
}
}
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 2c9c9c3fe0f9..fdae0f32d4e6 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -24,6 +24,8 @@
#include "utils/Macros.h"
+#include <vector>
+
namespace android {
namespace uirenderer {
@@ -59,14 +61,14 @@ public:
mMayRunAsync = mayRunAsync;
}
bool mayRunAsync() { return mMayRunAsync; }
- ANDROID_API void start() {
- if (mStagingPlayState == PlayState::NotStarted) {
- mStagingPlayState = PlayState::Running;
- } else {
- mStagingPlayState = PlayState::Restarted;
- }
- onStagingPlayStateChanged(); }
- ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); }
+ ANDROID_API void start();
+ ANDROID_API void reset();
+ ANDROID_API void reverse();
+ // Terminates the animation at its current progress.
+ ANDROID_API void cancel();
+
+ // Terminates the animation and skip to the end of the animation.
+ ANDROID_API void end();
void attach(RenderNode* target);
virtual void onAttached() {}
@@ -74,36 +76,42 @@ public:
void pushStaging(AnimationContext& context);
bool animate(AnimationContext& context);
- bool isRunning() { return mPlayState == PlayState::Running; }
+ bool isRunning() { return mPlayState == PlayState::Running
+ || mPlayState == PlayState::Reversing; }
bool isFinished() { return mPlayState == PlayState::Finished; }
float finalValue() { return mFinalValue; }
ANDROID_API virtual uint32_t dirtyMask() = 0;
void forceEndNow(AnimationContext& context);
+ RenderNode* target() { return mTarget; }
+ RenderNode* stagingTarget() { return mStagingTarget; }
protected:
// PlayState is used by mStagingPlayState and mPlayState to track the state initiated from UI
// thread and Render Thread animation state, respectively.
// From the UI thread, mStagingPlayState transition looks like
- // NotStarted -> Running -> Finished
- // ^ |
- // | |
- // Restarted <------
+ // NotStarted -> Running/Reversing -> Finished
+ // ^ |
+ // | |
+ // ----------------------
// Note: For mStagingState, the Finished state (optional) is only set when the animation is
// terminated by user.
//
// On Render Thread, mPlayState transition:
- // NotStart -> Running -> Finished
- // ^ |
- // | |
- // -------------
+ // NotStart -> Running/Reversing-> Finished
+ // ^ |
+ // | |
+ // ------------------
+ // Note that if the animation is in Running/Reversing state, calling start or reverse again
+ // would do nothing if the animation has the same play direction as the request; otherwise,
+ // the animation would start from where it is and change direction (i.e. Reversing <-> Running)
enum class PlayState {
NotStarted,
Running,
+ Reversing,
Finished,
- Restarted,
};
BaseRenderNodeAnimator(float finalValue);
@@ -111,14 +119,15 @@ protected:
virtual float getValue(RenderNode* target) const = 0;
virtual void setValue(RenderNode* target, float value) = 0;
- RenderNode* target() { return mTarget; }
void callOnFinishedListener(AnimationContext& context);
virtual void onStagingPlayStateChanged() {}
virtual void onPlayTimeChanged(nsecs_t playTime) {}
+ virtual void onPushStaging() {}
RenderNode* mTarget;
+ RenderNode* mStagingTarget;
float mFinalValue;
float mDeltaValue;
@@ -132,13 +141,28 @@ protected:
nsecs_t mDuration;
nsecs_t mStartDelay;
bool mMayRunAsync;
+ // Play Time tracks the progress of animation, it should always be [0, mDuration], 0 being
+ // the beginning of the animation, will reach mDuration at the end of an animation.
+ nsecs_t mPlayTime;
sp<AnimationListener> mListener;
private:
+ enum class Request {
+ Start,
+ Reverse,
+ Reset,
+ Cancel,
+ End
+ };
inline void checkMutable();
virtual void transitionToRunning(AnimationContext& context);
void doSetStartValue(float value);
+ bool updatePlayTime(nsecs_t playTime);
+ void resolveStagingRequest(Request request);
+
+ std::vector<Request> mStagingRequests;
+
};
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
@@ -167,6 +191,7 @@ protected:
virtual void setValue(RenderNode* target, float value) override;
virtual void onAttached() override;
virtual void onStagingPlayStateChanged() override;
+ virtual void onPushStaging() override;
private:
typedef bool (RenderProperties::*SetFloatProperty)(float value);
@@ -176,6 +201,8 @@ private:
const PropertyAccessors* mPropertyAccess;
static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
+ bool mShouldSyncPropertyFields = false;
+ bool mShouldUpdateStagingProperties = false;
};
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index cd30b1859384..f170e9cda8af 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -27,9 +27,8 @@ namespace uirenderer {
using namespace std;
-static void unref(BaseRenderNodeAnimator* animator) {
+static void detach(sp<BaseRenderNodeAnimator>& animator) {
animator->detach();
- animator->decStrong(nullptr);
}
AnimatorManager::AnimatorManager(RenderNode& parent)
@@ -38,14 +37,28 @@ AnimatorManager::AnimatorManager(RenderNode& parent)
}
AnimatorManager::~AnimatorManager() {
- for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
- for_each(mAnimators.begin(), mAnimators.end(), unref);
+ for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
+ for_each(mAnimators.begin(), mAnimators.end(), detach);
}
void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
- animator->incStrong(nullptr);
+ RenderNode* stagingTarget = animator->stagingTarget();
+ if (stagingTarget == &mParent) {
+ return;
+ }
+ mNewAnimators.emplace_back(animator.get());
+ // If the animator is already attached to other RenderNode, remove it from that RenderNode's
+ // new animator list. This ensures one animator only ends up in one newAnimatorList during one
+ // frame, even when it's added multiple times to multiple targets.
+ if (stagingTarget) {
+ stagingTarget->removeAnimator(animator);
+ }
animator->attach(&mParent);
- mNewAnimators.push_back(animator.get());
+}
+
+void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+ mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
+ mNewAnimators.end());
}
void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
@@ -56,38 +69,40 @@ void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
&mParent, mParent.getName());
}
-template<typename T>
-static void move_all(T& source, T& dest) {
- dest.reserve(source.size() + dest.size());
- for (typename T::iterator it = source.begin(); it != source.end(); it++) {
- dest.push_back(*it);
- }
- source.clear();
-}
-
void AnimatorManager::pushStaging() {
if (mNewAnimators.size()) {
LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
"Trying to start new animators on %p (%s) without an animation handle!",
&mParent, mParent.getName());
- // Since this is a straight move, we don't need to inc/dec the ref count
- move_all(mNewAnimators, mAnimators);
+
+ // Only add new animators that are not already in the mAnimators list
+ for (auto& anim : mNewAnimators) {
+ if (anim->target() != &mParent) {
+ mAnimators.push_back(std::move(anim));
+ }
+ }
+ mNewAnimators.clear();
}
- for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
- (*it)->pushStaging(mAnimationHandle->context());
+ for (auto& animator : mAnimators) {
+ animator->pushStaging(mAnimationHandle->context());
}
}
+void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
+ LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
+ mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
+}
+
class AnimateFunctor {
public:
- AnimateFunctor(TreeInfo& info, AnimationContext& context)
- : dirtyMask(0), mInfo(info), mContext(context) {}
+ AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
+ : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
- bool operator() (BaseRenderNodeAnimator* animator) {
- dirtyMask |= animator->dirtyMask();
+ bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+ *mDirtyMask |= animator->dirtyMask();
bool remove = animator->animate(mContext);
if (remove) {
- animator->decStrong(nullptr);
+ animator->detach();
} else {
if (animator->isRunning()) {
mInfo.out.hasAnimations = true;
@@ -99,11 +114,10 @@ public:
return remove;
}
- uint32_t dirtyMask;
-
private:
TreeInfo& mInfo;
AnimationContext& mContext;
+ uint32_t* mDirtyMask;
};
uint32_t AnimatorManager::animate(TreeInfo& info) {
@@ -128,21 +142,20 @@ void AnimatorManager::animateNoDamage(TreeInfo& info) {
}
uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
- AnimateFunctor functor(info, mAnimationHandle->context());
- std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
- newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
+ uint32_t dirtyMask;
+ AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
+ auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.erase(newEnd, mAnimators.end());
mAnimationHandle->notifyAnimationsRan();
mParent.mProperties.updateMatrix();
- return functor.dirtyMask;
+ return dirtyMask;
}
-static void endStagingAnimator(BaseRenderNodeAnimator* animator) {
- animator->end();
+static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
+ animator->cancel();
if (animator->listener()) {
- animator->listener()->onAnimationFinished(animator);
+ animator->listener()->onAnimationFinished(animator.get());
}
- animator->decStrong(nullptr);
}
void AnimatorManager::endAllStagingAnimators() {
@@ -157,9 +170,8 @@ class EndActiveAnimatorsFunctor {
public:
EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
- void operator() (BaseRenderNodeAnimator* animator) {
+ void operator() (sp<BaseRenderNodeAnimator>& animator) {
animator->forceEndNow(mContext);
- animator->decStrong(nullptr);
}
private:
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index fb75eb8599b4..61f6179d217c 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -39,11 +39,13 @@ public:
~AnimatorManager();
void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
+ void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
void setAnimationHandle(AnimationHandle* handle);
bool hasAnimationHandle() { return mAnimationHandle; }
void pushStaging();
+ void onAnimatorTargetChanged(BaseRenderNodeAnimator* animator);
// Returns the combined dirty mask of all animators run
uint32_t animate(TreeInfo& info);
@@ -66,9 +68,8 @@ private:
AnimationHandle* mAnimationHandle;
// To improve the efficiency of resizing & removing from the vector
- // use manual ref counting instead of sp<>.
- std::vector<BaseRenderNodeAnimator*> mNewAnimators;
- std::vector<BaseRenderNodeAnimator*> mAnimators;
+ std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators;
+ std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index f83e1faf9c8a..1aab3c79dcfd 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -334,15 +334,15 @@ static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& stat
}
static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
- PathTexture& texture, const RecordedOp& op) {
+ float xOffset, float yOffset, PathTexture& texture, const SkPaint& paint) {
Rect dest(texture.width(), texture.height());
- dest.translate(texture.left - texture.offset,
- texture.top - texture.offset);
+ dest.translate(xOffset + texture.left - texture.offset,
+ yOffset + texture.top - texture.offset);
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
- .setFillPathTexturePaint(texture, *(op.paint), state.alpha)
+ .setFillPathTexturePaint(texture, paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRect(dest)
.build();
@@ -368,7 +368,8 @@ void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, cons
op.startAngle, op.sweepAngle, op.useCenter, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, *texture, op);
+ renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+ *texture, *(op.paint));
}
} else {
SkRect rect = getBoundsOfFill(op);
@@ -519,7 +520,8 @@ void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, co
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, *texture, op);
+ renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.right,
+ *texture, *(op.paint));
}
} else {
SkPath path;
@@ -562,7 +564,9 @@ void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, co
PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, *texture, op);
+ // Unlike other callers to renderPathTexture, no offsets are used because PathOp doesn't
+ // have any translate built in, other than what's in the SkPath itself
+ renderPathTexture(renderer, state, 0, 0, *texture, *(op.paint));
}
}
@@ -588,7 +592,8 @@ void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, co
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, *texture, op);
+ renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+ *texture, *(op.paint));
}
} else {
SkPath path;
@@ -622,7 +627,8 @@ void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRect
op.rx, op.ry, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, *texture, op);
+ renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+ *texture, *(op.paint));
}
} else {
const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect(
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 35c8f6b52d38..c14738469058 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -296,12 +296,9 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
}
}
- // dirty offscreenbuffer
- if (dirtyBounds && mRenderTarget.offscreenBuffer) {
- // register layer damage to draw-back region
- android::Rect dirty(dirtyBounds->left, dirtyBounds->top,
- dirtyBounds->right, dirtyBounds->bottom);
- mRenderTarget.offscreenBuffer->region.orSelf(dirty);
+ if (dirtyBounds) {
+ // dirty offscreenbuffer if present
+ dirtyRenderTarget(*dirtyBounds);
}
}
@@ -329,29 +326,9 @@ void BakedOpRenderer::renderFunctor(const FunctorOp& op, const BakedOpState& sta
mRenderState.invokeFunctor(op.functor, DrawGlInfo::kModeDraw, &info);
}
-#define VALIDATE_RECT_ARG(rect, arg) \
- ((isnanf(rect.arg) || rect.arg < -10000 || rect.arg > 10000) ? (\
- ALOGW("suspicious " #rect "." #arg "! %f", rect.arg),\
- false) : true)
-
-#define VALIDATE_RECT(rect) \
- VALIDATE_RECT_ARG(rect, bottom) & \
- VALIDATE_RECT_ARG(rect, left) & \
- VALIDATE_RECT_ARG(rect, top) & \
- VALIDATE_RECT_ARG(rect, right)
-
void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) {
if (mRenderTarget.offscreenBuffer) {
- bool valid = VALIDATE_RECT(uiDirty);
- android::Rect dirty;
- if (valid) {
- dirty = android::Rect(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
- } else {
- dirty = android::Rect(0, 0,
- mRenderTarget.offscreenBuffer->viewportWidth,
- mRenderTarget.offscreenBuffer->viewportHeight);
- }
- mRenderTarget.offscreenBuffer->region.orSelf(dirty);
+ mRenderTarget.offscreenBuffer->dirty(uiDirty);
}
}
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index a542c26b41b8..682bd045098d 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -21,6 +21,15 @@
namespace android {
namespace uirenderer {
+static int computeClipSideFlags(const Rect& clip, const Rect& bounds) {
+ int clipSideFlags = 0;
+ if (clip.left > bounds.left) clipSideFlags |= OpClipSideFlags::Left;
+ if (clip.top > bounds.top) clipSideFlags |= OpClipSideFlags::Top;
+ if (clip.right < bounds.right) clipSideFlags |= OpClipSideFlags::Right;
+ if (clip.bottom < bounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+ return clipSideFlags;
+}
+
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
const RecordedOp& recordedOp, bool expandForStroke) {
// resolvedMatrix = parentMatrix * localMatrix
@@ -55,10 +64,7 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
clippedBounds.setEmpty();
} else {
// Not rejected! compute true clippedBounds and clipSideFlags
- if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
- if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
- if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
- if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+ clipSideFlags = computeClipSideFlags(clipRect, clippedBounds);
clippedBounds.doIntersect(clipRect);
}
}
@@ -69,11 +75,13 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
, clippedBounds(clipState->rect)
, clipSideFlags(OpClipSideFlags::Full) {}
-ResolvedRenderState::ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect)
+ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& dstRect)
: transform(Matrix4::identity())
- , clipState(viewportRect)
+ , clipState(clipRect)
, clippedBounds(dstRect)
- , clipSideFlags(OpClipSideFlags::None) {}
+ , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect)) {
+ clippedBounds.doIntersect(clipRect->rect);
+}
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 3db28c982469..4365ef870dda 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -100,7 +100,7 @@ public:
static BakedOpState* tryConstruct(LinearAllocator& allocator,
Snapshot& snapshot, const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- BakedOpState* bakedState = new (allocator) BakedOpState(
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
allocator, snapshot, recordedOp, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
@@ -124,7 +124,7 @@ public:
? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
: true;
- BakedOpState* bakedState = new (allocator) BakedOpState(
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
allocator, snapshot, recordedOp, expandForStroke);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
@@ -140,16 +140,12 @@ public:
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
// clip isn't empty, so construct the op
- return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
+ return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
}
static BakedOpState* directConstruct(LinearAllocator& allocator,
const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
- return new (allocator) BakedOpState(clip, dstRect, recordedOp);
- }
-
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
}
// computed state:
@@ -162,6 +158,8 @@ public:
const RecordedOp* op;
private:
+ friend class LinearAllocator;
+
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
const RecordedOp& recordedOp, bool expandForStroke)
: computedState(allocator, snapshot, recordedOp, expandForStroke)
@@ -177,8 +175,8 @@ private:
, projectionPathMask(snapshot.projectionPathMask)
, op(shadowOpPtr) {}
- BakedOpState(const ClipRect* viewportRect, const Rect& dstRect, const RecordedOp& recordedOp)
- : computedState(viewportRect, dstRect)
+ BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp)
+ : computedState(clipRect, dstRect)
, alpha(1.0f)
, roundRectClipState(nullptr)
, projectionPathMask(nullptr)
diff --git a/libs/hwui/BufferPool.h b/libs/hwui/BufferPool.h
deleted file mode 100644
index 005b399f603b..000000000000
--- a/libs/hwui/BufferPool.h
+++ /dev/null
@@ -1,181 +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.
- */
-
-#pragma once
-
-#include "utils/RefBase.h"
-#include "utils/Log.h"
-#include "utils/Macros.h"
-
-#include <atomic>
-#include <stdint.h>
-#include <memory>
-#include <mutex>
-
-namespace android {
-namespace uirenderer {
-
-/*
- * Simple thread-safe pool of int64_t arrays of a provided size.
- *
- * Permits allocating a client-provided max number of buffers.
- * If all buffers are in use, refuses to service any more
- * acquire requests until buffers are re-released to the pool.
- */
-class BufferPool : public VirtualLightRefBase {
-public:
- class Buffer {
- PREVENT_COPY_AND_ASSIGN(Buffer);
- public:
- int64_t* getBuffer() { return mBuffer.get(); }
- size_t getSize() { return mSize; }
-
- void release() {
- LOG_ALWAYS_FATAL_IF(mPool.get() == nullptr, "attempt to release unacquired buffer");
- mPool->release(this);
- }
-
- Buffer* incRef() {
- mRefs++;
- return this;
- }
-
- int decRef() {
- int refs = mRefs.fetch_sub(1);
- LOG_ALWAYS_FATAL_IF(refs == 0, "buffer reference decremented below 0");
- return refs - 1;
- }
-
- bool isUniqueRef() {
- return mRefs.load() == 1;
- }
-
- private:
- friend class BufferPool;
-
- Buffer(BufferPool* pool, size_t size) : mRefs(1) {
- mSize = size;
- mBuffer.reset(new int64_t[size]);
- mPool = pool;
- }
-
- void setPool(BufferPool* pool) {
- mPool = pool;
- }
-
- std::unique_ptr<Buffer> mNext;
- std::unique_ptr<int64_t[]> mBuffer;
- sp<BufferPool> mPool;
- size_t mSize;
-
- std::atomic_int mRefs;
- };
-
- BufferPool(size_t bufferSize, size_t count)
- : mBufferSize(bufferSize), mCount(count) {}
-
- /**
- * Acquires a buffer from the buffer pool if available.
- *
- * Only `mCount` buffers are allowed to be in use at a single
- * instance.
- *
- * If no buffer is available, i.e. `mCount` buffers are in use,
- * returns nullptr.
- *
- * The pointer returned from this method *MUST NOT* be freed, instead
- * BufferPool::release() must be called upon it when the client
- * is done with it. Failing to release buffers will eventually make the
- * BufferPool refuse to service any more BufferPool::acquire() requests.
- */
- BufferPool::Buffer* acquire() {
- std::lock_guard<std::mutex> lock(mLock);
-
- if (mHead.get() != nullptr) {
- BufferPool::Buffer* res = mHead.release();
- mHead = std::move(res->mNext);
- res->mNext.reset(nullptr);
- res->setPool(this);
- res->incRef();
- return res;
- }
-
- if (mAllocatedCount < mCount) {
- ++mAllocatedCount;
- return new BufferPool::Buffer(this, mBufferSize);
- }
-
- return nullptr;
- }
-
- /**
- * Releases a buffer previously acquired by BufferPool::acquire().
- *
- * The released buffer is not valid after calling this method and
- * attempting to use will result in undefined behavior.
- */
- void release(BufferPool::Buffer* buffer) {
- std::lock_guard<std::mutex> lock(mLock);
-
- if (buffer->decRef() != 0) {
- return;
- }
-
- buffer->setPool(nullptr);
-
- BufferPool::Buffer* list = mHead.get();
- if (list == nullptr) {
- mHead.reset(buffer);
- mHead->mNext.reset(nullptr);
- return;
- }
-
- while (list->mNext.get() != nullptr) {
- list = list->mNext.get();
- }
-
- list->mNext.reset(buffer);
- }
-
- /*
- * Used for testing.
- */
- size_t getAvailableBufferCount() {
- size_t remainingToAllocateCount = mCount - mAllocatedCount;
-
- BufferPool::Buffer* list = mHead.get();
- if (list == nullptr) return remainingToAllocateCount;
-
- int count = 1;
- while (list->mNext.get() != nullptr) {
- count++;
- list = list->mNext.get();
- }
-
- return count + remainingToAllocateCount;
- }
-
-private:
- mutable std::mutex mLock;
-
- size_t mBufferSize;
- size_t mCount;
- size_t mAllocatedCount = 0;
- std::unique_ptr<BufferPool::Buffer> mHead;
-};
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 9c08b4dd22ae..501cbe50ee05 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -361,17 +361,21 @@ const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
"expect RectangleList to be trivially destructible");
if (mLastSerialization == nullptr) {
+ ClipBase* serialization = nullptr;
switch (mMode) {
case ClipMode::Rectangle:
- mLastSerialization = allocator.create<ClipRect>(mClipRect);
+ serialization = allocator.create<ClipRect>(mClipRect);
break;
case ClipMode::RectangleList:
- mLastSerialization = allocator.create<ClipRectList>(mRectangleList);
+ serialization = allocator.create<ClipRectList>(mRectangleList);
+ serialization->rect = mRectangleList.calculateBounds();
break;
case ClipMode::Region:
- mLastSerialization = allocator.create<ClipRegion>(mClipRegion);
+ serialization = allocator.create<ClipRegion>(mClipRegion);
+ serialization->rect.set(mClipRegion.getBounds());
break;
}
+ mLastSerialization = serialization;
}
return mLastSerialization;
}
@@ -400,11 +404,17 @@ static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* s
return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
}
+static const ClipRect sEmptyClipRect(Rect(0, 0));
+
const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+
// if no recordedClip passed, just serialize current state
if (!recordedClip) return serializeClip(allocator);
+ // if either is empty, clip is empty
+ if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
+
if (!mLastResolutionResult
|| recordedClip != mLastResolutionClip
|| recordedClipTransform != mLastResolutionTransform) {
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index c2e14a29f29e..6d5833b3be86 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -45,7 +45,7 @@ struct DirtyStack {
};
DamageAccumulator::DamageAccumulator() {
- mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ mHead = mAllocator.create_trivial<DirtyStack>();
memset(mHead, 0, sizeof(DirtyStack));
// Create a root that we will not pop off
mHead->prev = mHead;
@@ -78,7 +78,7 @@ void DamageAccumulator::computeCurrentTransform(Matrix4* outMatrix) const {
void DamageAccumulator::pushCommon() {
if (!mHead->next) {
- DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
nextFrame->next = nullptr;
nextFrame->prev = mHead;
mHead->next = nextFrame;
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 2d5979f2f1a7..98ccf11b1c2a 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -49,11 +49,6 @@ typedef const void* mergeid_t;
class DeferredDisplayState {
public:
- static void* operator new(size_t size) = delete;
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
// global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
Rect mBounds;
@@ -124,7 +119,7 @@ private:
DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
DeferredDisplayState* createState() {
- return new (mAllocator) DeferredDisplayState();
+ return mAllocator.create_trivial<DeferredDisplayState>();
}
void tryRecycleState(DeferredDisplayState* state) {
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 00560d7df454..a14bdc4693e6 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -415,12 +415,7 @@ void DisplayListCanvas::drawPoints(const float* points, int count, const SkPaint
void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- const SkBitmap& bitmap = tree->getBitmapUpdateIfDirty();
- SkPaint* paint = tree->getPaint();
- const SkRect bounds = tree->getBounds();
- addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap),
- 0, 0, bitmap.width(), bitmap.height(),
- bounds.left(), bounds.top(), bounds.right(), bounds.bottom(), refPaint(paint)));
+ addDrawOp(new (alloc()) DrawVectorDrawableOp(tree));
}
void DisplayListCanvas::drawTextOnPath(const uint16_t* glyphs, int count,
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index e5711e35a88b..a703e227fc8d 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -251,7 +251,7 @@ private:
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+ T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -320,8 +320,7 @@ private:
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
- alloc().autoDestroy(localBitmap);
+ SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
mDisplayList->bitmapResources.push_back(localBitmap);
return localBitmap;
}
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 20501ba3c1d9..516e6199bd27 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -28,6 +28,7 @@
#include "UvMapper.h"
#include "utils/LinearAllocator.h"
#include "utils/PaintUtils.h"
+#include "VectorDrawable.h"
#include <algorithm>
@@ -64,7 +65,9 @@ public:
static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ // FIXME: Quick hack to keep old pipeline working, delete this when
+ // we no longer need to support HWUI_NEWOPS := false
+ return allocator.alloc<char>(size);
}
enum OpLogFlag {
@@ -1105,6 +1108,30 @@ private:
float* mRadius;
};
+class DrawVectorDrawableOp : public DrawOp {
+public:
+ DrawVectorDrawableOp(VectorDrawableRoot* tree)
+ : DrawOp(nullptr), mTree(tree) {}
+
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty();
+ SkPaint* paint = mTree->getPaint();
+ const SkRect bounds = mTree->getBounds();
+ renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()),
+ bounds, paint);
+ }
+
+ virtual void output(int level, uint32_t logFlags) const override {
+ OP_LOG("Draw Vector Drawable %p", mTree);
+ }
+
+ virtual const char* name() override { return "DrawVectorDrawable"; }
+
+private:
+ VectorDrawableRoot* mTree;
+
+};
+
class DrawOvalOp : public DrawStrokableOp {
public:
DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 185accec1ef6..04de98afe85c 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -209,7 +209,7 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
if (node.getLayer()) {
// HW layer
- LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
+ LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(node);
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
if (bakedOpState) {
// Node's layer already deferred, schedule it to render into parent layer
@@ -220,13 +220,13 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
// (temp layers are clipped to viewport, since they don't persist offscreen content)
SkPaint saveLayerPaint;
saveLayerPaint.setAlpha(properties.getAlpha());
- deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
+ deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
saveLayerBounds,
Matrix4::identity(),
nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
- deferEndLayerOp(*new (mAllocator) EndLayerOp());
+ deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
} else {
deferNodeOps(node);
}
@@ -549,7 +549,7 @@ void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) {
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
const SkBitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
SkPaint* paint = op.vectorDrawable->getPaint();
- const BitmapRectOp* resolvedOp = new (mAllocator) BitmapRectOp(op.unmappedBounds,
+ const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
op.localMatrix,
op.localClip,
paint,
@@ -565,7 +565,7 @@ void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) {
float y = *(op.y);
float radius = *(op.radius);
Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
- const OvalOp* resolvedOp = new (mAllocator) OvalOp(
+ const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
unmappedBounds,
op.localMatrix,
op.localClip,
@@ -626,7 +626,7 @@ void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
- const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
+ const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
op.localMatrix,
op.localClip,
@@ -754,7 +754,7 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
// record the draw operation into the previous layer's list of draw commands
// uses state from the associated beginLayerOp, since it has all the state needed for drawing
- LayerOp* drawLayerOp = new (mAllocator) LayerOp(
+ LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
beginLayerOp.unmappedBounds,
beginLayerOp.localMatrix,
beginLayerOp.localClip,
@@ -782,39 +782,46 @@ void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
boundsTransform.mapRect(dstRect);
dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip());
- // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
- OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
-
- /**
- * First, defer an operation to copy out the content from the rendertarget into a layer.
- */
- auto copyToOp = new (mAllocator) CopyToLayerOp(op, layerHandle);
- BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
- &(currentLayer().viewportClip), dstRect, *copyToOp);
- currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
-
- /**
- * Defer a clear rect, so that clears from multiple unclipped layers can be drawn
- * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible
- */
- currentLayer().deferLayerClear(dstRect);
-
- /**
- * And stash an operation to copy that layer back under the rendertarget until
- * a balanced EndUnclippedLayerOp is seen
- */
- auto copyFromOp = new (mAllocator) CopyFromLayerOp(op, layerHandle);
- bakedState = BakedOpState::directConstruct(mAllocator,
- &(currentLayer().viewportClip), dstRect, *copyFromOp);
- currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
+ if (dstRect.isEmpty()) {
+ // Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored
+ currentLayer().activeUnclippedSaveLayers.push_back(nullptr);
+ } else {
+ // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
+ OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
+
+ /**
+ * First, defer an operation to copy out the content from the rendertarget into a layer.
+ */
+ auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
+ BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
+ &(currentLayer().repaintClip), dstRect, *copyToOp);
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
+
+ /**
+ * Defer a clear rect, so that clears from multiple unclipped layers can be drawn
+ * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible
+ */
+ currentLayer().deferLayerClear(dstRect);
+
+ /**
+ * And stash an operation to copy that layer back under the rendertarget until
+ * a balanced EndUnclippedLayerOp is seen
+ */
+ auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
+ bakedState = BakedOpState::directConstruct(mAllocator,
+ &(currentLayer().repaintClip), dstRect, *copyFromOp);
+ currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
+ }
}
void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) {
LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!");
BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back();
- currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer);
currentLayer().activeUnclippedSaveLayers.pop_back();
+ if (copyFromLayerOp) {
+ currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer);
+ }
}
} // namespace uirenderer
diff --git a/libs/hwui/FrameStatsObserver.h b/libs/hwui/FrameMetricsObserver.h
index 7abc9f143a0b..4f81c8681fc8 100644
--- a/libs/hwui/FrameStatsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -18,14 +18,12 @@
#include <utils/RefBase.h>
-#include "BufferPool.h"
-
namespace android {
namespace uirenderer {
-class FrameStatsObserver : public VirtualLightRefBase {
+class FrameMetricsObserver : public VirtualLightRefBase {
public:
- virtual void notify(BufferPool::Buffer* buffer);
+ virtual void notify(const int64_t* buffer);
};
}; // namespace uirenderer
diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h
new file mode 100644
index 000000000000..c1cd0a9224b6
--- /dev/null
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/RefBase.h>
+#include <utils/Log.h>
+
+#include "FrameInfo.h"
+#include "FrameMetricsObserver.h"
+
+#include <string.h>
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+class FrameMetricsReporter {
+public:
+ FrameMetricsReporter() {}
+
+ void addObserver(FrameMetricsObserver* observer) {
+ mObservers.push_back(observer);
+ }
+
+ bool removeObserver(FrameMetricsObserver* observer) {
+ for (size_t i = 0; i < mObservers.size(); i++) {
+ if (mObservers[i].get() == observer) {
+ mObservers.erase(mObservers.begin() + i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool hasObservers() {
+ return mObservers.size() > 0;
+ }
+
+ void reportFrameMetrics(const int64_t* stats) {
+ for (size_t i = 0; i < mObservers.size(); i++) {
+ mObservers[i]->notify(stats);
+ }
+ }
+
+private:
+ std::vector< sp<FrameMetricsObserver> > mObservers;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
diff --git a/libs/hwui/FrameStatsReporter.h b/libs/hwui/FrameStatsReporter.h
deleted file mode 100644
index b8a9432d6507..000000000000
--- a/libs/hwui/FrameStatsReporter.h
+++ /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.
- */
-
-#pragma once
-
-#include <utils/RefBase.h>
-#include <utils/Log.h>
-
-#include "BufferPool.h"
-#include "FrameInfo.h"
-#include "FrameStatsObserver.h"
-
-#include <string.h>
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-class FrameStatsReporter {
-public:
- FrameStatsReporter() {
- mBufferPool = new BufferPool(kBufferSize, kBufferCount);
- LOG_ALWAYS_FATAL_IF(mBufferPool.get() == nullptr, "OOM: unable to allocate buffer pool");
- }
-
- void addObserver(FrameStatsObserver* observer) {
- mObservers.push_back(observer);
- }
-
- bool removeObserver(FrameStatsObserver* observer) {
- for (size_t i = 0; i < mObservers.size(); i++) {
- if (mObservers[i].get() == observer) {
- mObservers.erase(mObservers.begin() + i);
- return true;
- }
- }
- return false;
- }
-
- bool hasObservers() {
- return mObservers.size() > 0;
- }
-
- void reportFrameStats(const int64_t* stats) {
- BufferPool::Buffer* statsBuffer = mBufferPool->acquire();
-
- if (statsBuffer != nullptr) {
- // copy in frame stats
- memcpy(statsBuffer->getBuffer(), stats, kBufferSize * sizeof(*stats));
-
- // notify on requested threads
- for (size_t i = 0; i < mObservers.size(); i++) {
- mObservers[i]->notify(statsBuffer);
- }
-
- // drop our reference
- statsBuffer->release();
- } else {
- mDroppedReports++;
- }
- }
-
- int getDroppedReports() { return mDroppedReports; }
-
-private:
- static const size_t kBufferCount = 3;
- static const size_t kBufferSize = static_cast<size_t>(FrameInfoIndex::NumIndexes);
-
- std::vector< sp<FrameStatsObserver> > mObservers;
-
- sp<BufferPool> mBufferPool;
-
- int mDroppedReports = 0;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 11293d61211b..c8f5e9435594 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -165,6 +165,10 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
generateTexture(colors, positions, info.width, 2, texture);
mSize += size;
+ LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
+ "size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
+ " width = %" PRIu32 " bytesPerPixel() = %zu",
+ size, texture->objectSize(), info.width, bytesPerPixel());
mCache.put(gradient, texture);
return texture;
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index 7170d4fbeea7..bc39621f2cb2 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -64,10 +64,6 @@ protected:
class OpBatch : public BatchBase {
public:
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
OpBatch(batchid_t batchId, BakedOpState* op)
: BatchBase(batchId, op, false) {
}
@@ -80,10 +76,6 @@ public:
class MergingOpBatch : public BatchBase {
public:
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
MergingOpBatch(batchid_t batchId, BakedOpState* op)
: BatchBase(batchId, op, true)
, mClipSideFlags(op->computedState.clipSideFlags) {
@@ -207,10 +199,10 @@ LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
: width(width)
, height(height)
, repaintRect(repaintRect)
+ , repaintClip(repaintRect)
, offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr)
, beginLayerOp(beginLayerOp)
- , renderNode(renderNode)
- , viewportClip(Rect(width, height)) {}
+ , renderNode(renderNode) {}
// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still iterate to find similar batch to insert after
@@ -247,7 +239,7 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
// put the verts in the frame allocator, since
// 1) SimpleRectsOps needs verts, not rects
// 2) even if mClearRects stored verts, std::vectors will move their contents
- Vertex* const verts = (Vertex*) allocator.alloc(vertCount * sizeof(Vertex));
+ Vertex* const verts = (Vertex*) allocator.create_trivial_array<Vertex>(vertCount);
Vertex* currentVert = verts;
Rect bounds = mClearRects[0];
@@ -264,11 +256,11 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
// Flush all of these clears with a single draw
SkPaint* paint = allocator.create<SkPaint>();
paint->setXfermodeMode(SkXfermode::kClear_Mode);
- SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds,
+ SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
Matrix4::identity(), nullptr, paint,
verts, vertCount);
BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
- &viewportClip, bounds, *op);
+ &repaintClip, bounds, *op);
deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices);
}
}
@@ -292,7 +284,7 @@ void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
targetBatch->batchOp(op);
} else {
// new non-merging batch
- targetBatch = new (allocator) OpBatch(batchId, op);
+ targetBatch = allocator.create<OpBatch>(batchId, op);
mBatchLookup[batchId] = targetBatch;
mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
}
@@ -323,7 +315,7 @@ void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
targetBatch->mergeOp(op);
} else {
// new merging batch
- targetBatch = new (allocator) MergingOpBatch(batchId, op);
+ targetBatch = allocator.create<MergingOpBatch>(batchId, op);
mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h
index 99968e1750c8..4a7ca2de9b1b 100644
--- a/libs/hwui/LayerBuilder.h
+++ b/libs/hwui/LayerBuilder.h
@@ -109,10 +109,10 @@ public:
const uint32_t width;
const uint32_t height;
const Rect repaintRect;
+ const ClipRect repaintClip;
OffscreenBuffer* offscreenBuffer;
const BeginLayerOp* beginLayerOp;
const RenderNode* renderNode;
- const ClipRect viewportClip;
// list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps
std::vector<BakedOpState*> activeUnclippedSaveLayers;
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 73ebd1304750..deab95690d0e 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -438,7 +438,7 @@ void Matrix4::mapPoint(float& x, float& y) const {
}
void Matrix4::mapRect(Rect& r) const {
- if (isIdentity()) return;
+ if (isIdentity() || r.isEmpty()) return;
if (isSimple()) {
MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 1c25f26c0c25..36007cd5dc0e 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWUI_MATRIX_H
-#define ANDROID_HWUI_MATRIX_H
+#pragma once
-#include <SkMatrix.h>
+#include "Rect.h"
#include <cutils/compiler.h>
-
-#include "Rect.h"
+#include <iomanip>
+#include <ostream>
+#include <SkMatrix.h>
namespace android {
namespace uirenderer {
@@ -218,6 +218,22 @@ public:
void dump(const char* label = nullptr) const;
+ friend std::ostream& operator<<(std::ostream& os, const Matrix4& matrix) {
+ if (matrix.isSimple()) {
+ os << "offset " << matrix.getTranslateX() << "x" << matrix.getTranslateY();
+ if (!matrix.isPureTranslate()) {
+ os << ", scale " << matrix[kScaleX] << "x" << matrix[kScaleY];
+ }
+ } else {
+ os << "[" << matrix[0];
+ for (int i = 1; i < 16; i++) {
+ os << ", " << matrix[i];
+ }
+ os << "]";
+ }
+ return os;
+ }
+
static const Matrix4& identity();
private:
@@ -244,4 +260,3 @@ typedef Matrix4 mat4;
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_HWUI_MATRIX_H
diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp
new file mode 100644
index 000000000000..c34cfbe1b259
--- /dev/null
+++ b/libs/hwui/OpDumper.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OpDumper.h"
+
+#include "RecordedOp.h"
+
+namespace android {
+namespace uirenderer {
+
+#define STRINGIFY(n) #n,
+static const char* sOpNameLut[] = BUILD_FULL_OP_LUT(STRINGIFY);
+
+void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) {
+ for (int i = 0; i < level; i++) {
+ output << " ";
+ }
+
+ Rect localBounds(op.unmappedBounds);
+ op.localMatrix.mapRect(localBounds);
+ output << sOpNameLut[op.opId] << " " << localBounds;
+
+ if (op.localClip && !op.localClip->rect.contains(localBounds)) {
+ output << std::fixed << std::setprecision(0)
+ << " clip=" << op.localClip->rect
+ << " mode=" << (int)op.localClip->mode;
+ }
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h
new file mode 100644
index 000000000000..c99b51796b5c
--- /dev/null
+++ b/libs/hwui/OpDumper.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <ostream>
+
+namespace android {
+namespace uirenderer {
+
+struct RecordedOp;
+
+class OpDumper {
+public:
+ static void dump(const RecordedOp& op, std::ostream& output, int level = 0);
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 6df994c623f2..165c7db4c85f 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -36,12 +36,14 @@ public:
CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
- void unmap() override;
uint8_t* getMappedPointer() const override;
void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
+protected:
+ void unmap() override;
+
private:
std::unique_ptr<uint8_t[]> mBuffer;
};
@@ -81,12 +83,14 @@ public:
~GpuPixelBuffer();
uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
- void unmap() override;
uint8_t* getMappedPointer() const override;
void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
+protected:
+ void unmap() override;
+
private:
GLuint mBuffer;
uint8_t* mMappedPointer;
@@ -118,6 +122,7 @@ uint8_t* GpuPixelBuffer::map(AccessMode mode) {
LOG_ALWAYS_FATAL("Failed to map PBO");
}
mAccessMode = mode;
+ mCaches.pixelBufferState().unbind();
}
return mMappedPointer;
@@ -147,6 +152,7 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei
unmap();
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
+ mCaches.pixelBufferState().unbind();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index aac5ec4777ee..bbef36b72e4f 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -91,14 +91,6 @@ public:
virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0;
/**
- * Unmaps this buffer, if needed. After the buffer is unmapped,
- * the pointer previously returned by map() becomes invalid and
- * should not be used. After calling this method, getMappedPointer()
- * will always return NULL.
- */
- virtual void unmap() = 0;
-
- /**
* Returns the current access mode for this buffer. If the buffer
* is not mapped, this method returns kAccessMode_None.
*/
@@ -204,6 +196,14 @@ protected:
mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
}
+ /**
+ * Unmaps this buffer, if needed. After the buffer is unmapped,
+ * the pointer previously returned by map() becomes invalid and
+ * should not be used. After calling this method, getMappedPointer()
+ * will always return NULL.
+ */
+ virtual void unmap() = 0;
+
GLenum mFormat;
uint32_t mWidth;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index eca1afcc54dc..b29f91ff34aa 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -17,6 +17,8 @@
#include "PropertyValuesAnimatorSet.h"
#include "RenderNode.h"
+#include <algorithm>
+
namespace android {
namespace uirenderer {
@@ -53,16 +55,26 @@ void PropertyValuesAnimatorSet::setValue(RenderNode* target, float value) {
}
void PropertyValuesAnimatorSet::onPlayTimeChanged(nsecs_t playTime) {
- for (size_t i = 0; i < mAnimators.size(); i++) {
- mAnimators[i]->setCurrentPlayTime(playTime);
+ if (playTime == 0 && mDuration > 0) {
+ // Reset all the animators
+ for (auto it = mAnimators.rbegin(); it != mAnimators.rend(); it++) {
+ // Note that this set may containing animators modifying the same property, so when we
+ // reset the animators, we need to make sure the animators that end the first will
+ // have the final say on what the property value should be.
+ (*it)->setFraction(0);
+ }
+ } else if (playTime >= mDuration) {
+ // Skip all the animators to end
+ for (auto& anim : mAnimators) {
+ anim->setFraction(1);
+ }
+ } else {
+ for (auto& anim : mAnimators) {
+ anim->setCurrentPlayTime(playTime);
+ }
}
}
-void PropertyValuesAnimatorSet::reset() {
- // TODO: implement reset through adding a play state because we need to support reset() even
- // during an animation run.
-}
-
void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
init();
mOneShotListener = listener;
@@ -70,20 +82,23 @@ void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
}
void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
-// TODO: implement reverse
+ init();
+ mOneShotListener = listener;
+ BaseRenderNodeAnimator::reverse();
}
void PropertyValuesAnimatorSet::init() {
if (mInitialized) {
return;
}
- nsecs_t maxDuration = 0;
- for (size_t i = 0; i < mAnimators.size(); i++) {
- if (maxDuration < mAnimators[i]->getTotalDuration()) {
- maxDuration = mAnimators[i]->getTotalDuration();
- }
- }
- mDuration = maxDuration;
+
+ // Sort the animators by their total duration. Note that all the animators in the set start at
+ // the same time, so the ones with longer total duration (which includes start delay) will
+ // be the ones that end later.
+ std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) {
+ return a->getTotalDuration() < b->getTotalDuration();
+ });
+ mDuration = mAnimators[mAnimators.size() - 1]->getTotalDuration();
mInitialized = true;
}
@@ -106,18 +121,19 @@ PropertyAnimator::PropertyAnimator(PropertyValuesHolder* holder, Interpolator* i
void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) {
if (playTime >= mStartDelay && playTime < mTotalDuration) {
nsecs_t currentIterationPlayTime = (playTime - mStartDelay) % mDuration;
- mLatestFraction = currentIterationPlayTime / (float) mDuration;
+ float fraction = currentIterationPlayTime / (float) mDuration;
+ setFraction(fraction);
} else if (mLatestFraction < 1.0f && playTime >= mTotalDuration) {
- mLatestFraction = 1.0f;
- } else {
- return;
+ // This makes sure we only set the fraction = 1 once. It is needed because there might
+ // be another animator modifying the same property after this animator finishes, we need
+ // to make sure we don't set conflicting values on the same property within one frame.
+ setFraction(1.0f);
}
-
- setFraction(mLatestFraction);
}
void PropertyAnimator::setFraction(float fraction) {
- float interpolatedFraction = mInterpolator->interpolate(mLatestFraction);
+ mLatestFraction = fraction;
+ float interpolatedFraction = mInterpolator->interpolate(fraction);
mPropertyValuesHolder->setFraction(interpolatedFraction);
}
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index 4c7ce528bb20..c7ae7c0e8ce1 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -50,7 +50,6 @@ public:
void start(AnimationListener* listener);
void reverse(AnimationListener* listener);
- void reset();
void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
Interpolator* interpolators, int64_t startDelays,
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index bb26e2ec67a8..c37458d31029 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -119,6 +119,9 @@ class Tree;
#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
{ MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+#define BUILD_FULL_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
+
/**
* Op mapping functions, which skip unsupported ops.
*
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 16929b8ac8ee..9ae2212d0732 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -83,9 +83,9 @@ void RecordingCanvas::onViewportInitialized() {
void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
if (removed.flags & Snapshot::kFlagIsFboLayer) {
- addOp(new (alloc()) EndLayerOp());
+ addOp(alloc().create_trivial<EndLayerOp>());
} else if (removed.flags & Snapshot::kFlagIsLayer) {
- addOp(new (alloc()) EndUnclippedLayerOp());
+ addOp(alloc().create_trivial<EndUnclippedLayerOp>());
}
}
@@ -167,7 +167,7 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot.roundRectClipState = nullptr;
- addOp(new (alloc()) BeginLayerOp(
+ addOp(alloc().create_trivial<BeginLayerOp>(
unmappedBounds,
*previous.transform, // transform to *draw* with
previousClip, // clip to *draw* with
@@ -175,7 +175,7 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
} else {
snapshot.flags |= Snapshot::kFlagIsLayer;
- addOp(new (alloc()) BeginUnclippedLayerOp(
+ addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
unmappedBounds,
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -241,10 +241,13 @@ void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
- addOp(new (alloc()) RectOp(
- mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
+ const ClipBase* clip = getRecordedClip();
+ // if there's no current clip, draw a big rect and hope we cover the eventual clip bounds
+ Rect bounds = clip ? clip->rect : Rect(-10000, -10000, 10000, 10000);
+ addOp(alloc().create_trivial<RectOp>(
+ bounds,
Matrix4::identity(),
- getRecordedClip(),
+ clip,
refPaint(&paint)));
}
@@ -261,7 +264,7 @@ void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPa
if (floatCount < 2) return;
floatCount &= ~0x1; // round down to nearest two
- addOp(new (alloc()) PointsOp(
+ addOp(alloc().create_trivial<PointsOp>(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -272,7 +275,7 @@ void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPai
if (floatCount < 4) return;
floatCount &= ~0x3; // round down to nearest four
- addOp(new (alloc()) LinesOp(
+ addOp(alloc().create_trivial<LinesOp>(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -280,7 +283,7 @@ void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPai
}
void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
- addOp(new (alloc()) RectOp(
+ addOp(alloc().create_trivial<RectOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -290,7 +293,7 @@ void RecordingCanvas::drawRect(float left, float top, float right, float bottom,
void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
if (rects == nullptr) return;
- Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc(vertexCount * sizeof(Vertex));
+ Vertex* rectData = (Vertex*) mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
Vertex* vertex = rectData;
float left = FLT_MAX;
@@ -313,7 +316,7 @@ void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const
right = std::max(right, r);
bottom = std::max(bottom, b);
}
- addOp(new (alloc()) SimpleRectsOp(
+ addOp(alloc().create_trivial<SimpleRectsOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -347,7 +350,7 @@ void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
}
void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint& paint) {
- addOp(new (alloc()) RoundRectOp(
+ addOp(alloc().create_trivial<RoundRectOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -367,7 +370,7 @@ void RecordingCanvas::drawRoundRect(
mDisplayList->ref(ry);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(new (alloc()) RoundRectPropsOp(
+ addOp(alloc().create_trivial<RoundRectPropsOp>(
*(mState.currentSnapshot()->transform),
getRecordedClip(),
&paint->value,
@@ -389,7 +392,7 @@ void RecordingCanvas::drawCircle(
mDisplayList->ref(radius);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(new (alloc()) CirclePropsOp(
+ addOp(alloc().create_trivial<CirclePropsOp>(
*(mState.currentSnapshot()->transform),
getRecordedClip(),
&paint->value,
@@ -397,7 +400,7 @@ void RecordingCanvas::drawCircle(
}
void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
- addOp(new (alloc()) OvalOp(
+ addOp(alloc().create_trivial<OvalOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -406,16 +409,20 @@ void RecordingCanvas::drawOval(float left, float top, float right, float bottom,
void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
- addOp(new (alloc()) ArcOp(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint),
- startAngle, sweepAngle, useCenter));
+ if (fabs(sweepAngle) >= 360.0f) {
+ drawOval(left, top, right, bottom, paint);
+ } else {
+ addOp(alloc().create_trivial<ArcOp>(
+ Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(),
+ refPaint(&paint),
+ startAngle, sweepAngle, useCenter));
+ }
}
void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
- addOp(new (alloc()) PathOp(
+ addOp(alloc().create_trivial<PathOp>(
Rect(path.getBounds()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -424,7 +431,7 @@ void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- addOp(new (alloc()) VectorDrawableOp(
+ addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
Rect(tree->getBounds()),
*(mState.currentSnapshot()->transform),
@@ -475,7 +482,7 @@ void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float sr
drawBitmap(&bitmap, paint);
restore();
} else {
- addOp(new (alloc()) BitmapRectOp(
+ addOp(alloc().create_trivial<BitmapRectOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -487,7 +494,7 @@ void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float sr
void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
- addOp(new (alloc()) BitmapMeshOp(
+ addOp(alloc().create_trivial<BitmapMeshOp>(
calcBoundsOfPoints(vertices, vertexCount * 2),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -499,7 +506,7 @@ void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int
void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& patch,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) {
- addOp(new (alloc()) PatchOp(
+ addOp(alloc().create_trivial<PatchOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -515,7 +522,7 @@ void RecordingCanvas::drawText(const uint16_t* glyphs, const float* positions, i
positions = refBuffer<float>(positions, glyphCount * 2);
// TODO: either must account for text shadow in bounds, or record separate ops for text shadows
- addOp(new (alloc()) TextOp(
+ addOp(alloc().create_trivial<TextOp>(
Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -527,7 +534,7 @@ void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, con
float hOffset, float vOffset, const SkPaint& paint) {
if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
- addOp(new (alloc()) TextOnPathOp(
+ addOp(alloc().create_trivial<TextOnPathOp>(
mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -535,7 +542,7 @@ void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, con
}
void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
- addOp(new (alloc()) BitmapOp(
+ addOp(alloc().create_trivial<BitmapOp>(
Rect(bitmap->width(), bitmap->height()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -544,7 +551,7 @@ void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
auto&& stagingProps = renderNode->stagingProperties();
- RenderNodeOp* op = new (alloc()) RenderNodeOp(
+ RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -570,7 +577,7 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
totalTransform.multiply(layer->getTransform());
- addOp(new (alloc()) TextureLayerOp(
+ addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layer->getWidth(), layer->getHeight()),
totalTransform,
getRecordedClip(),
@@ -579,7 +586,7 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
mDisplayList->functors.push_back(functor);
- addOp(new (alloc()) FunctorOp(
+ addOp(alloc().create_trivial<FunctorOp>(
mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -587,7 +594,14 @@ void RecordingCanvas::callDrawGLFunction(Functor* functor) {
}
size_t RecordingCanvas::addOp(RecordedOp* op) {
- // TODO: validate if "addDrawOp" quickrejection logic is useful before adding
+ // skip op with empty clip
+ if (op->localClip && op->localClip->rect.isEmpty()) {
+ // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd
+ // and held by renderthread isn't affected by clip rejection.
+ // Could rewind alloc here if desired, but callers would have to not touch op afterwards.
+ return -1;
+ }
+
int insertIndex = mDisplayList->ops.size();
mDisplayList->ops.push_back(op);
if (mDeferredBarrierType != DeferredBarrierType::None) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index cc14e6111cec..719872d35169 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -219,7 +219,7 @@ private:
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+ T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -290,8 +290,7 @@ private:
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
- alloc().autoDestroy(localBitmap);
+ SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
mDisplayList->bitmapResources.push_back(localBitmap);
return localBitmap;
}
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 30c925c8775b..d9fce9b2c824 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWUI_RECT_H
-#define ANDROID_HWUI_RECT_H
+#pragma once
-#include <cmath>
-#include <algorithm>
-#include <SkRect.h>
+#include "Vertex.h"
#include <utils/Log.h>
-#include "Vertex.h"
+#include <algorithm>
+#include <cmath>
+#include <iomanip>
+#include <ostream>
+#include <SkRect.h>
namespace android {
namespace uirenderer {
@@ -282,9 +283,23 @@ public:
void dump(const char* label = nullptr) const {
ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
}
+
+ friend std::ostream& operator<<(std::ostream& os, const Rect& rect) {
+ if (rect.isEmpty()) {
+ return os << "empty";
+ }
+
+ if (rect.left == 0 && rect.top == 0) {
+ return os << "[" << rect.right << " x " << rect.bottom << "]";
+ }
+
+ return os << "[" << rect.left
+ << " " << rect.top
+ << " " << rect.right
+ << " " << rect.bottom << "]";
+ }
}; // class Rect
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_HWUI_RECT_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index bade216b3b21..61441ce9b16e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -19,8 +19,9 @@
#include "DamageAccumulator.h"
#include "Debug.h"
#if HWUI_NEW_OPS
-#include "RecordedOp.h"
#include "BakedOpRenderer.h"
+#include "RecordedOp.h"
+#include "OpDumper.h"
#endif
#include "DisplayListOp.h"
#include "LayerRenderer.h"
@@ -95,6 +96,34 @@ void RenderNode::setStagingDisplayList(DisplayList* displayList) {
* This function is a simplified version of replay(), where we simply retrieve and log the
* display list. This function should remain in sync with the replay() function.
*/
+#if HWUI_NEW_OPS
+void RenderNode::output(uint32_t level, const char* label) {
+ ALOGD("%s (%s %p%s%s%s%s%s)",
+ label,
+ getName(),
+ this,
+ (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""),
+ (properties().hasShadow() ? ", casting shadow" : ""),
+ (isRenderable() ? "" : ", empty"),
+ (properties().getProjectBackwards() ? ", projected" : ""),
+ (mLayer != nullptr ? ", on HW Layer" : ""));
+ properties().debugOutputProperties(level + 1);
+
+ if (mDisplayList) {
+ for (auto&& op : mDisplayList->getOps()) {
+ std::stringstream strout;
+ OpDumper::dump(*op, strout, level + 1);
+ if (op->opId == RecordedOpId::RenderNodeOp) {
+ auto rnOp = reinterpret_cast<const RenderNodeOp*>(op);
+ rnOp->renderNode->output(level + 1, strout.str().c_str());
+ } else {
+ ALOGD("%s", strout.str().c_str());
+ }
+ }
+ }
+ ALOGD("%*s/RenderNode(%s %p)", level * 2, "", getName(), this);
+}
+#else
void RenderNode::output(uint32_t level) {
ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this,
getName(),
@@ -104,22 +133,16 @@ void RenderNode::output(uint32_t level) {
(properties().getProjectBackwards() ? ", projected" : ""),
(mLayer != nullptr ? ", on HW Layer" : ""));
ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip);
-
properties().debugOutputProperties(level);
-
if (mDisplayList) {
-#if HWUI_NEW_OPS
- LOG_ALWAYS_FATAL("op dumping unsupported");
-#else
// TODO: consider printing the chunk boundaries here
for (auto&& op : mDisplayList->getOps()) {
op->output(level, DisplayListOp::kOpLogFlag_Recurse);
}
-#endif
}
-
ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
-}
+ }
+#endif
void RenderNode::copyTo(proto::RenderNode *pnode) {
pnode->set_id(static_cast<uint64_t>(
@@ -218,6 +241,10 @@ void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mAnimatorManager.addAnimator(animator);
}
+void RenderNode::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+ mAnimatorManager.removeAnimator(animator);
+}
+
void RenderNode::damageSelf(TreeInfo& info) {
if (isRenderable()) {
if (properties().getClipDamageToBounds()) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index f248de54acba..838192552127 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -123,7 +123,11 @@ public:
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
+#if HWUI_NEW_OPS
+ ANDROID_API void output(uint32_t level = 0, const char* label = "Root");
+#else
ANDROID_API void output(uint32_t level = 1);
+#endif
ANDROID_API int getDebugSize();
void copyTo(proto::RenderNode* node);
@@ -187,6 +191,12 @@ public:
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
+ void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
+
+ // This can only happen during pushStaging()
+ void onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
+ mAnimatorManager.onAnimatorTargetChanged(animator);
+ }
AnimatorManager& animators() { return mAnimatorManager; }
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index b848af4e7b1e..0b0f0fa4f304 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -102,22 +102,23 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
void RenderProperties::debugOutputProperties(const int level) const {
if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
- ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
+ ALOGD("%*s(Translate (left, top) %d, %d)", level * 2, "",
+ mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
}
if (mStaticMatrix) {
- ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
+ ALOGD("%*s(ConcatMatrix (static) %p: " SK_MATRIX_STRING ")",
level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
}
if (mAnimationMatrix) {
- ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
+ ALOGD("%*s(ConcatMatrix (animation) %p: " SK_MATRIX_STRING ")",
level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
}
if (hasTransformMatrix()) {
if (isTransformTranslateOnly()) {
- ALOGD("%*sTranslate %.2f, %.2f, %.2f",
+ ALOGD("%*s(Translate %.2f, %.2f, %.2f)",
level * 2, "", getTranslationX(), getTranslationY(), getZ());
} else {
- ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
+ ALOGD("%*s(ConcatMatrix %p: " SK_MATRIX_STRING ")",
level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
}
}
@@ -132,7 +133,7 @@ void RenderProperties::debugOutputProperties(const int level) const {
if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
// simply scale rendering content's alpha
- ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+ ALOGD("%*s(ScaleAlpha %.2f)", level * 2, "", mPrimitiveFields.mAlpha);
} else {
// savelayeralpha to create an offscreen buffer to apply alpha
Rect layerBounds(0, 0, getWidth(), getHeight());
@@ -140,19 +141,18 @@ void RenderProperties::debugOutputProperties(const int level) const {
getClippingRectForFlags(clipFlags, &layerBounds);
clipFlags = 0; // all clipping done by savelayer
}
- ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
+ ALOGD("%*s(SaveLayerAlpha %d, %d, %d, %d, %d, 0x%x)", level * 2, "",
(int)layerBounds.left, (int)layerBounds.top,
(int)layerBounds.right, (int)layerBounds.bottom,
(int)(mPrimitiveFields.mAlpha * 255),
SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer);
}
-
-
}
+
if (clipFlags) {
Rect clipRect;
getClippingRectForFlags(clipFlags, &clipRect);
- ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
+ ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
(int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
}
}
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index dbaa905b0728..b03643f06f1c 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -44,9 +44,9 @@ namespace uirenderer {
*/
class RoundRectClipState {
public:
- /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+ static void* operator new(size_t size) = delete;
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.alloc<RoundRectClipState>(size);
}
bool areaRequiresRoundRectClip(const Rect& rect) const {
@@ -65,9 +65,9 @@ public:
class ProjectionPathMask {
public:
- /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+ static void* operator new(size_t size) = delete;
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.alloc<ProjectionPathMask>(size);
}
const SkPath* projectionMask;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index c09b6dd89e4e..4f49a3518be0 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -28,13 +28,19 @@ namespace uirenderer {
static int bytesPerPixel(GLint glFormat) {
switch (glFormat) {
+ // The wrapped-texture case, usually means a SurfaceTexture
+ case 0:
+ return 0;
case GL_ALPHA:
return 1;
case GL_RGB:
return 3;
case GL_RGBA:
- default:
return 4;
+ case GL_RGBA16F:
+ return 16;
+ default:
+ LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat);
}
}
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 5510666eef86..4dfb41dafcc7 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -23,7 +23,7 @@
#include "Vertex.h"
#include <GLES3/gl3.h>
-#include <SkScalerContext.h>
+#include <SkGlyph.h>
#include <utils/Log.h>
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index e8882d9f4bda..288f73361bbc 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -23,7 +23,6 @@
#include <SkScalar.h>
#include <SkGlyphCache.h>
-#include <SkScalerContext.h>
#include <SkPaint.h>
#include <SkPathMeasure.h>
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
new file mode 100644
index 000000000000..7d4ef0f1f31e
--- /dev/null
+++ b/libs/hwui/hwui_static_deps.mk
@@ -0,0 +1,28 @@
+###############################################################################
+#
+#
+# This file contains the shared and static dependencies needed by any target
+# that attempts to statically link HWUI (i.e. libhwui_static build target). This
+# file should be included by any target that lists libhwui_static as a
+# dependency.
+#
+# This is a workaround for the fact that the build system does not add these
+# transitive dependencies when it attempts to link libhwui_static into another
+# library.
+#
+###############################################################################
+
+LOCAL_SHARED_LIBRARIES += \
+ liblog \
+ libcutils \
+ libutils \
+ libEGL \
+ libGLESv2 \
+ libskia \
+ libui \
+ libgui \
+ libprotobuf-cpp-lite
+
+ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+ LOCAL_SHARED_LIBRARIES += libRS libRScpp
+endif \ No newline at end of file
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 03cb5ce8ce2e..b575c696586e 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -34,7 +34,6 @@ MeshState::MeshState()
glGenBuffers(1, &mUnitQuadBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
-
mCurrentBuffer = mUnitQuadBuffer;
uint16_t regionIndices[kMaxNumberOfQuads * 6];
@@ -78,26 +77,18 @@ void MeshState::dump() {
// Buffer Objects
///////////////////////////////////////////////////////////////////////////////
-bool MeshState::bindMeshBuffer() {
- return bindMeshBuffer(mUnitQuadBuffer);
-}
-
-bool MeshState::bindMeshBuffer(GLuint buffer) {
- if (!buffer) buffer = mUnitQuadBuffer;
- return bindMeshBufferInternal(buffer);
-}
-
-bool MeshState::unbindMeshBuffer() {
- return bindMeshBufferInternal(0);
-}
-
-bool MeshState::bindMeshBufferInternal(GLuint buffer) {
+void MeshState::bindMeshBuffer(GLuint buffer) {
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
mCurrentBuffer = buffer;
- return true;
+
+ // buffer has changed, so invalidate cached vertex pos/texcoord pointers
+ resetVertexPointers();
}
- return false;
+}
+
+void MeshState::unbindMeshBuffer() {
+ return bindMeshBuffer(0);
}
void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
@@ -122,16 +113,22 @@ void MeshState::deleteMeshBuffer(GLuint buffer) {
// Vertices
///////////////////////////////////////////////////////////////////////////////
-void MeshState::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
- if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
+void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) {
+ // update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
+ if (mCurrentBuffer == 0
+ || vertices != mCurrentPositionPointer
+ || stride != mCurrentPositionStride) {
glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
mCurrentPositionPointer = vertices;
mCurrentPositionStride = stride;
}
}
-void MeshState::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
- if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
+void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) {
+ // update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
+ if (mCurrentBuffer == 0
+ || vertices != mCurrentTexCoordsPointer
+ || stride != mCurrentTexCoordsStride) {
glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
mCurrentTexCoordsPointer = vertices;
mCurrentTexCoordsStride = stride;
@@ -143,10 +140,6 @@ void MeshState::resetVertexPointers() {
mCurrentTexCoordsPointer = this;
}
-void MeshState::resetTexCoordsVertexPointer() {
- mCurrentTexCoordsPointer = this;
-}
-
void MeshState::enableTexCoordsVertexArray() {
if (!mTexCoordsArrayEnabled) {
glEnableVertexAttribArray(Program::kBindingTexCoords);
@@ -166,26 +159,18 @@ void MeshState::disableTexCoordsVertexArray() {
// Indices
///////////////////////////////////////////////////////////////////////////////
-bool MeshState::bindIndicesBufferInternal(const GLuint buffer) {
+void MeshState::bindIndicesBuffer(const GLuint buffer) {
if (mCurrentIndicesBuffer != buffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
mCurrentIndicesBuffer = buffer;
- return true;
}
- return false;
-}
-
-bool MeshState::bindQuadIndicesBuffer() {
- return bindIndicesBufferInternal(mQuadListIndices);
}
-bool MeshState::unbindIndicesBuffer() {
+void MeshState::unbindIndicesBuffer() {
if (mCurrentIndicesBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
mCurrentIndicesBuffer = 0;
- return true;
}
- return false;
}
} /* namespace uirenderer */
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
index 6c0fb78cae17..dd684686f584 100644
--- a/libs/hwui/renderstate/MeshState.h
+++ b/libs/hwui/renderstate/MeshState.h
@@ -60,20 +60,16 @@ public:
///////////////////////////////////////////////////////////////////////////////
// Buffer objects
///////////////////////////////////////////////////////////////////////////////
- /**
- * Binds the VBO used to render simple textured quads.
- */
- bool bindMeshBuffer();
/**
* Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad.
*/
- bool bindMeshBuffer(GLuint buffer);
+ void bindMeshBuffer(GLuint buffer);
/**
- * Unbinds the VBO used to render simple textured quads.
+ * Unbinds the current VBO if active.
*/
- bool unbindMeshBuffer();
+ void unbindMeshBuffer();
void genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data, GLenum usage);
void deleteMeshBuffer(GLuint);
@@ -85,21 +81,20 @@ public:
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gTextureVertexStride and a size of 2.
*/
- void bindPositionVertexPointer(bool force, const GLvoid* vertices,
+ void bindPositionVertexPointer(const GLvoid* vertices,
GLsizei stride = kTextureVertexStride);
/**
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gTextureVertexStride and a size of 2.
*/
- void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices,
+ void bindTexCoordsVertexPointer(const GLvoid* vertices,
GLsizei stride = kTextureVertexStride);
/**
* Resets the vertex pointers.
*/
void resetVertexPointers();
- void resetTexCoordsVertexPointer();
void enableTexCoordsVertexArray();
void disableTexCoordsVertexArray();
@@ -107,12 +102,8 @@ public:
///////////////////////////////////////////////////////////////////////////////
// Indices
///////////////////////////////////////////////////////////////////////////////
- /**
- * Binds a global indices buffer that can draw up to
- * gMaxNumberOfQuads quads.
- */
- bool bindQuadIndicesBuffer();
- bool unbindIndicesBuffer();
+ void bindIndicesBuffer(const GLuint buffer);
+ void unbindIndicesBuffer();
///////////////////////////////////////////////////////////////////////////////
// Getters - for use in Glop building
@@ -121,8 +112,6 @@ public:
GLuint getQuadListIBO() { return mQuadListIndices; }
private:
MeshState();
- bool bindMeshBufferInternal(const GLuint buffer);
- bool bindIndicesBufferInternal(const GLuint buffer);
GLuint mUnitQuadBuffer;
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index 54f38e848327..5f984b59ebd9 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -54,6 +54,14 @@ Rect OffscreenBuffer::getTextureCoordinates() {
return Rect(0, viewportHeight * texY, viewportWidth * texX, 0);
}
+void OffscreenBuffer::dirty(Rect dirtyArea) {
+ dirtyArea.doIntersect(0, 0, viewportWidth, viewportHeight);
+ if (!dirtyArea.isEmpty()) {
+ region.orSelf(android::Rect(dirtyArea.left, dirtyArea.top,
+ dirtyArea.right, dirtyArea.bottom));
+ }
+}
+
void OffscreenBuffer::updateMeshFromRegion() {
// avoid T-junctions as they cause artifacts in between the resultant
// geometry when complex transforms occur.
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index 94155efcbb0a..089f131668a0 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -48,6 +48,8 @@ public:
Rect getTextureCoordinates();
+ void dirty(Rect dirtyArea);
+
// must be called prior to rendering, to construct/update vertex buffer
void updateMeshFromRegion();
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index e535f2f2a640..ea4391b87006 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -292,28 +292,27 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) {
// ---------- Mesh setup ----------
// --------------------------------
// vertices
- const bool force = meshState().bindMeshBufferInternal(vertices.bufferObject)
- || (vertices.position != nullptr);
- meshState().bindPositionVertexPointer(force, vertices.position, vertices.stride);
+ meshState().bindMeshBuffer(vertices.bufferObject);
+ meshState().bindPositionVertexPointer(vertices.position, vertices.stride);
// indices
- meshState().bindIndicesBufferInternal(indices.bufferObject);
+ meshState().bindIndicesBuffer(indices.bufferObject);
if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
const Glop::Fill::TextureData& texture = fill.texture;
// texture always takes slot 0, shader samplers increment from there
mCaches->textureState().activateTexture(0);
+ mCaches->textureState().bindTexture(texture.target, texture.texture->id());
if (texture.clamp != GL_INVALID_ENUM) {
- texture.texture->setWrap(texture.clamp, true, false, texture.target);
+ texture.texture->setWrap(texture.clamp, false, false, texture.target);
}
if (texture.filter != GL_INVALID_ENUM) {
- texture.texture->setFilter(texture.filter, true, false, texture.target);
+ texture.texture->setFilter(texture.filter, false, false, texture.target);
}
- mCaches->textureState().bindTexture(texture.target, texture.texture->id());
meshState().enableTexCoordsVertexArray();
- meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
+ meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride);
if (texture.textureTransform) {
glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
@@ -361,11 +360,9 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) {
const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
while (elementsCount > 0) {
GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
-
- // rebind pointers without forcing, since initial bind handled above
- meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
+ meshState().bindPositionVertexPointer(vertexData, vertices.stride);
if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
- meshState().bindTexCoordsVertexPointer(false,
+ meshState().bindTexCoordsVertexPointer(
vertexData + kMeshTextureOffset, vertices.stride);
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ea702c01694e..249d83f50627 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -476,7 +476,7 @@ void CanvasContext::draw() {
// metrics the frame was swapped at this point
mCurrentFrameInfo->markSwapBuffers();
- if (drew) {
+ if (drew || mEglManager.damageRequiresSwap()) {
if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
setSurface(nullptr);
}
@@ -507,8 +507,8 @@ void CanvasContext::draw() {
mJankTracker.addFrame(*mCurrentFrameInfo);
mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
- if (CC_UNLIKELY(mFrameStatsReporter.get() != nullptr)) {
- mFrameStatsReporter->reportFrameStats(mCurrentFrameInfo->data());
+ if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) {
+ mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data());
}
GpuMemoryTracker::onFrameCompleted();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 168166ef5b23..cb61e51a2158 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -20,7 +20,7 @@
#include "DamageAccumulator.h"
#include "FrameInfo.h"
#include "FrameInfoVisualizer.h"
-#include "FrameStatsReporter.h"
+#include "FrameMetricsReporter.h"
#include "IContextFactory.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
@@ -142,31 +142,23 @@ public:
return mRenderThread.renderState();
}
- void addFrameStatsObserver(FrameStatsObserver* observer) {
- if (mFrameStatsReporter.get() == nullptr) {
- mFrameStatsReporter.reset(new FrameStatsReporter());
+ void addFrameMetricsObserver(FrameMetricsObserver* observer) {
+ if (mFrameMetricsReporter.get() == nullptr) {
+ mFrameMetricsReporter.reset(new FrameMetricsReporter());
}
- mFrameStatsReporter->addObserver(observer);
+ mFrameMetricsReporter->addObserver(observer);
}
- void removeFrameStatsObserver(FrameStatsObserver* observer) {
- if (mFrameStatsReporter.get() != nullptr) {
- mFrameStatsReporter->removeObserver(observer);
- if (!mFrameStatsReporter->hasObservers()) {
- mFrameStatsReporter.reset(nullptr);
+ void removeFrameMetricsObserver(FrameMetricsObserver* observer) {
+ if (mFrameMetricsReporter.get() != nullptr) {
+ mFrameMetricsReporter->removeObserver(observer);
+ if (!mFrameMetricsReporter->hasObservers()) {
+ mFrameMetricsReporter.reset(nullptr);
}
}
}
- long getDroppedFrameReportCount() {
- if (mFrameStatsReporter.get() != nullptr) {
- return mFrameStatsReporter->getDroppedReports();
- }
-
- return 0;
- }
-
private:
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -215,7 +207,7 @@ private:
std::string mName;
JankTracker mJankTracker;
FrameInfoVisualizer mProfiler;
- std::unique_ptr<FrameStatsReporter> mFrameStatsReporter;
+ std::unique_ptr<FrameMetricsReporter> mFrameMetricsReporter;
std::set<RenderNode*> mPrefetechedLayers;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 364d4dda1e7f..8def7ad03d34 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -270,6 +270,12 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
// Ensure we always have a valid surface & context
surface = mPBufferSurface;
}
+ // TODO: Temporary to help diagnose b/27286867
+ if (mCurrentSurface == mPBufferSurface || surface == mPBufferSurface) {
+ ALOGD("Switching from surface %p%s to %p%s", mCurrentSurface,
+ mCurrentSurface == mPBufferSurface ? " (pbuffer)" : "",
+ surface, surface == mPBufferSurface ? " (pbuffer)" : "");
+ }
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
if (errOut) {
*errOut = eglGetError();
@@ -324,6 +330,10 @@ void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) {
#endif
}
+bool EglManager::damageRequiresSwap() {
+ return EglExtensions.setDamage && mSwapBehavior == SwapBehavior::BufferAge;
+}
+
bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 62b5b99a6e30..459baed70e40 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -70,6 +70,10 @@ public:
bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr);
Frame beginFrame(EGLSurface surface);
void damageFrame(const Frame& frame, const SkRect& dirty);
+ // If this returns true it is mandatory that swapBuffers is called
+ // if damageFrame is called without subsequent calls to damageFrame().
+ // See EGL_KHR_partial_update for more information
+ bool damageRequiresSwap();
bool swapBuffers(const Frame& frame, const SkRect& screenDirty);
// Returns true iff the surface is now preserving buffers.
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 7c6cd7e014ef..04223a7d5188 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -568,17 +568,17 @@ void RenderProxy::serializeDisplayListTree() {
post(task);
}
-CREATE_BRIDGE2(addFrameStatsObserver, CanvasContext* context,
- FrameStatsObserver* frameStatsObserver) {
- args->context->addFrameStatsObserver(args->frameStatsObserver);
+CREATE_BRIDGE2(addFrameMetricsObserver, CanvasContext* context,
+ FrameMetricsObserver* frameStatsObserver) {
+ args->context->addFrameMetricsObserver(args->frameStatsObserver);
if (args->frameStatsObserver != nullptr) {
args->frameStatsObserver->decStrong(args->context);
}
return nullptr;
}
-void RenderProxy::addFrameStatsObserver(FrameStatsObserver* observer) {
- SETUP_TASK(addFrameStatsObserver);
+void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observer) {
+ SETUP_TASK(addFrameMetricsObserver);
args->context = mContext;
args->frameStatsObserver = observer;
if (observer != nullptr) {
@@ -587,17 +587,17 @@ void RenderProxy::addFrameStatsObserver(FrameStatsObserver* observer) {
post(task);
}
-CREATE_BRIDGE2(removeFrameStatsObserver, CanvasContext* context,
- FrameStatsObserver* frameStatsObserver) {
- args->context->removeFrameStatsObserver(args->frameStatsObserver);
+CREATE_BRIDGE2(removeFrameMetricsObserver, CanvasContext* context,
+ FrameMetricsObserver* frameStatsObserver) {
+ args->context->removeFrameMetricsObserver(args->frameStatsObserver);
if (args->frameStatsObserver != nullptr) {
args->frameStatsObserver->decStrong(args->context);
}
return nullptr;
}
-void RenderProxy::removeFrameStatsObserver(FrameStatsObserver* observer) {
- SETUP_TASK(removeFrameStatsObserver);
+void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observer) {
+ SETUP_TASK(removeFrameMetricsObserver);
args->context = mContext;
args->frameStatsObserver = observer;
if (observer != nullptr) {
@@ -606,16 +606,6 @@ void RenderProxy::removeFrameStatsObserver(FrameStatsObserver* observer) {
post(task);
}
-CREATE_BRIDGE1(getDroppedFrameReportCount, CanvasContext* context) {
- return (void*) args->context->getDroppedFrameReportCount();
-}
-
-long RenderProxy::getDroppedFrameReportCount() {
- SETUP_TASK(getDroppedFrameReportCount);
- args->context = mContext;
- return (long) postAndWait(task);
-}
-
void RenderProxy::post(RenderTask* task) {
mRenderThread.queue(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 178724a85d04..8d65a8259513 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -29,7 +29,7 @@
#include <utils/StrongPointer.h>
#include "../Caches.h"
-#include "../FrameStatsObserver.h"
+#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
#include "CanvasContext.h"
#include "DrawFrameTask.h"
@@ -113,8 +113,8 @@ public:
ANDROID_API void drawRenderNode(RenderNode* node);
ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
- ANDROID_API void addFrameStatsObserver(FrameStatsObserver* observer);
- ANDROID_API void removeFrameStatsObserver(FrameStatsObserver* observer);
+ ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
+ ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API long getDroppedFrameReportCount();
private:
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 3440d03b4fc5..9595a85e99dd 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -162,6 +162,7 @@ void TestUtils::TestTask::run() {
renderState.onGLContextCreated();
rtCallback(renderthread::RenderThread::getInstance());
+ renderState.flush(Caches::FlushMode::Full);
renderState.onGLContextDestroyed();
// Restore the previous signal handler
diff --git a/libs/hwui/tests/unit/BufferPoolTests.cpp b/libs/hwui/tests/unit/BufferPoolTests.cpp
deleted file mode 100644
index 44e6d3a0cbea..000000000000
--- a/libs/hwui/tests/unit/BufferPoolTests.cpp
+++ /dev/null
@@ -1,102 +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.
- */
-
-#include <gtest/gtest.h>
-
-#include <BufferPool.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace uirenderer {
-
-TEST(BufferPool, acquireThenRelease) {
- static const int numRuns = 5;
-
- // 10 buffers of size 1
- static const size_t bufferSize = 1;
- static const size_t bufferCount = 10;
- sp<BufferPool> pool = new BufferPool(bufferSize, bufferCount);
-
- for (int run = 0; run < numRuns; run++) {
- BufferPool::Buffer* acquiredBuffers[bufferCount];
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
- acquiredBuffers[i] = pool->acquire();
- ASSERT_NE(nullptr, acquiredBuffers[i]);
- ASSERT_TRUE(acquiredBuffers[i]->isUniqueRef());
- }
-
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(i, pool->getAvailableBufferCount());
- acquiredBuffers[i]->release();
- acquiredBuffers[i] = nullptr;
- }
-
- ASSERT_EQ(bufferCount, pool->getAvailableBufferCount());
- }
-}
-
-TEST(BufferPool, acquireReleaseInterleaved) {
- static const int numRuns = 5;
-
- // 10 buffers of size 1
- static const size_t bufferSize = 1;
- static const size_t bufferCount = 10;
-
- sp<BufferPool> pool = new BufferPool(bufferSize, bufferCount);
-
- for (int run = 0; run < numRuns; run++) {
- BufferPool::Buffer* acquiredBuffers[bufferCount];
-
- // acquire all
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
- acquiredBuffers[i] = pool->acquire();
- ASSERT_NE(nullptr, acquiredBuffers[i]);
- }
-
- // release half
- for (size_t i = 0; i < bufferCount / 2; i++) {
- ASSERT_EQ(i, pool->getAvailableBufferCount());
- acquiredBuffers[i]->release();
- acquiredBuffers[i] = nullptr;
- }
-
- const size_t expectedRemaining = bufferCount / 2;
- ASSERT_EQ(expectedRemaining, pool->getAvailableBufferCount());
-
- // acquire half
- for (size_t i = 0; i < bufferCount / 2; i++) {
- ASSERT_EQ(expectedRemaining - i, pool->getAvailableBufferCount());
- acquiredBuffers[i] = pool->acquire();
- }
-
- // acquire one more, should fail
- ASSERT_EQ(nullptr, pool->acquire());
-
- // release all
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(i, pool->getAvailableBufferCount());
- acquiredBuffers[i]->release();
- acquiredBuffers[i] = nullptr;
- }
-
- ASSERT_EQ(bufferCount, pool->getAvailableBufferCount());
- }
-}
-
-};
-};
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index 4cae737ab295..dc2ea0784b7e 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -133,7 +133,7 @@ TEST(ClipArea, serializeClip) {
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
auto clipRect = reinterpret_cast<const ClipRect*>(serializedClip);
- ASSERT_EQ(Rect(200, 200), clipRect->rect);
+ EXPECT_EQ(Rect(200, 200), clipRect->rect);
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
@@ -147,7 +147,10 @@ TEST(ClipArea, serializeClip) {
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
- ASSERT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ EXPECT_FALSE(clipRectList->rect.isEmpty());
+ EXPECT_FLOAT_EQ(199.87817f, clipRectList->rect.right)
+ << "Right side should be clipped by rotated rect";
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
@@ -161,8 +164,9 @@ TEST(ClipArea, serializeClip) {
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::Region, serializedClip->mode);
auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
- ASSERT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
+ EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
<< "Clip region should be 200x200";
+ EXPECT_EQ(Rect(200, 200), clipRegion->rect);
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
}
@@ -224,6 +228,7 @@ TEST(ClipArea, serializeIntersectedClip) {
ClipRegion recordedClip;
recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+ recordedClip.rect = Rect(200, 200);
Matrix4 translate10x20;
translate10x20.loadTranslate(10, 20, 0);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index f49dd3f6bc81..f86898fd669a 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -651,6 +651,62 @@ TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
<< "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
}
+TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
+ class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
+ public:
+ void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ }
+ void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ ASSERT_NE(nullptr, op.paint);
+ EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
+ << "Expect dirty rect as clip";
+ ASSERT_NE(nullptr, state.computedState.clipState);
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
+ EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(2, mIndex++);
+ }
+ void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(3, mIndex++);
+ }
+ };
+
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // save smaller than clip, so we get unclipped behavior
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.restore();
+ });
+
+ // draw with partial screen dirty, and assert we see that rect later
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+ SaveLayerUnclippedClearClipTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(4, renderer.getIndex());
+}
+
+TEST(FrameBuilder, saveLayerUnclipped_reject) {
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // unclipped savelayer + rect both in area that won't intersect with dirty
+ canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(100, 100, 200, 200, SkPaint());
+ canvas.restore();
+ });
+
+ // draw with partial screen dirty that doesn't intersect with savelayer
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+ FailRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
* - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
* - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 5c442901045e..402a09c55e8f 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -30,7 +30,7 @@ struct SimplePair {
TEST(LinearAllocator, create) {
LinearAllocator la;
EXPECT_EQ(0u, la.usedSize());
- la.alloc(64);
+ la.alloc<char>(64);
// There's some internal tracking as well as padding
// so the usedSize isn't strictly defined
EXPECT_LE(64u, la.usedSize());
@@ -50,13 +50,12 @@ TEST(LinearAllocator, dtor) {
la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
la.create<SimplePair>();
}
- la.alloc(100);
+ la.alloc<char>(100);
for (int i = 0; i < 5; i++) {
- auto sd = new (la) TestUtils::SignalingDtor(destroyed + 5 + i);
- la.autoDestroy(sd);
- new (la) SimplePair();
+ la.create<TestUtils::SignalingDtor>(destroyed + 5 + i);
+ la.create_trivial<SimplePair>();
}
- la.alloc(100);
+ la.alloc<char>(100);
for (int i = 0; i < 10; i++) {
EXPECT_EQ(0, destroyed[i]);
}
@@ -70,7 +69,7 @@ TEST(LinearAllocator, rewind) {
int destroyed = 0;
{
LinearAllocator la;
- auto addr = la.alloc(100);
+ auto addr = la.alloc<char>(100);
EXPECT_LE(100u, la.usedSize());
la.rewindIfLastAlloc(addr, 100);
EXPECT_GT(16u, la.usedSize());
diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp
new file mode 100644
index 000000000000..da2263788c25
--- /dev/null
+++ b/libs/hwui/tests/unit/MatrixTests.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+
+using namespace android::uirenderer;
+
+TEST(Matrix, mapRect) {
+ // Skew, so we don't hit identity/translate/simple fast paths
+ Matrix4 matrix;
+ matrix.skew(0.1f, 0.1f);
+
+ // non-zero empty rect, so sorting x/y would make rect non-empty
+ Rect empty(100, 100, -100, -100);
+ ASSERT_TRUE(empty.isEmpty());
+ matrix.mapRect(empty);
+ EXPECT_TRUE(empty.isEmpty())
+ << "Empty rect should always remain empty, regardless of mapping.";
+}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 2fd879562265..0c6eb571b9b4 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -55,6 +55,14 @@ TEST(OffscreenBuffer, getTextureCoordinates) {
});
}
+TEST(OffscreenBuffer, dirty) {
+ TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
+ OffscreenBuffer buffer(thread.renderState(), Caches::getInstance(), 256u, 256u);
+ buffer.dirty(Rect(-100, -100, 100, 100));
+ EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds());
+ });
+}
+
TEST(OffscreenBufferPool, construct) {
TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
OffscreenBufferPool pool;
diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp
new file mode 100644
index 000000000000..01840d72b766
--- /dev/null
+++ b/libs/hwui/tests/unit/OpDumperTests.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "tests/common/TestUtils.h"
+#include "OpDumper.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(OpDumper, dump) {
+ SkPaint paint;
+ RectOp op(uirenderer::Rect(100, 100), Matrix4::identity(), nullptr, &paint);
+
+ std::stringstream stream;
+ OpDumper::dump(op, stream);
+ EXPECT_STREQ("RectOp [100 x 100]", stream.str().c_str());
+
+ stream.str("");
+ OpDumper::dump(op, stream, 2);
+ EXPECT_STREQ(" RectOp [100 x 100]", stream.str().c_str());
+
+ ClipRect clipRect(uirenderer::Rect(50, 50));
+ op.localClip = &clipRect;
+
+ stream.str("");
+ OpDumper::dump(op, stream, 2);
+ EXPECT_STREQ(" RectOp [100 x 100] clip=[50 x 50] mode=0", stream.str().c_str());
+}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 20d2f1f18c58..c39047ca1d89 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -19,6 +19,7 @@
#include <RecordedOp.h>
#include <RecordingCanvas.h>
#include <tests/common/TestUtils.h>
+#include <utils/Color.h>
namespace android {
namespace uirenderer {
@@ -57,6 +58,33 @@ TEST(RecordingCanvas, clipRect) {
<< "Clip should be serialized once";
}
+TEST(RecordingCanvas, emptyClipRect) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+ canvas.clipRect(100, 100, 200, 200, SkRegion::kIntersect_Op);
+ canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
+ canvas.restore();
+ });
+ ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
+}
+
+TEST(RecordingCanvas, drawArc) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
+ canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint());
+ });
+
+ auto&& ops = dl->getOps();
+ ASSERT_EQ(2u, ops.size()) << "Must be exactly two ops";
+ EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId);
+ EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds);
+
+ EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId)
+ << "Circular arcs should be converted to ovals";
+ EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
+}
+
TEST(RecordingCanvas, drawLines) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkPaint paint;
@@ -169,6 +197,19 @@ TEST(RecordingCanvas, drawText_forceAlignLeft) {
ASSERT_EQ(3, count);
}
+TEST(RecordingCanvas, drawColor) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.drawColor(Color::Black, SkXfermode::kSrcOver_Mode);
+ });
+
+ ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
+ auto op = *(dl->getOps()[0]);
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_TRUE(op.unmappedBounds.contains(Rect(-1000, -1000, 1000, 1000)))
+ << "no clip, unmappedBounds should resolve to be much larger than DL bounds";
+}
+
TEST(RecordingCanvas, backgroundAndImage) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkBitmap bitmap;
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index e6a4c03156b4..5bba420a258f 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -81,10 +81,6 @@ static void _addAllocation(int count) {
#define min(x,y) (((x) < (y)) ? (x) : (y))
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la) {
- return la.alloc(size);
-}
-
namespace android {
namespace uirenderer {
@@ -171,7 +167,7 @@ void LinearAllocator::ensureNext(size_t size) {
mNext = start(mCurrentPage);
}
-void* LinearAllocator::alloc(size_t size) {
+void* LinearAllocator::allocImpl(size_t size) {
size = ALIGN(size);
if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
@@ -196,7 +192,7 @@ void LinearAllocator::addToDestructionList(Destructor dtor, void* addr) {
"DestructorNode must have standard layout");
static_assert(std::is_trivially_destructible<DestructorNode>::value,
"DestructorNode must be trivially destructable");
- auto node = new (*this) DestructorNode();
+ auto node = new (allocImpl(sizeof(DestructorNode))) DestructorNode();
node->dtor = dtor;
node->addr = addr;
node->next = mDtorList;
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index dcbc0dda951a..34c8c6beea81 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -52,30 +52,43 @@ public:
* The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
* delete() on an object stored in a buffer is needed, it should be overridden to use
* rewindIfLastAlloc()
+ *
+ * Note that unlike create, for alloc the type is purely for compile-time error
+ * checking and does not affect size.
*/
- void* alloc(size_t size);
+ template<class T>
+ void* alloc(size_t size) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, type is non-trivial! did you mean to use create()?");
+ return allocImpl(size);
+ }
/**
* Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
template<class T, typename... Params>
- T* create(Params... params) {
- T* ret = new (*this) T(params...);
- autoDestroy(ret);
+ T* create(Params&&... params) {
+ T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
+ if (!std::is_trivially_destructible<T>::value) {
+ auto dtor = [](void* ret) { ((T*)ret)->~T(); };
+ addToDestructionList(dtor, ret);
+ }
return ret;
}
- /**
- * Adds the pointer to the tracking list to have its destructor called
- * when the LinearAllocator is destroyed.
- */
+ template<class T, typename... Params>
+ T* create_trivial(Params&&... params) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, called create_trivial on a non-trivial type");
+ return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
+ }
+
template<class T>
- void autoDestroy(T* addr) {
- if (!std::is_trivially_destructible<T>::value) {
- auto dtor = [](void* addr) { ((T*)addr)->~T(); };
- addToDestructionList(dtor, addr);
- }
+ T* create_trivial_array(int count) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, called create_trivial_array on a non-trivial type");
+ return reinterpret_cast<T*>(allocImpl(sizeof(T) * count));
}
/**
@@ -114,6 +127,8 @@ private:
DestructorNode* next = nullptr;
};
+ void* allocImpl(size_t size);
+
void addToDestructionList(Destructor, void* addr);
void runDestructorFor(void* addr);
Page* newPage(size_t pageSize);
@@ -159,7 +174,7 @@ public:
: linearAllocator(other.linearAllocator) {}
T* allocate(size_t num, const void* = 0) {
- return (T*)(linearAllocator.alloc(num * sizeof(T)));
+ return (T*)(linearAllocator.alloc<void*>(num * sizeof(T)));
}
void deallocate(pointer p, size_t num) {
@@ -187,6 +202,4 @@ public:
}; // namespace uirenderer
}; // namespace android
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la);
-
#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index 05a3d5931e5d..5add95711f2d 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -42,7 +42,7 @@ struct SizePrinter {
static const char* SUFFIXES[] = {"B", "KiB", "MiB"};
size_t suffix = 0;
double temp = d.bytes;
- while (temp > 1000 && suffix < 2) {
+ while (temp > 1024 && suffix < 2) {
temp /= 1024.0;
suffix++;
}
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 37ef3df7990f..3c8a78d4d18d 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -16,42 +16,16 @@
package android.location;
-import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* A class containing a GPS clock timestamp.
* It represents a measurement of the GPS receiver's clock.
*/
public final class GnssClock implements Parcelable {
-
// The following enumerations must be in sync with the values declared in gps.h
- /** The type of the GPS Clock. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({CLOCK_TYPE_UNKNOWN, CLOCK_TYPE_LOCAL_HW_TIME, CLOCK_TYPE_GPS_TIME})
- public @interface GnssClockType {}
-
- /**
- * The type of the time stored is not available or it is unknown.
- */
- public static final byte CLOCK_TYPE_UNKNOWN = 0;
-
- /**
- * The source of the time value reported by this class is the 'Local Hardware Clock'.
- */
- public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1;
-
- /**
- * The source of the time value reported by this class is the 'GPS time' derived from
- * satellites (epoch = Jan 6, 1980).
- */
- public static final byte CLOCK_TYPE_GPS_TIME = 2;
-
private static final short HAS_NO_FLAGS = 0;
private static final short HAS_LEAP_SECOND = (1<<0);
private static final short HAS_TIME_UNCERTAINTY = (1<<1);
@@ -65,7 +39,6 @@ public final class GnssClock implements Parcelable {
private short mFlags;
private short mLeapSecond;
- private byte mType;
private long mTimeInNs;
private double mTimeUncertaintyInNs;
private long mFullBiasInNs;
@@ -73,7 +46,7 @@ public final class GnssClock implements Parcelable {
private double mBiasUncertaintyInNs;
private double mDriftInNsPerSec;
private double mDriftUncertaintyInNsPerSec;
- private long mTimeOfLastHwClockDiscontinuityInNs;
+ private int mHardwareClockDiscontinuityCount;
GnssClock() {
initialize();
@@ -85,7 +58,6 @@ public final class GnssClock implements Parcelable {
public void set(GnssClock clock) {
mFlags = clock.mFlags;
mLeapSecond = clock.mLeapSecond;
- mType = clock.mType;
mTimeInNs = clock.mTimeInNs;
mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
mFullBiasInNs = clock.mFullBiasInNs;
@@ -93,7 +65,7 @@ public final class GnssClock implements Parcelable {
mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
mDriftInNsPerSec = clock.mDriftInNsPerSec;
mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
- mTimeOfLastHwClockDiscontinuityInNs = clock.mTimeOfLastHwClockDiscontinuityInNs;
+ mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
}
/**
@@ -104,38 +76,6 @@ public final class GnssClock implements Parcelable {
}
/**
- * Gets the type of time reported by {@link #getTimeInNs()}.
- */
- @GnssClockType
- public byte getType() {
- return mType;
- }
-
- /**
- * Sets the type of time reported.
- */
- public void setType(@GnssClockType byte value) {
- mType = value;
- }
-
- /**
- * Gets a string representation of the 'type'.
- * For internal and logging use only.
- */
- private String getTypeString() {
- switch (mType) {
- case CLOCK_TYPE_UNKNOWN:
- return "Unknown";
- case CLOCK_TYPE_GPS_TIME:
- return "GpsTime";
- case CLOCK_TYPE_LOCAL_HW_TIME:
- return "LocalHwClock";
- default:
- return "<Invalid:" + mType + ">";
- }
- }
-
- /**
* Returns true if {@link #getLeapSecond()} is available, false otherwise.
*/
public boolean hasLeapSecond() {
@@ -170,10 +110,7 @@ public final class GnssClock implements Parcelable {
}
/**
- * Gets the GPS receiver internal clock value in nanoseconds.
- * This can be either the 'local hardware clock' value ({@link #CLOCK_TYPE_LOCAL_HW_TIME}), or the
- * current GPS time derived inside GPS receiver ({@link #CLOCK_TYPE_GPS_TIME}).
- * {@link #getType()} defines the time reported.
+ * Gets the GNSS receiver internal clock value in nanoseconds.
*
* For 'local hardware clock' this value is expected to be monotonically increasing during the
* reporting session. The real GPS time can be derived by compensating
@@ -241,15 +178,14 @@ public final class GnssClock implements Parcelable {
* Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
* the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
*
- * This value is available if {@link #CLOCK_TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
- * the clock for GPS time.
- * {@link #getBiasUncertaintyInNs()} should be used for quality check.
+ * This value is available if the receiver has estimated GPS time. If the computed time is for a
+ * non-GPS constellation, the time offset of that constellation to GPS has to be applied to fill
+ * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyInNs()} in
+ * it, and it should be used for quality check. The value is only available if
+ * {@link #hasFullBiasInNs()} is true.
*
* The sign of the value is defined by the following equation:
- * true time (GPS time) = time_ns + (full_bias_ns + bias_ns)
- *
- * The reported full bias includes {@link #getBiasUncertaintyInNs()}.
- * The value is onl available if {@link #hasFullBiasInNs()} is true.
+ * local estimate of GPS time = time_ns + (full_bias_ns + bias_ns)
*/
public long getFullBiasInNs() {
return mFullBiasInNs;
@@ -395,17 +331,17 @@ public final class GnssClock implements Parcelable {
}
/**
- * Gets time of last hardware clock discontinuity.
+ * Gets count of last hardware clock discontinuity.
*/
- public long getTimeOfLastHwClockDiscontinuityInNs() {
- return mTimeOfLastHwClockDiscontinuityInNs;
+ public int getHardwareClockDiscontinuityCount() {
+ return mHardwareClockDiscontinuityCount;
}
/**
- * Sets time of last hardware clock discontinuity.
+ * Sets count of last hardware clock discontinuity.
*/
- public void setTimeOfLastHwClockDiscontinuityInNs(long timeOfLastHwClockDiscontinuityInNs) {
- mTimeOfLastHwClockDiscontinuityInNs = timeOfLastHwClockDiscontinuityInNs;
+ public void setHardwareClockDiscontinuityCount(int value) {
+ mHardwareClockDiscontinuityCount = value;
}
/**
@@ -423,7 +359,6 @@ public final class GnssClock implements Parcelable {
gpsClock.mFlags = (short) parcel.readInt();
gpsClock.mLeapSecond = (short) parcel.readInt();
- gpsClock.mType = parcel.readByte();
gpsClock.mTimeInNs = parcel.readLong();
gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
gpsClock.mFullBiasInNs = parcel.readLong();
@@ -431,7 +366,7 @@ public final class GnssClock implements Parcelable {
gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
gpsClock.mDriftInNsPerSec = parcel.readDouble();
gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
- gpsClock.mTimeOfLastHwClockDiscontinuityInNs = parcel.readLong();
+ gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
return gpsClock;
}
@@ -442,10 +377,10 @@ public final class GnssClock implements Parcelable {
}
};
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
parcel.writeInt(mLeapSecond);
- parcel.writeByte(mType);
parcel.writeLong(mTimeInNs);
parcel.writeDouble(mTimeUncertaintyInNs);
parcel.writeLong(mFullBiasInNs);
@@ -453,7 +388,7 @@ public final class GnssClock implements Parcelable {
parcel.writeDouble(mBiasUncertaintyInNs);
parcel.writeDouble(mDriftInNsPerSec);
parcel.writeDouble(mDriftUncertaintyInNsPerSec);
- parcel.writeLong(mTimeOfLastHwClockDiscontinuityInNs);
+ parcel.writeInt(mHardwareClockDiscontinuityCount);
}
@Override
@@ -467,8 +402,6 @@ public final class GnssClock implements Parcelable {
final String formatWithUncertainty = " %-15s = %-25s %-26s = %s\n";
StringBuilder builder = new StringBuilder("GnssClock:\n");
- builder.append(String.format(format, "Type", getTypeString()));
-
builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
builder.append(String.format(
@@ -497,17 +430,12 @@ public final class GnssClock implements Parcelable {
"DriftUncertaintyInNsPerSec",
hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
- builder.append(String.format(format, "TimeOfLastHwClockDiscontinuityInNs",
- getType() == CLOCK_TYPE_LOCAL_HW_TIME
- ? mTimeOfLastHwClockDiscontinuityInNs : null));
-
return builder.toString();
}
private void initialize() {
mFlags = HAS_NO_FLAGS;
resetLeapSecond();
- setType(CLOCK_TYPE_UNKNOWN);
setTimeInNs(Long.MIN_VALUE);
resetTimeUncertaintyInNs();
resetFullBiasInNs();
@@ -515,7 +443,7 @@ public final class GnssClock implements Parcelable {
resetBiasUncertaintyInNs();
resetDriftInNsPerSec();
resetDriftUncertaintyInNsPerSec();
- setTimeOfLastHwClockDiscontinuityInNs(Long.MIN_VALUE);
+ setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
}
private void setFlag(short flag) {
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index d8f507c9b70e..abdc13c1dfb7 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -24,15 +24,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * A class representing a GPS satellite measurement, containing raw and computed information.
+ * A class representing a GNSS satellite measurement, containing raw and computed information.
*/
public final class GnssMeasurement implements Parcelable {
private int mFlags;
- private byte mPrn;
+ private short mSvid;
+ private byte mConstellationType;
private double mTimeOffsetInNs;
private short mState;
- private long mReceivedGpsTowInNs;
- private long mReceivedGpsTowUncertaintyInNs;
+ private long mReceivedSvTimeInNs;
+ private long mReceivedSvTimeUncertaintyInNs;
private double mCn0InDbHz;
private double mPseudorangeRateInMetersPerSec;
private double mPseudorangeRateUncertaintyInMetersPerSec;
@@ -59,8 +60,6 @@ public final class GnssMeasurement implements Parcelable {
private double mAzimuthInDeg;
private double mAzimuthUncertaintyInDeg;
private boolean mUsedInFix;
- private double mPseudorangeRateCarrierInMetersPerSec;
- private double mPseudorangeRateCarrierUncertaintyInMetersPerSec;
// The following enumerations must be in sync with the values declared in gps.h
@@ -82,8 +81,8 @@ public final class GnssMeasurement implements Parcelable {
private static final int HAS_TIME_FROM_LAST_BIT = (1<<14);
private static final int HAS_DOPPLER_SHIFT = (1<<15);
private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16);
- private static final int HAS_USED_IN_FIX = (1<<17);
- private static final int GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
+ // private static final int HAS_USED_IN_FIX = (1<<17);
+ private static final int HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
/** The status of 'loss of lock'. */
@Retention(RetentionPolicy.SOURCE)
@@ -127,37 +126,37 @@ public final class GnssMeasurement implements Parcelable {
public static final byte MULTIPATH_INDICATOR_NOT_USED = 2;
/**
- * The state of GPS receiver the measurement is invalid or unknown.
+ * The state of GNSS receiver the measurement is invalid or unknown.
*/
public static final short STATE_UNKNOWN = 0;
/**
- * The state of the GPS receiver is ranging code lock.
+ * The state of the GNSS receiver is ranging code lock.
*/
public static final short STATE_CODE_LOCK = (1<<0);
/**
- * The state of the GPS receiver is in bit sync.
+ * The state of the GNSS receiver is in bit sync.
*/
public static final short STATE_BIT_SYNC = (1<<1);
/**
- *The state of the GPS receiver is in sub-frame sync.
+ *The state of the GNSS receiver is in sub-frame sync.
*/
public static final short STATE_SUBFRAME_SYNC = (1<<2);
/**
- * The state of the GPS receiver has TOW decoded.
+ * The state of the GNSS receiver has TOW decoded.
*/
public static final short STATE_TOW_DECODED = (1<<3);
/**
- * The state of the GPS receiver contains millisecond ambiguity.
+ * The state of the GNSS receiver contains millisecond ambiguity.
*/
public static final short STATE_MSEC_AMBIGUOUS = (1<<4);
/**
- * All the GPS receiver state flags.
+ * All the GNSS receiver state flags.
*/
private static final short STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
| STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS;
@@ -198,11 +197,12 @@ public final class GnssMeasurement implements Parcelable {
*/
public void set(GnssMeasurement measurement) {
mFlags = measurement.mFlags;
- mPrn = measurement.mPrn;
+ mSvid = measurement.mSvid;
+ mConstellationType = measurement.mConstellationType;
mTimeOffsetInNs = measurement.mTimeOffsetInNs;
mState = measurement.mState;
- mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs;
- mReceivedGpsTowUncertaintyInNs = measurement.mReceivedGpsTowUncertaintyInNs;
+ mReceivedSvTimeInNs = measurement.mReceivedSvTimeInNs;
+ mReceivedSvTimeUncertaintyInNs = measurement.mReceivedSvTimeUncertaintyInNs;
mCn0InDbHz = measurement.mCn0InDbHz;
mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
mPseudorangeRateUncertaintyInMetersPerSec =
@@ -231,10 +231,6 @@ public final class GnssMeasurement implements Parcelable {
mAzimuthInDeg = measurement.mAzimuthInDeg;
mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
mUsedInFix = measurement.mUsedInFix;
- mPseudorangeRateCarrierInMetersPerSec =
- measurement.mPseudorangeRateCarrierInMetersPerSec;
- mPseudorangeRateCarrierUncertaintyInMetersPerSec =
- measurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec;
}
/**
@@ -248,21 +244,37 @@ public final class GnssMeasurement implements Parcelable {
* Gets the Pseudo-random number (PRN).
* Range: [1, 32]
*/
- public byte getPrn() {
- return mPrn;
+ public short getSvid() {
+ return mSvid;
}
/**
* Sets the Pseud-random number (PRN).
*/
- public void setPrn(byte value) {
- mPrn = value;
+ public void setSvid(short value) {
+ mSvid = value;
+ }
+
+ /**
+ * Getst the constellation type.
+ */
+ @GnssStatus.ConstellationType
+ public byte getConstellationType() {
+ return mConstellationType;
+ }
+
+ /**
+ * Sets the constellation type.
+ */
+ public void setConstellationType(@GnssStatus.ConstellationType byte value) {
+ mConstellationType = value;
}
/**
* Gets the time offset at which the measurement was taken in nanoseconds.
- * The reference receiver's time is specified by {@link GnssClock#getTimeInNs()} and should be
- * interpreted in the same way as indicated by {@link GnssClock#getType()}.
+ *
+ * The reference receiver's time from which this is offset is specified by
+ * {@link GnssClock#getTimeInNs()}.
*
* The sign of this value is given by the following equation:
* measurement time = time_ns + time_offset_ns
@@ -285,7 +297,7 @@ public final class GnssMeasurement implements Parcelable {
* Gets per-satellite sync state.
* It represents the current sync state for the associated satellite.
*
- * This value helps interpret {@link #getReceivedGpsTowInNs()}.
+ * This value helps interpret {@link #getReceivedSvTimeInNs()}.
*/
public short getState() {
return mState;
@@ -333,39 +345,92 @@ public final class GnssMeasurement implements Parcelable {
}
/**
- * Gets the received GPS Time-of-Week at the measurement time, in nanoseconds.
- * The value is relative to the beginning of the current GPS week.
+ * Gets the received GNSS satellite time, at the measurement time, in nanoseconds.
+ *
+ * For GPS &amp; QZSS, this is:
+ * Received GPS Time-of-Week at the measurement time, in nanoseconds.
+ * The value is relative to the beginning of the current GPS week.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range
+ * for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set
+ * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC is set
+ * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED is set
+ *
+ * Note well: if there is any ambiguity in integer millisecond,
+ * STATE_MSEC_AMBIGUOUS should be set accordingly, in the 'state' field.
+ *
+ * This value must be populated if 'state' != STATE_UNKNOWN.
+ *
+ * For Glonass, this is:
+ * Received Glonass time of day, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC is set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set
+ * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC is set
+ * Time of day : [ 0 1day ] : STATE_GLO_TOD_DECODED is set
+ *
+ * For Beidou, this is:
+ * Received Beidou time of week, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC is set
+ * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC is set
+ * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC is set
+ * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC is set
+ * Time of week : [ 0 1week ] : STATE_TOW_DECODED is set
+ *
+ * For Galileo, this is:
+ * Received Galileo time of week, at the measurement time in nanoseconds.
+ *
+ * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK is set
+ * E1C 2nd code lock : [ 0 100ms ] : STATE_GAL_E1C_2ND_CODE_LOCK is set
+ *
+ * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC is set
+ * Time of week : [ 0 1week ] : STATE_GAL_TOW_DECODED is set
*
- * Given {@link #getState()} of the GPS receiver, the range of this field can be:
- * Searching : [ 0 ] : {@link #STATE_UNKNOWN} is set
- * Ranging code lock : [ 0 1 ms ] : {@link #STATE_CODE_LOCK} is set
- * Bit sync : [ 0 20 ms ] : {@link #STATE_BIT_SYNC} is set
- * Subframe sync : [ 0 6 ms ] : {@link #STATE_SUBFRAME_SYNC} is set
- * TOW decoded : [ 0 1 week ] : {@link #STATE_TOW_DECODED} is set
+ * For SBAS, this is:
+ * Received SBAS time, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set
+ * Message : [ 0 1s ] : STATE_SBAS_SYNC is set
*/
- public long getReceivedGpsTowInNs() {
- return mReceivedGpsTowInNs;
+ public long getReceivedSvTimeInNs() {
+ return mReceivedSvTimeInNs;
}
/**
- * Sets the received GPS time-of-week in nanoseconds.
+ * Sets the received GNSS time in nanoseconds.
*/
- public void setReceivedGpsTowInNs(long value) {
- mReceivedGpsTowInNs = value;
+ public void setReceivedSvTimeInNs(long value) {
+ mReceivedSvTimeInNs = value;
}
/**
- * Gets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds.
+ * Gets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
*/
- public long getReceivedGpsTowUncertaintyInNs() {
- return mReceivedGpsTowUncertaintyInNs;
+ public long getReceivedSvTimeUncertaintyInNs() {
+ return mReceivedSvTimeUncertaintyInNs;
}
/**
- * Sets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds.
+ * Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
*/
- public void setReceivedGpsTowUncertaintyInNs(long value) {
- mReceivedGpsTowUncertaintyInNs = value;
+ public void setReceivedSvTimeUncertaintyInNs(long value) {
+ mReceivedSvTimeUncertaintyInNs = value;
}
/**
@@ -416,7 +481,7 @@ public final class GnssMeasurement implements Parcelable {
* value, {@code false} if it contains an uncorrected value.
*/
public boolean isPseudorangeRateCorrected() {
- return !isFlagSet(GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE);
+ return !isFlagSet(HAS_UNCORRECTED_PSEUDORANGE_RATE);
}
/**
@@ -1160,7 +1225,7 @@ public final class GnssMeasurement implements Parcelable {
}
/**
- * Gets a flag indicating whether the GPS represented by the measurement was used for computing
+ * Gets a flag indicating whether the GNSS represented by the measurement was used for computing
* the most recent fix.
*
* @return A non-null value if the data is available, null otherwise.
@@ -1176,45 +1241,18 @@ public final class GnssMeasurement implements Parcelable {
mUsedInFix = value;
}
- /**
- * Gets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
- */
- public double getPseudorangeRateCarrierInMetersPerSec() {
- return mPseudorangeRateCarrierInMetersPerSec;
- }
-
- /**
- * Sets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
- */
- public void setPseudorangeRateCarrierInMetersPerSec(double value) {
- mPseudorangeRateCarrierInMetersPerSec = value;
- }
-
- /**
- * Gets 1-Sigma uncertainty of the pseudorange rate carrier.
- */
- public double getPseudorangeRateCarrierUncertaintyInMetersPerSec() {
- return mPseudorangeRateCarrierUncertaintyInMetersPerSec;
- }
-
- /**
- * Sets 1-Sigma uncertainty of the pseudorange rate carrier.
- */
- public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double value) {
- mPseudorangeRateCarrierUncertaintyInMetersPerSec = value;
- }
-
public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@Override
public GnssMeasurement createFromParcel(Parcel parcel) {
GnssMeasurement gnssMeasurement = new GnssMeasurement();
gnssMeasurement.mFlags = parcel.readInt();
- gnssMeasurement.mPrn = parcel.readByte();
+ gnssMeasurement.mSvid = (short) parcel.readInt();
+ gnssMeasurement.mConstellationType = parcel.readByte();
gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
gnssMeasurement.mState = (short) parcel.readInt();
- gnssMeasurement.mReceivedGpsTowInNs = parcel.readLong();
- gnssMeasurement.mReceivedGpsTowUncertaintyInNs = parcel.readLong();
+ gnssMeasurement.mReceivedSvTimeInNs = parcel.readLong();
+ gnssMeasurement.mReceivedSvTimeUncertaintyInNs = parcel.readLong();
gnssMeasurement.mCn0InDbHz = parcel.readDouble();
gnssMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
gnssMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
@@ -1241,8 +1279,6 @@ public final class GnssMeasurement implements Parcelable {
gnssMeasurement.mAzimuthInDeg = parcel.readDouble();
gnssMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
gnssMeasurement.mUsedInFix = parcel.readInt() != 0;
- gnssMeasurement.mPseudorangeRateCarrierInMetersPerSec = parcel.readDouble();
- gnssMeasurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec = parcel.readDouble();
return gnssMeasurement;
}
@@ -1253,13 +1289,15 @@ public final class GnssMeasurement implements Parcelable {
}
};
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
- parcel.writeByte(mPrn);
+ parcel.writeInt(mSvid);
+ parcel.writeByte(mConstellationType);
parcel.writeDouble(mTimeOffsetInNs);
parcel.writeInt(mState);
- parcel.writeLong(mReceivedGpsTowInNs);
- parcel.writeLong(mReceivedGpsTowUncertaintyInNs);
+ parcel.writeLong(mReceivedSvTimeInNs);
+ parcel.writeLong(mReceivedSvTimeUncertaintyInNs);
parcel.writeDouble(mCn0InDbHz);
parcel.writeDouble(mPseudorangeRateInMetersPerSec);
parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
@@ -1286,8 +1324,6 @@ public final class GnssMeasurement implements Parcelable {
parcel.writeDouble(mAzimuthInDeg);
parcel.writeDouble(mAzimuthUncertaintyInDeg);
parcel.writeInt(mUsedInFix ? 1 : 0);
- parcel.writeDouble(mPseudorangeRateCarrierInMetersPerSec);
- parcel.writeDouble(mPseudorangeRateCarrierUncertaintyInMetersPerSec);
}
@Override
@@ -1301,18 +1337,18 @@ public final class GnssMeasurement implements Parcelable {
final String formatWithUncertainty = " %-29s = %-25s %-40s = %s\n";
StringBuilder builder = new StringBuilder("GnssMeasurement:\n");
- builder.append(String.format(format, "Prn", mPrn));
-
+ builder.append(String.format(format, "Svid", mSvid));
+ builder.append(String.format(format, "ConstellationType", mConstellationType));
builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
builder.append(String.format(format, "State", getStateString()));
builder.append(String.format(
formatWithUncertainty,
- "ReceivedGpsTowInNs",
- mReceivedGpsTowInNs,
- "ReceivedGpsTowUncertaintyInNs",
- mReceivedGpsTowUncertaintyInNs));
+ "ReceivedSvTimeInNs",
+ mReceivedSvTimeInNs,
+ "ReceivedSvTimeUncertaintyInNs",
+ mReceivedSvTimeUncertaintyInNs));
builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
@@ -1412,21 +1448,16 @@ public final class GnssMeasurement implements Parcelable {
builder.append(String.format(format, "UsedInFix", mUsedInFix));
- builder.append(String.format(format, "PseudorangeRateCarrierInMetersPerSec",
- mPseudorangeRateCarrierInMetersPerSec));
- builder.append(String.format(format, "PseudorangeRateCarrierUncertaintyInMetersPerSec",
- mPseudorangeRateCarrierUncertaintyInMetersPerSec));
-
return builder.toString();
}
private void initialize() {
mFlags = HAS_NO_FLAGS;
- setPrn(Byte.MIN_VALUE);
+ setSvid((short) 0);
setTimeOffsetInNs(Long.MIN_VALUE);
setState(STATE_UNKNOWN);
- setReceivedGpsTowInNs(Long.MIN_VALUE);
- setReceivedGpsTowUncertaintyInNs(Long.MAX_VALUE);
+ setReceivedSvTimeInNs(Long.MIN_VALUE);
+ setReceivedSvTimeUncertaintyInNs(Long.MAX_VALUE);
setCn0InDbHz(Double.MIN_VALUE);
setPseudorangeRateInMetersPerSec(Double.MIN_VALUE);
setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE);
@@ -1453,8 +1484,6 @@ public final class GnssMeasurement implements Parcelable {
resetAzimuthInDeg();
resetAzimuthUncertaintyInDeg();
setUsedInFix(false);
- setPseudorangeRateCarrierInMetersPerSec(Double.MIN_VALUE);
- setPseudorangeRateCarrierUncertaintyInMetersPerSec(Double.MIN_VALUE);
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index 0e011d5c98a8..faefd0bbe543 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
import java.security.InvalidParameterException;
/**
- * A class containing a GPS satellite Navigation Message.
+ * A class containing a GNSS satellite Navigation Message.
*/
public final class GnssNavigationMessage implements Parcelable {
@@ -34,36 +34,33 @@ public final class GnssNavigationMessage implements Parcelable {
/** The type of the GPS Clock. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_L1CA, MESSAGE_TYPE_L2CNAV, MESSAGE_TYPE_L5CNAV,
- MESSAGE_TYPE_CNAV2})
+ @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_GPS_L1CA, MESSAGE_TYPE_GPS_L2CNAV,
+ MESSAGE_TYPE_GPS_L5CNAV, MESSAGE_TYPE_GPS_CNAV2, MESSAGE_TYPE_GLO_L1CA, MESSAGE_TYPE_BDS_D1,
+ MESSAGE_TYPE_BDS_D2, MESSAGE_TYPE_GAL_I, MESSAGE_TYPE_GAL_F})
public @interface GnssNavigationMessageType {}
// The following enumerations must be in sync with the values declared in gps.h
- /**
- * The type of the navigation message is not available or unknown.
- */
- public static final byte MESSAGE_TYPE_UNKNOWN = 0;
-
- /**
- * The Navigation Message is of type L1 C/A.
- */
- public static final byte MESSAGE_TYPE_L1CA = 1;
-
- /**
- * The Navigation Message is of type L1-CNAV.
- */
- public static final byte MESSAGE_TYPE_L2CNAV = 2;
-
- /**
- * The Navigation Message is of type L5-CNAV.
- */
- public static final byte MESSAGE_TYPE_L5CNAV = 3;
-
- /**
- * The Navigation Message is of type CNAV-2.
- */
- public static final byte MESSAGE_TYPE_CNAV2 = 4;
+ /** Message type unknown */
+ public static final short MESSAGE_TYPE_UNKNOWN = 0;
+ /** GPS L1 C/A message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_L1CA = 0x0101;
+ /** GPS L2-CNAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_L2CNAV = 0x0102;
+ /** GPS L5-CNAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_L5CNAV = 0x0103;
+ /** GPS CNAV-2 message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_CNAV2 = 0x0104;
+ /** Glonass L1 CA message contained in the structure. */
+ public static final short MESSAGE_TYPE_GLO_L1CA = 0x0301;
+ /** Beidou D1 message contained in the structure. */
+ public static final short MESSAGE_TYPE_BDS_D1 = 0x0501;
+ /** Beidou D2 message contained in the structure. */
+ public static final short MESSAGE_TYPE_BDS_D2 = 0x0502;
+ /** Galileo I/NAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GAL_I = 0x0601;
+ /** Galileo F/NAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GAL_F = 0x0602;
/**
* The Navigation Message Status is 'unknown'.
@@ -83,8 +80,8 @@ public final class GnssNavigationMessage implements Parcelable {
// End enumerations in sync with gps.h
- private byte mType;
- private byte mPrn;
+ private short mType;
+ private short mSvid;
private short mMessageId;
private short mSubmessageId;
private byte[] mData;
@@ -99,7 +96,7 @@ public final class GnssNavigationMessage implements Parcelable {
*/
public void set(GnssNavigationMessage navigationMessage) {
mType = navigationMessage.mType;
- mPrn = navigationMessage.mPrn;
+ mSvid = navigationMessage.mSvid;
mMessageId = navigationMessage.mMessageId;
mSubmessageId = navigationMessage.mSubmessageId;
mData = navigationMessage.mData;
@@ -117,14 +114,14 @@ public final class GnssNavigationMessage implements Parcelable {
* Gets the type of the navigation message contained in the object.
*/
@GnssNavigationMessageType
- public byte getType() {
+ public short getType() {
return mType;
}
/**
* Sets the type of the navigation message.
*/
- public void setType(@GnssNavigationMessageType byte value) {
+ public void setType(@GnssNavigationMessageType short value) {
mType = value;
}
@@ -136,14 +133,24 @@ public final class GnssNavigationMessage implements Parcelable {
switch (mType) {
case MESSAGE_TYPE_UNKNOWN:
return "Unknown";
- case MESSAGE_TYPE_L1CA:
- return "L1 C/A";
- case MESSAGE_TYPE_L2CNAV:
- return "L2-CNAV";
- case MESSAGE_TYPE_L5CNAV:
- return "L5-CNAV";
- case MESSAGE_TYPE_CNAV2:
- return "CNAV-2";
+ case MESSAGE_TYPE_GPS_L1CA:
+ return "GPS L1 C/A";
+ case MESSAGE_TYPE_GPS_L2CNAV:
+ return "GPS L2-CNAV";
+ case MESSAGE_TYPE_GPS_L5CNAV:
+ return "GPS L5-CNAV";
+ case MESSAGE_TYPE_GPS_CNAV2:
+ return "GPS CNAV2";
+ case MESSAGE_TYPE_GLO_L1CA:
+ return "Glonass L1 C/A";
+ case MESSAGE_TYPE_BDS_D1:
+ return "Beidou D1";
+ case MESSAGE_TYPE_BDS_D2:
+ return "Beidou D2";
+ case MESSAGE_TYPE_GAL_I:
+ return "Galileo I";
+ case MESSAGE_TYPE_GAL_F:
+ return "Galileo F";
default:
return "<Invalid:" + mType + ">";
}
@@ -153,15 +160,15 @@ public final class GnssNavigationMessage implements Parcelable {
* Gets the Pseudo-random number.
* Range: [1, 32].
*/
- public byte getPrn() {
- return mPrn;
+ public short getSvid() {
+ return mSvid;
}
/**
* Sets the Pseud-random number.
*/
- public void setPrn(byte value) {
- mPrn = value;
+ public void setSvid(short value) {
+ mSvid = value;
}
/**
@@ -255,8 +262,8 @@ public final class GnssNavigationMessage implements Parcelable {
public GnssNavigationMessage createFromParcel(Parcel parcel) {
GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
- navigationMessage.setType(parcel.readByte());
- navigationMessage.setPrn(parcel.readByte());
+ navigationMessage.setType((short) parcel.readInt());
+ navigationMessage.setSvid((short) parcel.readInt());
navigationMessage.setMessageId((short) parcel.readInt());
navigationMessage.setSubmessageId((short) parcel.readInt());
@@ -281,9 +288,10 @@ public final class GnssNavigationMessage implements Parcelable {
}
};
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeByte(mType);
- parcel.writeByte(mPrn);
+ parcel.writeInt(mType);
+ parcel.writeInt(mSvid);
parcel.writeInt(mMessageId);
parcel.writeInt(mSubmessageId);
parcel.writeInt(mData.length);
@@ -302,7 +310,7 @@ public final class GnssNavigationMessage implements Parcelable {
StringBuilder builder = new StringBuilder("GnssNavigationMessage:\n");
builder.append(String.format(format, "Type", getTypeString()));
- builder.append(String.format(format, "Prn", mPrn));
+ builder.append(String.format(format, "Svid", mSvid));
builder.append(String.format(format, "Status", getStatusString()));
builder.append(String.format(format, "MessageId", mMessageId));
builder.append(String.format(format, "SubmessageId", mSubmessageId));
@@ -321,7 +329,7 @@ public final class GnssNavigationMessage implements Parcelable {
private void initialize() {
mType = MESSAGE_TYPE_UNKNOWN;
- mPrn = 0;
+ mSvid = 0;
mMessageId = -1;
mSubmessageId = -1;
mData = EMPTY_ARRAY;
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 77e8a5bbaca0..06ce30c97887 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -16,25 +16,36 @@
package android.location;
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class represents the current state of the GNSS engine.
* This class is used in conjunction with the {@link GnssStatusCallback}.
*/
public final class GnssStatus {
/** Unknown constellation type. */
- public static final int CONSTELLATION_UNKNOWN = 0;
+ public static final byte CONSTELLATION_UNKNOWN = 0;
/** Constellation type constant for GPS. */
- public static final int CONSTELLATION_GPS = 1;
+ public static final byte CONSTELLATION_GPS = 1;
/** Constellation type constant for SBAS. */
- public static final int CONSTELLATION_SBAS = 2;
+ public static final byte CONSTELLATION_SBAS = 2;
/** Constellation type constant for Glonass. */
- public static final int CONSTELLATION_GLONASS = 3;
+ public static final byte CONSTELLATION_GLONASS = 3;
/** Constellation type constant for QZSS. */
- public static final int CONSTELLATION_QZSS = 4;
+ public static final byte CONSTELLATION_QZSS = 4;
/** Constellation type constant for Beidou. */
- public static final int CONSTELLATION_BEIDOU = 5;
+ public static final byte CONSTELLATION_BEIDOU = 5;
/** Constellation type constant for Galileo. */
- public static final int CONSTELLATION_GALILEO = 6;
+ public static final byte CONSTELLATION_GALILEO = 6;
+
+ /** Constellation type. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS,
+ CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO})
+ public @interface ConstellationType {}
// these must match the definitions in gps.h
/** @hide */
@@ -47,24 +58,26 @@ public final class GnssStatus {
public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
/** @hide */
- public static final int PRN_SHIFT_WIDTH = 3;
+ public static final int SVID_SHIFT_WIDTH = 7;
+ /** @hide */
+ public static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 3;
+ /** @hide */
+ public static final int CONSTELLATION_TYPE_MASK = 0xf;
/* These package private values are modified by the LocationManager class */
- /* package */ int[] mPrnWithFlags;
+ /* package */ int[] mSvidWithFlags;
/* package */ float[] mSnrs;
/* package */ float[] mElevations;
/* package */ float[] mAzimuths;
- /* package */ int[] mConstellationTypes;
/* package */ int mSvCount;
- GnssStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations, float[] azimuths,
- int[] constellationTypes) {
+ GnssStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+ float[] azimuths) {
mSvCount = svCount;
- mPrnWithFlags = prnWithFlags;
+ mSvidWithFlags = svidWithFlags;
mSnrs = snrs;
mElevations = elevations;
mAzimuths = azimuths;
- mConstellationTypes = constellationTypes;
}
/**
@@ -78,16 +91,18 @@ public final class GnssStatus {
* Retrieves the constellation type of the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public int getConstellationType(int satIndex) {
- return mConstellationTypes[satIndex];
+ @ConstellationType
+ public byte getConstellationType(int satIndex) {
+ return (byte) ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+ & CONSTELLATION_TYPE_MASK);
}
/**
* Retrieves the pseudo-random number of the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public int getPrn(int satIndex) {
- return mPrnWithFlags[satIndex] >> PRN_SHIFT_WIDTH;
+ public int getSvid(int satIndex) {
+ return mSvidWithFlags[satIndex] >> SVID_SHIFT_WIDTH;
}
/**
@@ -119,7 +134,7 @@ public final class GnssStatus {
* @param satIndex the index of the satellite in the list.
*/
public boolean hasEphemeris(int satIndex) {
- return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+ return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
}
/**
@@ -127,7 +142,7 @@ public final class GnssStatus {
* @param satIndex the index of the satellite in the list.
*/
public boolean hasAlmanac(int satIndex) {
- return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+ return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
}
/**
@@ -135,6 +150,6 @@ public final class GnssStatus {
* @param satIndex the index of the satellite in the list.
*/
public boolean usedInFix(int satIndex) {
- return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+ return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
}
}
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 8d2f781e497f..7b3dd7de081f 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -138,15 +138,18 @@ public final class GpsStatus {
// For API-compat a public ctor() is not available
GpsStatus() {}
- private void setStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations,
- float[] azimuths, int[] constellationTypes) {
+ private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+ float[] azimuths) {
clearSatellites();
for (int i = 0; i < svCount; i++) {
+ final int constellationType =
+ (svidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
+ & GnssStatus.CONSTELLATION_TYPE_MASK;
// Skip all non-GPS satellites.
- if (constellationTypes[i] != GnssStatus.CONSTELLATION_GPS) {
+ if (constellationType != GnssStatus.CONSTELLATION_GPS) {
continue;
}
- int prn = prnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH;
+ int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
if (prn > 0 && prn <= NUM_SATELLITES) {
GpsSatellite satellite = mSatellites.get(prn);
if (satellite == null) {
@@ -159,11 +162,11 @@ public final class GpsStatus {
satellite.mElevation = elevations[i];
satellite.mAzimuth = azimuths[i];
satellite.mHasEphemeris =
- (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+ (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
satellite.mHasAlmanac =
- (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+ (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
satellite.mUsedInFix =
- (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+ (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
}
}
}
@@ -176,8 +179,8 @@ public final class GpsStatus {
*/
void setStatus(GnssStatus status, int timeToFirstFix) {
mTimeToFirstFix = timeToFirstFix;
- setStatus(status.mSvCount, status.mPrnWithFlags, status.mSnrs, status.mElevations,
- status.mAzimuths, status.mConstellationTypes);
+ setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
+ status.mAzimuths);
}
void setTimeToFirstFix(int ttff) {
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index d1c6a85a9fdd..8c7d06eee5e6 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -26,7 +26,7 @@ oneway interface IGnssStatusListener
void onGnssStarted();
void onGnssStopped();
void onFirstFix(int ttff);
- void onSvStatusChanged(int svCount, in int[] prnWithFlags, in float[] snrs,
- in float[] elevations, in float[] azimuths, in int[] constellationTypes);
+ void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] snrs,
+ in float[] elevations, in float[] azimuths);
void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 4f1e0397abd0..bc8b026222ed 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -69,7 +69,7 @@ interface ILocationManager
in String packageName);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
- int getGpsYearOfHardware();
+ int getGnssYearOfHardware();
// --- deprecated ---
List<String> getAllProviders();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 30cf101397db..3cd47e73d340 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -307,7 +307,7 @@ public class LocationManager {
try {
mService.locationCallbackFinished(this);
} catch (RemoteException e) {
- Log.e(TAG, "locationCallbackFinished: RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -341,9 +341,8 @@ public class LocationManager {
try {
return mService.getAllProviders();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -357,9 +356,8 @@ public class LocationManager {
try {
return mService.getProviders(null, enabledOnly);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -382,9 +380,8 @@ public class LocationManager {
}
return createProvider(name, properties);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -402,9 +399,8 @@ public class LocationManager {
try {
return mService.getProviders(criteria, enabledOnly);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -434,9 +430,8 @@ public class LocationManager {
try {
return mService.getBestProvider(criteria, enabledOnly);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
- return null;
}
/**
@@ -885,7 +880,7 @@ public class LocationManager {
try {
mService.requestLocationUpdates(request, transport, intent, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -911,7 +906,7 @@ public class LocationManager {
try {
mService.removeUpdates(transport, null, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -930,7 +925,7 @@ public class LocationManager {
try {
mService.removeUpdates(null, intent, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -992,7 +987,7 @@ public class LocationManager {
try {
mService.requestGeofence(request, fence, intent, mContext.getPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1040,7 +1035,7 @@ public class LocationManager {
try {
mService.requestGeofence(request, fence, intent, mContext.getPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1067,7 +1062,7 @@ public class LocationManager {
try {
mService.removeGeofence(null, intent, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1095,7 +1090,7 @@ public class LocationManager {
try {
mService.removeGeofence(fence, intent, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1117,7 +1112,7 @@ public class LocationManager {
try {
mService.removeGeofence(null, intent, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1148,8 +1143,7 @@ public class LocationManager {
try {
return mService.isProviderEnabled(provider);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1173,8 +1167,7 @@ public class LocationManager {
try {
return mService.getLastLocation(null, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1205,8 +1198,7 @@ public class LocationManager {
try {
return mService.getLastLocation(request, packageName);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1237,7 +1229,7 @@ public class LocationManager {
try {
mService.addTestProvider(name, properties, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1255,7 +1247,7 @@ public class LocationManager {
try {
mService.removeTestProvider(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1292,7 +1284,7 @@ public class LocationManager {
try {
mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1310,7 +1302,7 @@ public class LocationManager {
try {
mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1330,7 +1322,7 @@ public class LocationManager {
try {
mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1348,7 +1340,7 @@ public class LocationManager {
try {
mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1371,7 +1363,7 @@ public class LocationManager {
mService.setTestProviderStatus(provider, status, extras, updateTime,
mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1389,7 +1381,7 @@ public class LocationManager {
try {
mService.clearTestProviderStatus(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1562,10 +1554,9 @@ public class LocationManager {
@Override
public void onSvStatusChanged(int svCount, int[] prnWithFlags,
- float[] snrs, float[] elevations, float[] azimuths, int[] constellationTypes) {
+ float[] snrs, float[] elevations, float[] azimuths) {
if (mGnssCallback != null) {
- mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths,
- constellationTypes);
+ mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
@@ -1616,8 +1607,7 @@ public class LocationManager {
mGpsStatusListeners.put(listener, transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
- result = false;
+ throw e.rethrowFromSystemServer();
}
return result;
@@ -1636,7 +1626,7 @@ public class LocationManager {
mService.unregisterGnssStatusCallback(transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1680,8 +1670,7 @@ public class LocationManager {
mGnssStatusListeners.put(callback, transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
- result = false;
+ throw e.rethrowFromSystemServer();
}
return result;
@@ -1699,7 +1688,7 @@ public class LocationManager {
mService.unregisterGnssStatusCallback(transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1729,8 +1718,7 @@ public class LocationManager {
mGpsNmeaListeners.put(listener, transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
- result = false;
+ throw e.rethrowFromSystemServer();
}
return result;
@@ -1749,7 +1737,7 @@ public class LocationManager {
mService.unregisterGnssStatusCallback(transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1793,8 +1781,7 @@ public class LocationManager {
mGnssNmeaListeners.put(listener, transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
- result = false;
+ throw e.rethrowFromSystemServer();
}
return result;
@@ -1812,7 +1799,7 @@ public class LocationManager {
mService.unregisterGnssStatusCallback(transport);
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1960,12 +1947,11 @@ public class LocationManager {
* @hide
*/
@TestApi
- public int getGpsYearOfHardware() {
+ public int getGnssYearOfHardware() {
try {
- return mService.getGpsYearOfHardware();
+ return mService.getGnssYearOfHardware();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getGpsSystemInfo: ", e);
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1984,8 +1970,7 @@ public class LocationManager {
try {
return mService.sendExtraCommand(provider, command, extras);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in sendExtraCommand: ", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1999,8 +1984,7 @@ public class LocationManager {
try {
return mService.sendNiResponse(notifId, userResponse);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in sendNiResponse: ", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 45529efec0d9..9922b7237b74 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -111,6 +111,10 @@ public final class AudioDeviceInfo {
* A device type connected over IP.
*/
public static final int TYPE_IP = 20;
+ /**
+ * A type-agnostic device used for communication with external audio systems
+ */
+ public static final int TYPE_BUS = 21;
private final AudioDevicePort mPort;
@@ -279,6 +283,7 @@ public final class AudioDeviceInfo {
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BUS, TYPE_BUS);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
@@ -296,6 +301,7 @@ public final class AudioDeviceInfo {
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS);
// not covered here, legacy
//AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
@@ -323,6 +329,7 @@ public final class AudioDeviceInfo {
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_OUT_IP);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_OUT_BUS);
}
}
diff --git a/media/java/android/media/AudioFormat.aidl b/media/java/android/media/AudioFormat.aidl
new file mode 100644
index 000000000000..8613f550e3c8
--- /dev/null
+++ b/media/java/android/media/AudioFormat.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable AudioFormat;
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 000a56d186b5..b0411a2b63f5 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -18,10 +18,13 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
/**
* The {@link AudioFormat} class is used to access a number of audio format and
@@ -209,7 +212,7 @@ import java.util.Arrays;
* AudioTrack.getPlaybackHeadPosition()}),
* depending on the context where audio frame is used.
*/
-public class AudioFormat {
+public class AudioFormat implements Parcelable {
//---------------------------------------------------------
// Constants
@@ -332,6 +335,24 @@ public class AudioFormat {
CHANNEL_OUT_LOW_FREQUENCY);
// CHANNEL_OUT_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_OUT_ALL
+ /** Minimum value for sample rate,
+ * assuming AudioTrack and AudioRecord share the same limitations.
+ * @hide
+ */
+ // never unhide
+ public static final int SAMPLE_RATE_HZ_MIN = 4000;
+ /** Maximum value for sample rate,
+ * assuming AudioTrack and AudioRecord share the same limitations.
+ * @hide
+ */
+ // never unhide
+ public static final int SAMPLE_RATE_HZ_MAX = 192000;
+ /** Sample rate will be a route-dependent value.
+ * For AudioTrack, it is usually the sink sample rate,
+ * and for AudioRecord it is usually the source sample rate.
+ */
+ public static final int SAMPLE_RATE_UNSPECIFIED = 0;
+
/**
* @hide
* Return the input channel mask corresponding to an output channel mask.
@@ -558,7 +579,7 @@ public class AudioFormat {
}
/**
- * Constructor used by the JNI
+ * Constructor used by the JNI. Parameters are not checked for validity.
*/
// Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this
// constructor
@@ -607,12 +628,9 @@ public class AudioFormat {
/**
* Return the sample rate.
* @return one of the values that can be set in {@link Builder#setSampleRate(int)} or
- * 0 if not set.
+ * {@link #SAMPLE_RATE_UNSPECIFIED} if not set.
*/
public int getSampleRate() {
- if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) == 0) {
- return 0;
- }
return mSampleRate;
}
@@ -684,7 +702,7 @@ public class AudioFormat {
*/
public static class Builder {
private int mEncoding = ENCODING_INVALID;
- private int mSampleRate = 0;
+ private int mSampleRate = SAMPLE_RATE_UNSPECIFIED;
private int mChannelMask = CHANNEL_INVALID;
private int mChannelIndexMask = 0;
private int mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_NONE;
@@ -715,6 +733,8 @@ public class AudioFormat {
public AudioFormat build() {
AudioFormat af = new AudioFormat(1980/*ignored*/);
af.mEncoding = mEncoding;
+ // not calling setSampleRate is equivalent to calling
+ // setSampleRate(SAMPLE_RATE_UNSPECIFIED)
af.mSampleRate = mSampleRate;
af.mChannelMask = mChannelMask;
af.mChannelIndexMask = mChannelIndexMask;
@@ -792,7 +812,7 @@ public class AudioFormat {
* are specified but do not have the same channel count.
*/
public @NonNull Builder setChannelMask(int channelMask) {
- if (channelMask == 0) {
+ if (channelMask == CHANNEL_INVALID) {
throw new IllegalArgumentException("Invalid zero channel mask");
} else if (/* channelMask != 0 && */ mChannelIndexMask != 0 &&
Integer.bitCount(channelMask) != Integer.bitCount(mChannelIndexMask)) {
@@ -864,7 +884,11 @@ public class AudioFormat {
* @throws java.lang.IllegalArgumentException
*/
public Builder setSampleRate(int sampleRate) throws IllegalArgumentException {
- if ((sampleRate <= 0) || (sampleRate > 192000)) {
+ // TODO Consider whether to keep the MIN and MAX range checks here.
+ // It is not necessary and poses the problem of defining the limits independently from
+ // native implementation or platform capabilities.
+ if (((sampleRate < SAMPLE_RATE_HZ_MIN) || (sampleRate > SAMPLE_RATE_HZ_MAX)) &&
+ sampleRate != SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException("Invalid sample rate " + sampleRate);
}
mSampleRate = sampleRate;
@@ -874,6 +898,64 @@ public class AudioFormat {
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ AudioFormat that = (AudioFormat) o;
+
+ if (mPropertySetMask != that.mPropertySetMask) return false;
+
+ // return false if any of the properties is set and the values differ
+ return !((((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
+ && (mEncoding != that.mEncoding))
+ || (((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
+ && (mSampleRate != that.mSampleRate))
+ || (((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0)
+ && (mChannelMask != that.mChannelMask))
+ || (((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0)
+ && (mChannelIndexMask != that.mChannelIndexMask)));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPropertySetMask, mSampleRate, mEncoding, mChannelMask,
+ mChannelIndexMask);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPropertySetMask);
+ dest.writeInt(mEncoding);
+ dest.writeInt(mSampleRate);
+ dest.writeInt(mChannelMask);
+ dest.writeInt(mChannelIndexMask);
+ }
+
+ private AudioFormat(Parcel in) {
+ mPropertySetMask = in.readInt();
+ mEncoding = in.readInt();
+ mSampleRate = in.readInt();
+ mChannelMask = in.readInt();
+ mChannelIndexMask = in.readInt();
+ }
+
+ public static final Parcelable.Creator<AudioFormat> CREATOR =
+ new Parcelable.Creator<AudioFormat>() {
+ public AudioFormat createFromParcel(Parcel p) {
+ return new AudioFormat(p);
+ }
+ public AudioFormat[] newArray(int size) {
+ return new AudioFormat[size];
+ }
+ };
+
+ @Override
public String toString () {
return new String("AudioFormat:"
+ " props=" + mPropertySetMask
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index dc534be03cbb..c7e96cf664bb 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -177,16 +177,6 @@ public class AudioManager {
"android.media.MASTER_MUTE_CHANGED_ACTION";
/**
- * @hide Broadcast intent when the master mono state changes.
- * Includes the new mono state
- *
- * @see #EXTRA_MASTER_MONO
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String MASTER_MONO_CHANGED_ACTION =
- "android.media.MASTER_MONO_CHANGED_ACTION";
-
- /**
* The new vibrate setting for a particular type.
*
* @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -265,13 +255,6 @@ public class AudioManager {
"android.media.EXTRA_STREAM_VOLUME_MUTED";
/**
- * @hide The new master mono state for the master mono changed intent.
- * Value is boolean
- */
- public static final String EXTRA_MASTER_MONO =
- "android.media.EXTRA_MASTER_MONO";
-
- /**
* Broadcast Action: Wired Headset plugged in or unplugged.
*
* You <em>cannot</em> receive this through components declared
@@ -826,7 +809,7 @@ public class AudioManager {
service.adjustStreamVolume(streamType, direction, flags,
getContext().getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in adjustStreamVolume", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -894,18 +877,7 @@ public class AudioManager {
service.setMasterMute(mute, flags, getContext().getOpPackageName(),
UserHandle.getCallingUserId());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setMasterMute", e);
- }
- }
-
- /** @hide */
- public void setMasterMono(boolean mono) {
- IAudioService service = getService();
- try {
- service.setMasterMono(mono, getContext().getOpPackageName(),
- UserHandle.getCallingUserId());
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setMasterMono", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -921,8 +893,7 @@ public class AudioManager {
try {
return service.getRingerModeExternal();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getRingerMode", e);
- return RINGER_MODE_NORMAL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -942,8 +913,7 @@ public class AudioManager {
try {
return service.isValidRingerMode(ringerMode);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in isValidRingerMode", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -959,8 +929,7 @@ public class AudioManager {
try {
return service.getStreamMaxVolume(streamType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getStreamMaxVolume", e);
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -977,8 +946,7 @@ public class AudioManager {
try {
return service.getStreamMinVolume(streamType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getStreamMinVolume", e);
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -995,8 +963,7 @@ public class AudioManager {
try {
return service.getStreamVolume(streamType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getStreamVolume", e);
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1010,8 +977,7 @@ public class AudioManager {
try {
return service.getLastAudibleStreamVolume(streamType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
- return 0;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1026,8 +992,7 @@ public class AudioManager {
try {
return service.getUiSoundsStreamType();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getUiSoundsStreamType", e);
- return STREAM_RING;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1052,7 +1017,7 @@ public class AudioManager {
try {
service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setRingerMode", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1073,7 +1038,7 @@ public class AudioManager {
try {
service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setStreamVolume", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1150,8 +1115,7 @@ public class AudioManager {
try {
return service.isStreamMute(streamType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in isStreamMute", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1165,23 +1129,7 @@ public class AudioManager {
try {
return service.isMasterMute();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in isMasterMute", e);
- return false;
- }
- }
-
- /**
- * get master mono state.
- *
- * @hide
- */
- public boolean isMasterMono() {
- IAudioService service = getService();
- try {
- return service.isMasterMono();
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in isMasterMono", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1197,7 +1145,7 @@ public class AudioManager {
try {
service.forceVolumeControlStream(streamType, mICallBack);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in forceVolumeControlStream", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1225,8 +1173,7 @@ public class AudioManager {
try {
return service.shouldVibrate(vibrateType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in shouldVibrate", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1252,8 +1199,7 @@ public class AudioManager {
try {
return service.getVibrateSetting(vibrateType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getVibrateSetting", e);
- return VIBRATE_SETTING_OFF;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1280,7 +1226,7 @@ public class AudioManager {
try {
service.setVibrateSetting(vibrateType, vibrateSetting);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setVibrateSetting", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1298,7 +1244,7 @@ public class AudioManager {
try {
service.setSpeakerphoneOn(on);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setSpeakerphoneOn", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1312,8 +1258,7 @@ public class AudioManager {
try {
return service.isSpeakerphoneOn();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in isSpeakerphoneOn", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1454,7 +1399,7 @@ public class AudioManager {
service.startBluetoothSco(mICallBack,
getContext().getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in startBluetoothSco", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1478,7 +1423,7 @@ public class AudioManager {
try {
service.startBluetoothScoVirtualCall(mICallBack);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in startBluetoothScoVirtualCall", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1497,7 +1442,7 @@ public class AudioManager {
try {
service.stopBluetoothSco(mICallBack);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in stopBluetoothSco", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1515,7 +1460,7 @@ public class AudioManager {
try {
service.setBluetoothScoOn(on);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setBluetoothScoOn", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1530,8 +1475,7 @@ public class AudioManager {
try {
return service.isBluetoothScoOn();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in isBluetoothScoOn", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1603,7 +1547,7 @@ public class AudioManager {
service.setMicrophoneMute(on, getContext().getOpPackageName(),
UserHandle.getCallingUserId());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setMicrophoneMute", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1636,7 +1580,7 @@ public class AudioManager {
try {
service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setMode", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1652,8 +1596,7 @@ public class AudioManager {
try {
return service.getMode();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in getMode", e);
- return MODE_INVALID;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1790,8 +1733,7 @@ public class AudioManager {
try {
return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in isAudioFocusExclusive()", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -1957,7 +1899,7 @@ public class AudioManager {
try {
service.playSoundEffect(effectType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in playSoundEffect"+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -1992,7 +1934,7 @@ public class AudioManager {
try {
service.playSoundEffect(effectType);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in playSoundEffect"+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2024,7 +1966,7 @@ public class AudioManager {
try {
service.playSoundEffectVolume(effectType, volume);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in playSoundEffect"+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2046,7 +1988,7 @@ public class AudioManager {
try {
service.loadSoundEffects();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in loadSoundEffects"+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2060,7 +2002,7 @@ public class AudioManager {
try {
service.unloadSoundEffects();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in unloadSoundEffects"+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2471,7 +2413,7 @@ public class AudioManager {
getContext().getOpPackageName() /* package name */, flags,
ap != null ? ap.cb() : null);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
+ throw e.rethrowFromSystemServer();
}
return status;
}
@@ -2497,7 +2439,7 @@ public class AudioManager {
AUDIOFOCUS_FLAG_LOCK,
null /* policy token */);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService:", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2513,7 +2455,7 @@ public class AudioManager {
service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
null /*AudioAttributes, legacy behavior*/);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2542,7 +2484,7 @@ public class AudioManager {
status = service.abandonAudioFocus(mAudioFocusDispatcher,
getIdForAudioFocusListener(l), aa);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call abandonAudioFocus() on AudioService:", e);
+ throw e.rethrowFromSystemServer();
}
return status;
}
@@ -2756,8 +2698,7 @@ public class AudioManager {
}
// successful registration
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerAudioPolicyAsync()", e);
- return ERROR;
+ throw e.rethrowFromSystemServer();
}
return SUCCESS;
}
@@ -2776,7 +2717,7 @@ public class AudioManager {
service.unregisterAudioPolicyAsync(policy.cb());
policy.setRegistration(null);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in unregisterAudioPolicyAsync()", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2836,7 +2777,7 @@ public class AudioManager {
try {
service.registerRecordingCallback(mRecCb);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerRecordingCallback", e);
+ throw e.rethrowFromSystemServer();
}
}
} else {
@@ -2868,7 +2809,7 @@ public class AudioManager {
try {
service.unregisterRecordingCallback(mRecCb);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in unregisterRecordingCallback", e);
+ throw e.rethrowFromSystemServer();
}
}
} else {
@@ -2888,8 +2829,7 @@ public class AudioManager {
try {
return service.getActiveRecordConfigurations();
} catch (RemoteException e) {
- Log.e(TAG, "Unable to retrieve active record configurations", e);
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -2972,7 +2912,7 @@ public class AudioManager {
try {
service.reloadAudioSettings();
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in reloadAudioSettings"+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2987,7 +2927,7 @@ public class AudioManager {
try {
service.avrcpSupportsAbsoluteVolume(address, support);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in avrcpSupportsAbsoluteVolume", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3281,7 +3221,7 @@ public class AudioManager {
service.setWiredDeviceConnectionState(type, state, address, name,
mApplicationContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3303,7 +3243,7 @@ public class AudioManager {
try {
delay = service.setBluetoothA2dpDeviceConnectionState(device, state, profile);
} catch (RemoteException e) {
- Log.e(TAG, "Dead object in setBluetoothA2dpDeviceConnectionState "+e);
+ throw e.rethrowFromSystemServer();
}
return delay;
}
@@ -3313,7 +3253,7 @@ public class AudioManager {
try {
return getService().getRingtonePlayer();
} catch (RemoteException e) {
- return null;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3321,6 +3261,7 @@ public class AudioManager {
* Used as a key for {@link #getProperty} to request the native or optimal output sample rate
* for this device's primary output stream, in decimal Hz.
*/
+ // FIXME Deprecate
public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
"android.media.property.OUTPUT_SAMPLE_RATE";
@@ -3328,6 +3269,7 @@ public class AudioManager {
* Used as a key for {@link #getProperty} to request the native or optimal output buffer size
* for this device's primary output stream, in decimal PCM frames.
*/
+ // FIXME Deprecate
public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
"android.media.property.OUTPUT_FRAMES_PER_BUFFER";
@@ -3406,7 +3348,7 @@ public class AudioManager {
try {
getService().setVolumeController(controller);
} catch (RemoteException e) {
- Log.w(TAG, "Error setting volume controller", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3420,7 +3362,7 @@ public class AudioManager {
try {
getService().notifyVolumeControllerVisible(controller, visible);
} catch (RemoteException e) {
- Log.w(TAG, "Error notifying about volume controller visibility", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3432,8 +3374,7 @@ public class AudioManager {
try {
return getService().isStreamAffectedByRingerMode(streamType);
} catch (RemoteException e) {
- Log.w(TAG, "Error calling isStreamAffectedByRingerMode", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3445,8 +3386,7 @@ public class AudioManager {
try {
return getService().isStreamAffectedByMute(streamType);
} catch (RemoteException e) {
- Log.w(TAG, "Error calling isStreamAffectedByMute", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3458,7 +3398,7 @@ public class AudioManager {
try {
getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
} catch (RemoteException e) {
- Log.w(TAG, "Error disabling safe media volume", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3470,7 +3410,7 @@ public class AudioManager {
try {
getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
} catch (RemoteException e) {
- Log.w(TAG, "Error calling setRingerModeInternal", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3482,8 +3422,7 @@ public class AudioManager {
try {
return getService().getRingerModeInternal();
} catch (RemoteException e) {
- Log.w(TAG, "Error calling getRingerModeInternal", e);
- return RINGER_MODE_NORMAL;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3495,7 +3434,7 @@ public class AudioManager {
try {
getService().setVolumePolicy(policy);
} catch (RemoteException e) {
- Log.w(TAG, "Error calling setVolumePolicy", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -3510,8 +3449,7 @@ public class AudioManager {
try {
return getService().setHdmiSystemAudioSupported(on);
} catch (RemoteException e) {
- Log.w(TAG, "Error setting system audio mode", e);
- return AudioSystem.DEVICE_NONE;
+ throw e.rethrowFromSystemServer();
}
}
@@ -3525,8 +3463,7 @@ public class AudioManager {
try {
return getService().isHdmiSystemAudioSupported();
} catch (RemoteException e) {
- Log.w(TAG, "Error querying system audio mode", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
}
diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java
index acadb413e429..6c70213ad83a 100644
--- a/media/java/android/media/AudioPatch.java
+++ b/media/java/android/media/AudioPatch.java
@@ -53,6 +53,13 @@ public class AudioPatch {
return mSinks;
}
+ /**
+ * Get the system unique patch ID.
+ */
+ public int id() {
+ return mHandle.id();
+ }
+
@Override
public String toString() {
StringBuilder s = new StringBuilder();
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 800b91497058..b8f0717d7318 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -57,10 +57,6 @@ public class AudioRecord implements AudioRouting
// Constants
//--------------------
- /** Minimum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MIN = 4000;
- /** Maximum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MAX = 192000;
/**
* indicates AudioRecord state is not successfully initialized.
@@ -168,8 +164,9 @@ public class AudioRecord implements AudioRouting
//--------------------
/**
* The audio data sampling rate in Hz.
+ * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
*/
- private int mSampleRate;
+ private int mSampleRate; // initialized by all constructors via audioParamCheck()
/**
* The number of input audio channels (1 is mono, 2 is stereo)
*/
@@ -251,6 +248,9 @@ public class AudioRecord implements AudioRouting
* @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
* rate that is guaranteed to work on all devices, but other rates such as 22050,
* 16000, and 11025 may work on some devices.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+ * which is usually the sample rate of the source.
+ * {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_IN_MONO} and
* {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
@@ -337,16 +337,9 @@ public class AudioRecord implements AudioRouting
mAudioAttributes = attributes;
}
- int rate = 0;
- if ((format.getPropertySetMask()
- & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
- {
- rate = format.getSampleRate();
- } else {
- rate = AudioSystem.getPrimaryOutputSamplingRate();
- if (rate <= 0) {
- rate = 44100;
- }
+ int rate = format.getSampleRate();
+ if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
+ rate = 0;
}
int encoding = AudioFormat.ENCODING_DEFAULT;
@@ -373,19 +366,21 @@ public class AudioRecord implements AudioRouting
audioBuffSizeCheck(bufferSizeInBytes);
+ int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1];
session[0] = sessionId;
//TODO: update native initialization when information about hardware init failure
// due to capture device already open is available.
int initResult = native_setup( new WeakReference<AudioRecord>(this),
- mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
+ mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
mAudioFormat, mNativeBufferSizeInBytes,
- session, ActivityThread.currentOpPackageName());
+ session, ActivityThread.currentOpPackageName(), 0 /*nativeRecordInJavaObj*/);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing native AudioRecord object.");
return; // with mState == STATE_UNINITIALIZED
}
+ mSampleRate = sampleRate[0];
mSessionId = session[0];
mState = STATE_INITIALIZED;
@@ -395,12 +390,32 @@ public class AudioRecord implements AudioRouting
* A constructor which explicitly connects a Native (C++) AudioRecord. For use by
* the AudioRecordRoutingProxy subclass.
* @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
- * (associated with an OpenSL ES recorder).
+ * (associated with an OpenSL ES recorder). Note: the caller must ensure a correct
+ * value here as no error checking is or can be done.
*/
/*package*/ AudioRecord(long nativeRecordInJavaObj) {
- mNativeRecorderInJavaObj = nativeRecordInJavaObj;
+ int[] session = { 0 };
+ int[] rates = { 0 };
+ //TODO: update native initialization when information about hardware init failure
+ // due to capture device already open is available.
+ // Note that for this native_setup, we are providing an already created/initialized
+ // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored.
+ int initResult = native_setup(new WeakReference<AudioRecord>(this),
+ null /*mAudioAttributes*/,
+ rates /*mSampleRates*/,
+ 0 /*mChannelMask*/,
+ 0 /*mChannelIndexMask*/,
+ 0 /*mAudioFormat*/,
+ 0 /*mNativeBufferSizeInBytes*/,
+ session,
+ ActivityThread.currentOpPackageName(),
+ nativeRecordInJavaObj);
+ if (initResult != SUCCESS) {
+ loge("Error code "+initResult+" when initializing native AudioRecord object.");
+ return; // with mState == STATE_UNINITIALIZED
+ }
- // other initialization here...
+ mSessionId = session[0];
mState = STATE_INITIALIZED;
}
@@ -623,6 +638,7 @@ public class AudioRecord implements AudioRouting
return mask;
}
+
// postconditions:
// mRecordSource is valid
// mAudioFormat is valid
@@ -642,7 +658,9 @@ public class AudioRecord implements AudioRouting
//--------------
// sample rate
- if ((sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX)) {
+ if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
+ sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
+ sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate.");
}
@@ -714,7 +732,11 @@ public class AudioRecord implements AudioRouting
// Getters
//--------------------
/**
- * Returns the configured audio data sample rate in Hz
+ * Returns the configured audio sink sample rate in Hz.
+ * The sink sample rate never changes after construction.
+ * If the constructor had a specific sample rate, then the sink sample rate is that value.
+ * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
+ * then the sink sample rate is a route-dependent default value based on the source [sic].
*/
public int getSampleRate() {
return mSampleRate;
@@ -861,6 +883,7 @@ public class AudioRecord implements AudioRouting
* See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
* configuration values.
* @param sampleRateInHz the sample rate expressed in Hertz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_IN_MONO} and
* {@link AudioFormat#CHANNEL_IN_STEREO}
@@ -1014,9 +1037,12 @@ public class AudioRecord implements AudioRouting
* Reads audio data from the audio hardware for recording into a byte array.
* The format specified in the AudioRecord constructor should be
* {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
+ * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated.
* @param audioData the array to which the recorded audio data is written.
- * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
+ * @param offsetInBytes index in audioData to which the data is written expressed in bytes.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInBytes the number of requested bytes.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
* <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
* is read.
@@ -1025,7 +1051,8 @@ public class AudioRecord implements AudioRouting
* @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
- * The number of bytes will not exceed sizeInBytes.
+ * The number of bytes will be a multiple of the frame size in bytes
+ * not to exceed sizeInBytes.
*/
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@ReadMode int readMode) {
@@ -1053,12 +1080,14 @@ public class AudioRecord implements AudioRouting
* The format specified in the AudioRecord constructor should be
* {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
* @param audioData the array to which the recorded audio data is written.
- * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
+ * @param offsetInShorts index in audioData to which the data is written expressed in shorts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInShorts the number of requested shorts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
- * The number of shorts will not exceed sizeInShorts.
+ * The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
*/
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
@@ -1070,7 +1099,9 @@ public class AudioRecord implements AudioRouting
* {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
* @param audioData the array to which the recorded audio data is written.
* @param offsetInShorts index in audioData from which the data is written expressed in shorts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInShorts the number of requested shorts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
* <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
* is read.
@@ -1079,7 +1110,7 @@ public class AudioRecord implements AudioRouting
* @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
- * The number of shorts will not exceed sizeInShorts.
+ * The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
*/
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@ReadMode int readMode) {
@@ -1108,7 +1139,9 @@ public class AudioRecord implements AudioRouting
* {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
* @param audioData the array to which the recorded audio data is written.
* @param offsetInFloats index in audioData from which the data is written.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInFloats the number of requested floats.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
* <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
* is read.
@@ -1117,7 +1150,7 @@ public class AudioRecord implements AudioRouting
* @return the number of floats that were read or {@link #ERROR_INVALID_OPERATION}
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
- * The number of floats will not exceed sizeInFloats.
+ * The number of floats will be a multiple of the channel count not to exceed sizeInFloats.
*/
public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
@ReadMode int readMode) {
@@ -1154,6 +1187,7 @@ public class AudioRecord implements AudioRouting
* The representation of the data in the buffer will depend on the format specified in
* the AudioRecord constructor, and will be native endian.
* @param audioBuffer the direct buffer to which the recorded audio data is written.
+ * Data is written to audioBuffer.position().
* @param sizeInBytes the number of requested bytes. It is recommended but not enforced
* that the number of bytes requested be a multiple of the frame size (sample size in
* bytes multiplied by the channel count).
@@ -1161,7 +1195,7 @@ public class AudioRecord implements AudioRouting
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
* The number of bytes will not exceed sizeInBytes.
- * The number of bytes read will truncated to be a multiple of the frame size.
+ * The number of bytes read will be truncated to be a multiple of the frame size.
*/
public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
return read(audioBuffer, sizeInBytes, READ_BLOCKING);
@@ -1175,6 +1209,7 @@ public class AudioRecord implements AudioRouting
* The representation of the data in the buffer will depend on the format specified in
* the AudioRecord constructor, and will be native endian.
* @param audioBuffer the direct buffer to which the recorded audio data is written.
+ * Data is written to audioBuffer.position().
* @param sizeInBytes the number of requested bytes. It is recommended but not enforced
* that the number of bytes requested be a multiple of the frame size (sample size in
* bytes multiplied by the channel count).
@@ -1187,7 +1222,7 @@ public class AudioRecord implements AudioRouting
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
* The number of bytes will not exceed sizeInBytes.
- * The number of bytes read will truncated to be a multiple of the frame size.
+ * The number of bytes read will be truncated to be a multiple of the frame size.
*/
public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
if (mState != STATE_INITIALIZED) {
@@ -1696,8 +1731,9 @@ public class AudioRecord implements AudioRouting
private native final int native_setup(Object audiorecord_this,
Object /*AudioAttributes*/ attributes,
- int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
- int buffSizeInBytes, int[] sessionId, String opPackageName);
+ int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
+ int buffSizeInBytes, int[] sessionId, String opPackageName,
+ long nativeRecordInJavaObj);
// TODO remove: implementation calls directly into implementation of native_release()
private native final void native_finalize();
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
index 69df88f3cfe3..c2cd9b3d0637 100644
--- a/media/java/android/media/AudioRecordConfiguration.java
+++ b/media/java/android/media/AudioRecordConfiguration.java
@@ -18,7 +18,9 @@ package android.media;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
+import java.util.ArrayList;
import java.util.Objects;
/**
@@ -28,6 +30,7 @@ import java.util.Objects;
*
*/
public class AudioRecordConfiguration implements Parcelable {
+ private final static String TAG = new String("AudioRecordConfiguration");
private final int mSessionId;
@@ -36,29 +39,18 @@ public class AudioRecordConfiguration implements Parcelable {
private final AudioFormat mDeviceFormat;
private final AudioFormat mClientFormat;
- private final AudioDeviceInfo mRecDevice;
-
- /**
- * @hide
- */
- public AudioRecordConfiguration(int session, int source) {
- mSessionId = session;
- mClientSource = source;
- mDeviceFormat = new AudioFormat.Builder().build();
- mClientFormat = new AudioFormat.Builder().build();
- mRecDevice = null;
- }
+ private final int mPatchHandle;
/**
* @hide
*/
public AudioRecordConfiguration(int session, int source, AudioFormat devFormat,
- AudioFormat clientFormat, AudioDeviceInfo device) {
+ AudioFormat clientFormat, int patchHandle) {
mSessionId = session;
mClientSource = source;
mDeviceFormat = devFormat;
mClientFormat = clientFormat;
- mRecDevice = device;
+ mPatchHandle = patchHandle;
}
/**
@@ -95,10 +87,38 @@ public class AudioRecordConfiguration implements Parcelable {
public AudioFormat getClientFormat() { return mClientFormat; }
/**
- * Returns the audio input device used for this recording.
- * @return the audio recording device
+ * Returns information about the audio input device used for this recording.
+ * @return the audio recording device or null if this information cannot be retrieved
*/
- public AudioDeviceInfo getAudioDevice() { return mRecDevice; }
+ public AudioDeviceInfo getAudioDevice() {
+ // build the AudioDeviceInfo from the patch handle
+ ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
+ if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
+ Log.e(TAG, "Error retrieving list of audio patches");
+ return null;
+ }
+ for (int i = 0 ; i < patches.size() ; i++) {
+ final AudioPatch patch = patches.get(i);
+ if (patch.id() == mPatchHandle) {
+ final AudioPortConfig[] sources = patch.sources();
+ if ((sources != null) && (sources.length > 0)) {
+ // not supporting multiple sources, so just look at the first source
+ final int devId = sources[0].port().id();
+ final AudioDeviceInfo[] devices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
+ for (int j = 0; j < devices.length; j++) {
+ if (devices[j].getId() == devId) {
+ return devices[j];
+ }
+ }
+ }
+ // patch handle is unique, there won't be another with the same handle
+ break;
+ }
+ }
+ Log.e(TAG, "Couldn't find device for recording, did recording end already?");
+ return null;
+ }
public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
= new Parcelable.Creator<AudioRecordConfiguration>() {
@@ -129,14 +149,17 @@ public class AudioRecordConfiguration implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSessionId);
dest.writeInt(mClientSource);
+ mClientFormat.writeToParcel(dest, 0);
+ mDeviceFormat.writeToParcel(dest, 0);
+ dest.writeInt(mPatchHandle);
}
private AudioRecordConfiguration(Parcel in) {
mSessionId = in.readInt();
mClientSource = in.readInt();
- mDeviceFormat = new AudioFormat.Builder().build();
- mClientFormat = new AudioFormat.Builder().build();
- mRecDevice = null;
+ mClientFormat = AudioFormat.CREATOR.createFromParcel(in);
+ mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in);
+ mPatchHandle = in.readInt();
}
@Override
@@ -144,8 +167,12 @@ public class AudioRecordConfiguration implements Parcelable {
if (this == o) return true;
if (o == null || !(o instanceof AudioRecordConfiguration)) return false;
- final AudioRecordConfiguration that = (AudioRecordConfiguration) o;
- return ((mSessionId == that.mSessionId)
- && (mClientSource == that.mClientSource));
+ AudioRecordConfiguration that = (AudioRecordConfiguration) o;
+
+ return ((mSessionId == that.mSessionId)
+ && (mClientSource == that.mClientSource)
+ && (mPatchHandle == that.mPatchHandle)
+ && (mClientFormat.equals(that.mClientFormat))
+ && (mDeviceFormat.equals(that.mDeviceFormat)));
}
} \ No newline at end of file
diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java
index 2161cf3ee7ab..41f92d49e39f 100644
--- a/media/java/android/media/AudioRouting.java
+++ b/media/java/android/media/AudioRouting.java
@@ -41,6 +41,14 @@ public interface AudioRouting {
public AudioDeviceInfo getPreferredDevice();
/**
+ * Returns an {@link AudioDeviceInfo} identifying the current routing of this
+ * AudioTrack/AudioRecord.
+ * Note: The query is only valid if the AudioTrack/AudioRecord is currently playing.
+ * If it is not, <code>getRoutedDevice()</code> will return null.
+ */
+ public AudioDeviceInfo getRoutedDevice();
+
+ /**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
* changes on this AudioTrack/AudioRecord.
* @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index aa0d78dacd7e..247c4aea9106 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -273,7 +273,23 @@ public class AudioSystem
*/
public interface AudioRecordingCallback
{
- void onRecordingConfigurationChanged(int event, int session, int source);
+ /**
+ * Callback for recording activity notifications events
+ * @param event
+ * @param session
+ * @param source
+ * @param recordingFormat an array of ints containing respectively the client and device
+ * recording configurations (2*3 ints), followed by the patch handle:
+ * index 0: client format
+ * 1: client channel mask
+ * 2: client sample rate
+ * 3: device format
+ * 4: device channel mask
+ * 5: device sample rate
+ * 6: patch handle
+ */
+ void onRecordingConfigurationChanged(int event, int session, int source,
+ int[] recordingFormat);
}
private static AudioRecordingCallback sRecordingCallback;
@@ -285,13 +301,23 @@ public class AudioSystem
}
}
- private static void recordingCallbackFromNative(int event, int session, int source) {
+ /**
+ * Callback from native for recording configuration updates.
+ * @param event
+ * @param session
+ * @param source
+ * @param recordingFormat see
+ * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])} for
+ * the description of the record format.
+ */
+ private static void recordingCallbackFromNative(int event, int session, int source,
+ int[] recordingFormat) {
AudioRecordingCallback cb = null;
synchronized (AudioSystem.class) {
cb = sRecordingCallback;
}
if (cb != null) {
- cb.onRecordingConfigurationChanged(event, session, source);
+ cb.onRecordingConfigurationChanged(event, session, source, recordingFormat);
}
}
@@ -346,6 +372,7 @@ public class AudioSystem
public static final int DEVICE_OUT_AUX_LINE = 0x200000;
public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
public static final int DEVICE_OUT_IP = 0x800000;
+ public static final int DEVICE_OUT_BUS = 0x1000000;
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
@@ -373,6 +400,7 @@ public class AudioSystem
DEVICE_OUT_AUX_LINE |
DEVICE_OUT_SPEAKER_SAFE |
DEVICE_OUT_IP |
+ DEVICE_OUT_BUS |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -412,6 +440,7 @@ public class AudioSystem
public static final int DEVICE_IN_BLUETOOTH_A2DP = DEVICE_BIT_IN | 0x20000;
public static final int DEVICE_IN_LOOPBACK = DEVICE_BIT_IN | 0x40000;
public static final int DEVICE_IN_IP = DEVICE_BIT_IN | 0x80000;
+ public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
@@ -434,6 +463,7 @@ public class AudioSystem
DEVICE_IN_BLUETOOTH_A2DP |
DEVICE_IN_LOOPBACK |
DEVICE_IN_IP |
+ DEVICE_IN_BUS |
DEVICE_IN_DEFAULT);
public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -469,6 +499,7 @@ public class AudioSystem
public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
public static final String DEVICE_OUT_IP_NAME = "ip";
+ public static final String DEVICE_OUT_BUS_NAME = "bus";
public static final String DEVICE_IN_COMMUNICATION_NAME = "communication";
public static final String DEVICE_IN_AMBIENT_NAME = "ambient";
@@ -490,6 +521,7 @@ public class AudioSystem
public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp";
public static final String DEVICE_IN_LOOPBACK_NAME = "loopback";
public static final String DEVICE_IN_IP_NAME = "ip";
+ public static final String DEVICE_IN_BUS_NAME = "bus";
public static String getOutputDeviceName(int device)
{
@@ -542,6 +574,8 @@ public class AudioSystem
return DEVICE_OUT_SPEAKER_SAFE_NAME;
case DEVICE_OUT_IP:
return DEVICE_OUT_IP_NAME;
+ case DEVICE_OUT_BUS:
+ return DEVICE_OUT_BUS_NAME;
case DEVICE_OUT_DEFAULT:
default:
return Integer.toString(device);
@@ -591,6 +625,8 @@ public class AudioSystem
return DEVICE_IN_LOOPBACK_NAME;
case DEVICE_IN_IP:
return DEVICE_IN_IP_NAME;
+ case DEVICE_IN_BUS:
+ return DEVICE_IN_BUS_NAME;
case DEVICE_IN_DEFAULT:
default:
return Integer.toString(device);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b26b310a904b..f02e8375f072 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -91,11 +91,6 @@ public class AudioTrack implements AudioRouting
*/
private static final float GAIN_MAX = 1.0f;
- /** Minimum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MIN = 4000;
- /** Maximum value for sample rate */
- private static final int SAMPLE_RATE_HZ_MAX = 192000;
-
/** Maximum value for AudioTrack channel count
* @hide public for MediaCode only, do not un-hide or change to a numeric literal
*/
@@ -254,6 +249,7 @@ public class AudioTrack implements AudioRouting
private final Looper mInitializationLooper;
/**
* The audio data source sampling rate in Hz.
+ * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
*/
private int mSampleRate; // initialized by all constructors via audioParamCheck()
/**
@@ -340,6 +336,9 @@ public class AudioTrack implements AudioRouting
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
* {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
* @param sampleRateInHz the initial source sample rate expressed in Hz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+ * which is usually the sample rate of the sink.
+ * {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -389,6 +388,8 @@ public class AudioTrack implements AudioRouting
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},
* {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.
* @param sampleRateInHz the initial source sample rate expressed in Hz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
+ * which is usually the sample rate of the sink.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -461,16 +462,11 @@ public class AudioTrack implements AudioRouting
looper = Looper.getMainLooper();
}
- int rate = 0;
- if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
- {
- rate = format.getSampleRate();
- } else {
- rate = AudioSystem.getPrimaryOutputSamplingRate();
- if (rate <= 0) {
- rate = 44100;
- }
+ int rate = format.getSampleRate();
+ if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
+ rate = 0;
}
+
int channelIndexMask = 0;
if ((format.getPropertySetMask()
& AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
@@ -503,17 +499,19 @@ public class AudioTrack implements AudioRouting
throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
}
+ int[] sampleRate = new int[] {mSampleRate};
int[] session = new int[1];
session[0] = sessionId;
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
- mSampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
- mNativeBufferSizeInBytes, mDataLoadMode, session);
+ sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
+ mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
}
+ mSampleRate = sampleRate[0];
mSessionId = session[0];
if (mDataLoadMode == MODE_STATIC) {
@@ -530,8 +528,6 @@ public class AudioTrack implements AudioRouting
* (associated with an OpenSL ES player).
*/
/*package*/ AudioTrack(long nativeTrackInJavaObj) {
- mNativeTrackInJavaObj = nativeTrackInJavaObj;
-
// "final"s
mAttributes = null;
mAppOps = null;
@@ -544,6 +540,26 @@ public class AudioTrack implements AudioRouting
mInitializationLooper = looper;
// other initialization...
+ // Note that for this native_setup, we are providing an already created/initialized
+ // *Native* AudioTrack, so the attributes parameters to native_setup() are ignored.
+ int[] session = { 0 };
+ int[] rates = { 0 };
+ int initResult = native_setup(new WeakReference<AudioTrack>(this),
+ null /*mAttributes - NA*/,
+ rates /*sampleRate - NA*/,
+ 0 /*mChannelMask - NA*/,
+ 0 /*mChannelIndexMask - NA*/,
+ 0 /*mAudioFormat - NA*/,
+ 0 /*mNativeBufferSizeInBytes - NA*/,
+ 0 /*mDataLoadMode - NA*/,
+ session,
+ nativeTrackInJavaObj);
+ if (initResult != SUCCESS) {
+ loge("Error code "+initResult+" when initializing AudioTrack.");
+ return; // with mState == STATE_UNINITIALIZED
+ }
+
+ mSessionId = session[0];
mState = STATE_INITIALIZED;
}
@@ -712,7 +728,7 @@ public class AudioTrack implements AudioRouting
if (mFormat == null) {
mFormat = new AudioFormat.Builder()
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
- .setSampleRate(AudioSystem.getPrimaryOutputSamplingRate())
+ //.setSampleRate(AudioFormat.SAMPLE_RATE_UNSPECIFIED)
.setEncoding(AudioFormat.ENCODING_DEFAULT)
.build();
}
@@ -762,7 +778,9 @@ public class AudioTrack implements AudioRouting
int audioFormat, int mode) {
//--------------
// sample rate, note these values are subject to change
- if (sampleRateInHz < SAMPLE_RATE_HZ_MIN || sampleRateInHz > SAMPLE_RATE_HZ_MAX) {
+ if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
+ sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
+ sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
throw new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate.");
}
@@ -885,10 +903,10 @@ public class AudioTrack implements AudioRouting
// postcondition:
// mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
private void audioBuffSizeCheck(int audioBufferSize) {
- // NB: this section is only valid with PCM data.
+ // NB: this section is only valid with PCM or IEC61937 data.
// To update when supporting compressed formats
int frameSizeInBytes;
- if (AudioFormat.isEncodingLinearPcm(mAudioFormat)) {
+ if (AudioFormat.isEncodingLinearFrames(mAudioFormat)) {
frameSizeInBytes = mChannelCount * AudioFormat.getBytesPerSample(mAudioFormat);
} else {
frameSizeInBytes = 1;
@@ -948,7 +966,13 @@ public class AudioTrack implements AudioRouting
}
/**
- * Returns the configured audio data sample rate in Hz
+ * Returns the configured audio source sample rate in Hz.
+ * The initial source sample rate depends on the constructor parameters,
+ * but the source sample rate may change if {@link #setPlaybackRate(int)} is called.
+ * If the constructor had a specific sample rate, then the initial sink sample rate is that
+ * value.
+ * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
+ * then the initial sink sample rate is a route-dependent default value based on the source [sic].
*/
public int getSampleRate() {
return mSampleRate;
@@ -1052,32 +1076,27 @@ public class AudioTrack implements AudioRouting
}
}
-// TODO Change getBufferCapacityInFrames() reference below to
-// {@link #getBufferCapacityInFrames()} after @hide is removed.
-// TODO Change setBufferSizeInFrames(int) reference below to
-// {@link #setBufferSizeInFrames(int)} after @hide is removed.
+
/**
- * Returns the effective size of the <code>AudioTrack</code> buffer
+ * Returns the effective size of the <code>AudioTrack</code> buffer
* that the application writes to.
- * <p> This will be less than or equal to the result of
- * getBufferCapacityInFrames().
- * It will be equal if setBufferSizeInFrames(int) has never been called.
- * <p> If the track is subsequently routed to a different output sink, the buffer
- * size and capacity may enlarge to accommodate.
- * <p> If the <code>AudioTrack</code> encoding indicates compressed data,
- * e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
- * the size of the native <code>AudioTrack</code> buffer in bytes.
- * <p> See also {@link AudioManager#getProperty(String)} for key
- * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
- * @return current size in frames of the <code>AudioTrack</code> buffer.
- * @throws IllegalStateException
+ * <p> This will be less than or equal to the result of
+ * {@link #getBufferCapacityInFrames()}.
+ * It will be equal if {@link #setBufferSizeInFrames(int)} has never been called.
+ * <p> If the track is subsequently routed to a different output sink, the buffer
+ * size and capacity may enlarge to accommodate.
+ * <p> If the <code>AudioTrack</code> encoding indicates compressed data,
+ * e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
+ * the size of the native <code>AudioTrack</code> buffer in bytes.
+ * <p> See also {@link AudioManager#getProperty(String)} for key
+ * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
+ * @return current size in frames of the <code>AudioTrack</code> buffer.
+ * @throws IllegalStateException
*/
public int getBufferSizeInFrames() {
return native_get_buffer_size_frames();
}
-// TODO Change getBufferCapacityInFrames() reference below to
-// {@link #getBufferCapacityInFrames()} after @hide is removed.
/**
* Limits the effective size of the <code>AudioTrack</code> buffer
* that the application writes to.
@@ -1087,9 +1106,9 @@ public class AudioTrack implements AudioRouting
* <p>Changing this limit modifies the latency associated with
* the buffer for this track. A smaller size will give lower latency
* but there may be more glitches due to buffer underruns.
- * <p>The actual size used may not be equal to this requested size.
+ * <p>The actual size used may not be equal to this requested size.
* It will be limited to a valid range with a maximum of
- * getBufferCapacityInFrames().
+ * {@link #getBufferCapacityInFrames()}.
* It may also be adjusted slightly for internal reasons.
* If bufferSizeInFrames is less than zero then {@link #ERROR_BAD_VALUE}
* will be returned.
@@ -1097,9 +1116,9 @@ public class AudioTrack implements AudioRouting
* It is not supported for compressed audio tracks.
*
* @param bufferSizeInFrames requested buffer size
- * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
- * {@link #ERROR_INVALID_OPERATION}
- * @throws IllegalStateException
+ * @return the actual buffer size in frames or an error code,
+ * {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
+ * @throws IllegalStateException
*/
public int setBufferSizeInFrames(int bufferSizeInFrames) {
if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
@@ -1223,6 +1242,7 @@ public class AudioTrack implements AudioRouting
* to a higher value than the initial source sample rate, be sure to configure the buffer size
* based on the highest planned sample rate.
* @param sampleRateInHz the source sample rate expressed in Hz.
+ * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
@@ -1260,7 +1280,9 @@ public class AudioTrack implements AudioRouting
}
// sample rate, note these values are subject to change
- if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) {
+ // Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed
+ if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
+ (sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) {
loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");
return ERROR_BAD_VALUE;
}
@@ -1774,6 +1796,7 @@ public class AudioTrack implements AudioRouting
* or copies audio data for later playback (static buffer mode).
* The format specified in the AudioTrack constructor should be
* {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
+ * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated.
* <p>
* In streaming mode, the write will normally block until all the data has been enqueued for
* playback, and will return a full transfer count. However, if the track is stopped or paused
@@ -1786,7 +1809,9 @@ public class AudioTrack implements AudioRouting
* @param audioData the array that holds the data to play.
* @param offsetInBytes the offset expressed in bytes in audioData where the data to write
* starts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInBytes the number of bytes to write in audioData after the offset.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @return zero or the positive number of bytes that were written, or
* {@link #ERROR_INVALID_OPERATION}
* if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
@@ -1795,6 +1820,8 @@ public class AudioTrack implements AudioRouting
* needs to be recreated.
* The dead object error code is not returned if some data was successfully transferred.
* In this case, the error is returned at the next write().
+ * The number of bytes will be a multiple of the frame size in bytes
+ * not to exceed sizeInBytes.
*
* This is equivalent to {@link #write(byte[], int, int, int)} with <code>writeMode</code>
* set to {@link #WRITE_BLOCKING}.
@@ -1808,6 +1835,7 @@ public class AudioTrack implements AudioRouting
* or copies audio data for later playback (static buffer mode).
* The format specified in the AudioTrack constructor should be
* {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
+ * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated.
* <p>
* In streaming mode, the blocking behavior depends on the write mode. If the write mode is
* {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued
@@ -1823,7 +1851,9 @@ public class AudioTrack implements AudioRouting
* @param audioData the array that holds the data to play.
* @param offsetInBytes the offset expressed in bytes in audioData where the data to write
* starts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInBytes the number of bytes to write in audioData after the offset.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
* effect in static mode.
* <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
@@ -1838,6 +1868,8 @@ public class AudioTrack implements AudioRouting
* needs to be recreated.
* The dead object error code is not returned if some data was successfully transferred.
* In this case, the error is returned at the next write().
+ * The number of bytes will be a multiple of the frame size in bytes
+ * not to exceed sizeInBytes.
*/
public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@WriteMode int writeMode) {
@@ -1887,7 +1919,9 @@ public class AudioTrack implements AudioRouting
* @param audioData the array that holds the data to play.
* @param offsetInShorts the offset expressed in shorts in audioData where the data to play
* starts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInShorts the number of shorts to read in audioData after the offset.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @return zero or the positive number of shorts that were written, or
* {@link #ERROR_INVALID_OPERATION}
* if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
@@ -1896,6 +1930,7 @@ public class AudioTrack implements AudioRouting
* needs to be recreated.
* The dead object error code is not returned if some data was successfully transferred.
* In this case, the error is returned at the next write().
+ * The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
*
* This is equivalent to {@link #write(short[], int, int, int)} with <code>writeMode</code>
* set to {@link #WRITE_BLOCKING}.
@@ -1923,7 +1958,9 @@ public class AudioTrack implements AudioRouting
* @param audioData the array that holds the data to write.
* @param offsetInShorts the offset expressed in shorts in audioData where the data to write
* starts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInShorts the number of shorts to read in audioData after the offset.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
* effect in static mode.
* <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
@@ -1938,6 +1975,7 @@ public class AudioTrack implements AudioRouting
* needs to be recreated.
* The dead object error code is not returned if some data was successfully transferred.
* In this case, the error is returned at the next write().
+ * The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
*/
public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@WriteMode int writeMode) {
@@ -1999,7 +2037,9 @@ public class AudioTrack implements AudioRouting
* to provide samples values within the nominal range.
* @param offsetInFloats the offset, expressed as a number of floats,
* in audioData where the data to write starts.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param sizeInFloats the number of floats to write in audioData after the offset.
+ * Must not be negative, or cause the data access to go out of bounds of the array.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
* effect in static mode.
* <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
@@ -2014,6 +2054,7 @@ public class AudioTrack implements AudioRouting
* needs to be recreated.
* The dead object error code is not returned if some data was successfully transferred.
* In this case, the error is returned at the next write().
+ * The number of floats will be a multiple of the channel count not to exceed sizeInFloats.
*/
public int write(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
@WriteMode int writeMode) {
@@ -2075,7 +2116,9 @@ public class AudioTrack implements AudioRouting
* <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
* have been advanced to reflect the amount of data that was successfully written to
* the AudioTrack.
- * @param sizeInBytes number of bytes to write.
+ * @param sizeInBytes number of bytes to write. It is recommended but not enforced
+ * that the number of bytes requested be a multiple of the frame size (sample size in
+ * bytes multiplied by the channel count).
* <BR>Note this may differ from <code>audioData.remaining()</code>, but cannot exceed it.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
* effect in static mode.
@@ -2142,7 +2185,9 @@ public class AudioTrack implements AudioRouting
* <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
* have been advanced to reflect the amount of data that was successfully written to
* the AudioTrack.
- * @param sizeInBytes number of bytes to write.
+ * @param sizeInBytes number of bytes to write. It is recommended but not enforced
+ * that the number of bytes requested be a multiple of the frame size (sample size in
+ * bytes multiplied by the channel count).
* <BR>Note this may differ from <code>audioData.remaining()</code>, but cannot exceed it.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}.
* <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
@@ -2745,8 +2790,8 @@ public class AudioTrack implements AudioRouting
// AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC
private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
Object /*AudioAttributes*/ attributes,
- int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
- int buffSizeInBytes, int mode, int[] sessionId);
+ int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
+ int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack);
private native final void native_finalize();
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 7fb67ee5581d..1a387be21183 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -16,22 +16,51 @@
package android.media;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.regex.Pattern;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
/**
* This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
* <p>
* Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF and RAF.
+ * <p>
+ * Attribute mutation is supported for JPEG image files.
*/
public class ExifInterface {
+ private static final String TAG = "ExifInterface";
+ private static final boolean DEBUG = false;
+
// The Exif tag names
/** Type is int. */
public static final String TAG_ORIENTATION = "Orientation";
@@ -97,6 +126,20 @@ public class ExifInterface {
public static final String TAG_FOCAL_LENGTH = "FocalLength";
/** Type is String. Name of GPS processing method used for location finding. */
public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+ /** Type is double. */
+ public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ /** Type is double. */
+ public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+ /** Type is double. */
+ public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ /** Type is int. */
+ public static final String TAG_LIGHT_SOURCE = "LightSource";
+ /** Type is int. */
+ public static final String TAG_METERING_MODE = "MeteringMode";
+ /** Type is int. */
+ public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
+ /** Type is int. */
+ public static final String TAG_EXPOSURE_MODE = "ExposureMode";
// Private tags used for thumbnail information.
private static final String TAG_HAS_THUMBNAIL = "hasThumbnail";
@@ -119,30 +162,321 @@ public class ExifInterface {
// Constants used for white balance
public static final int WHITEBALANCE_AUTO = 0;
public static final int WHITEBALANCE_MANUAL = 1;
+
private static SimpleDateFormat sFormatter;
+ // See Exchangeable image file format for digital still cameras: Exif version 2.2.
+ // The following values are for parsing EXIF data area. There are tag groups in EXIF data area.
+ // They are called "Image File Directory". They have multiple data formats to cover various
+ // image metadata from GPS longitude to camera model name.
+
+ // Types of Exif byte alignments (see JEITA CP-3451 page 10)
+ private static final short BYTE_ALIGN_II = 0x4949; // II: Intel order
+ private static final short BYTE_ALIGN_MM = 0x4d4d; // MM: Motorola order
+
+ // Formats for the value in IFD entry (See TIFF 6.0 spec Types page 15).
+ private static final int IFD_FORMAT_BYTE = 1;
+ private static final int IFD_FORMAT_STRING = 2;
+ private static final int IFD_FORMAT_USHORT = 3;
+ private static final int IFD_FORMAT_ULONG = 4;
+ private static final int IFD_FORMAT_URATIONAL = 5;
+ private static final int IFD_FORMAT_SBYTE = 6;
+ private static final int IFD_FORMAT_UNDEFINED = 7;
+ private static final int IFD_FORMAT_SSHORT = 8;
+ private static final int IFD_FORMAT_SLONG = 9;
+ private static final int IFD_FORMAT_SRATIONAL = 10;
+ private static final int IFD_FORMAT_SINGLE = 11;
+ private static final int IFD_FORMAT_DOUBLE = 12;
+ // Sizes of the components of each IFD value format
+ private static final int[] IFD_FORMAT_BYTES_PER_FORMAT = new int[] {
+ 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8
+ };
+ private static final byte[] EXIF_ASCII_PREFIX = new byte[] {
+ 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0
+ };
+
+ // A class for indicating EXIF tag.
+ private static class ExifTag {
+ public final int number;
+ public final String name;
+
+ private ExifTag(String name, int number) {
+ this.name = name;
+ this.number = number;
+ }
+ }
+
+ // Primary image IFD TIFF tags (See JEITA CP-3451 Table 14. page 54).
+ private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] {
+ new ExifTag("ImageWidth", 256),
+ new ExifTag("ImageLength", 257),
+ new ExifTag("BitsPerSample", 258),
+ new ExifTag("Compression", 259),
+ new ExifTag("PhotometricInterpretation", 262),
+ new ExifTag("ImageDescription", 270),
+ new ExifTag("Make", 271),
+ new ExifTag("Model", 272),
+ new ExifTag("StripOffsets", 273),
+ new ExifTag("Orientation", 274),
+ new ExifTag("SamplesPerPixel", 277),
+ new ExifTag("RowsPerStrip", 278),
+ new ExifTag("StripByteCounts", 279),
+ new ExifTag("XResolution", 282),
+ new ExifTag("YResolution", 283),
+ new ExifTag("PlanarConfiguration", 284),
+ new ExifTag("ResolutionUnit", 296),
+ new ExifTag("TransferFunction", 301),
+ new ExifTag("Software", 305),
+ new ExifTag("DateTime", 306),
+ new ExifTag("Artist", 315),
+ new ExifTag("WhitePoint", 318),
+ new ExifTag("PrimaryChromaticities", 319),
+ new ExifTag("JPEGInterchangeFormat", 513),
+ new ExifTag("JPEGInterchangeFormatLength", 514),
+ new ExifTag("YCbCrCoefficients", 529),
+ new ExifTag("YCbCrSubSampling", 530),
+ new ExifTag("YCbCrPositioning", 531),
+ new ExifTag("ReferenceBlackWhite", 532),
+ new ExifTag("Copyright", 33432),
+ new ExifTag("ExifIFDPointer", 34665),
+ new ExifTag("GPSInfoIFDPointer", 34853),
+ };
+ // Primary image IFD Exif Private tags (See JEITA CP-3451 Table 15. page 55).
+ private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] {
+ new ExifTag("ExposureTime", 33434),
+ new ExifTag("FNumber", 33437),
+ new ExifTag("ExposureProgram", 34850),
+ new ExifTag("SpectralSensitivity", 34852),
+ new ExifTag("ISOSpeedRatings", 34855),
+ new ExifTag("OECF", 34856),
+ new ExifTag("ExifVersion", 36864),
+ new ExifTag("DateTimeOriginal", 36867),
+ new ExifTag("DateTimeDigitized", 36868),
+ new ExifTag("ComponentsConfiguration", 37121),
+ new ExifTag("CompressedBitsPerPixel", 37122),
+ new ExifTag("ShutterSpeedValue", 37377),
+ new ExifTag("ApertureValue", 37378),
+ new ExifTag("BrightnessValue", 37379),
+ new ExifTag("ExposureBiasValue", 37380),
+ new ExifTag("MaxApertureValue", 37381),
+ new ExifTag("SubjectDistance", 37382),
+ new ExifTag("MeteringMode", 37383),
+ new ExifTag("LightSource", 37384),
+ new ExifTag("Flash", 37385),
+ new ExifTag("FocalLength", 37386),
+ new ExifTag("SubjectArea", 37396),
+ new ExifTag("MakerNote", 37500),
+ new ExifTag("UserComment", 37510),
+ new ExifTag("SubSecTime", 37520),
+ new ExifTag("SubSecTimeOriginal", 37521),
+ new ExifTag("SubSecTimeDigitized", 37522),
+ new ExifTag("FlashpixVersion", 40960),
+ new ExifTag("ColorSpace", 40961),
+ new ExifTag("PixelXDimension", 40962),
+ new ExifTag("PixelYDimension", 40963),
+ new ExifTag("RelatedSoundFile", 40964),
+ new ExifTag("InteroperabilityIFDPointer", 40965),
+ new ExifTag("FlashEnergy", 41483),
+ new ExifTag("SpatialFrequencyResponse", 41484),
+ new ExifTag("FocalPlaneXResolution", 41486),
+ new ExifTag("FocalPlaneYResolution", 41487),
+ new ExifTag("FocalPlaneResolutionUnit", 41488),
+ new ExifTag("SubjectLocation", 41492),
+ new ExifTag("ExposureIndex", 41493),
+ new ExifTag("SensingMethod", 41495),
+ new ExifTag("FileSource", 41728),
+ new ExifTag("SceneType", 41729),
+ new ExifTag("CFAPattern", 41730),
+ new ExifTag("CustomRendered", 41985),
+ new ExifTag("ExposureMode", 41986),
+ new ExifTag("WhiteBalance", 41987),
+ new ExifTag("DigitalZoomRatio", 41988),
+ new ExifTag("FocalLengthIn35mmFilm", 41989),
+ new ExifTag("SceneCaptureType", 41990),
+ new ExifTag("GainControl", 41991),
+ new ExifTag("Contrast", 41992),
+ new ExifTag("Saturation", 41993),
+ new ExifTag("Sharpness", 41994),
+ new ExifTag("DeviceSettingDescription", 41995),
+ new ExifTag("SubjectDistanceRange", 41996),
+ new ExifTag("ImageUniqueID", 42016),
+ };
+ // Primary image IFD GPS Info tags (See JEITA CP-3451 Table 16. page 56).
+ private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] {
+ new ExifTag("GPSVersionID", 0),
+ new ExifTag("GPSLatitudeRef", 1),
+ new ExifTag("GPSLatitude", 2),
+ new ExifTag("GPSLongitudeRef", 3),
+ new ExifTag("GPSLongitude", 4),
+ new ExifTag("GPSAltitudeRef", 5),
+ new ExifTag("GPSAltitude", 6),
+ new ExifTag("GPSTimeStamp", 7),
+ new ExifTag("GPSSatellites", 8),
+ new ExifTag("GPSStatus", 9),
+ new ExifTag("GPSMeasureMode", 10),
+ new ExifTag("GPSDOP", 11),
+ new ExifTag("GPSSpeedRef", 12),
+ new ExifTag("GPSSpeed", 13),
+ new ExifTag("GPSTrackRef", 14),
+ new ExifTag("GPSTrack", 15),
+ new ExifTag("GPSImgDirectionRef", 16),
+ new ExifTag("GPSImgDirection", 17),
+ new ExifTag("GPSMapDatum", 18),
+ new ExifTag("GPSDestLatitudeRef", 19),
+ new ExifTag("GPSDestLatitude", 20),
+ new ExifTag("GPSDestLongitudeRef", 21),
+ new ExifTag("GPSDestLongitude", 22),
+ new ExifTag("GPSDestBearingRef", 23),
+ new ExifTag("GPSDestBearing", 24),
+ new ExifTag("GPSDestDistanceRef", 25),
+ new ExifTag("GPSDestDistance", 26),
+ new ExifTag("GPSProcessingMethod", 27),
+ new ExifTag("GPSAreaInformation", 28),
+ new ExifTag("GPSDateStamp", 29),
+ new ExifTag("GPSDifferential", 30),
+ };
+ // Primary image IFD Interoperability tag (See JEITA CP-3451 Table 17. page 56).
+ private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] {
+ new ExifTag("InteroperabilityIndex", 1),
+ };
+ // IFD Thumbnail tags (See JEITA CP-3451 Table 18. page 57).
+ private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] {
+ new ExifTag("ThumbnailImageWidth", 256),
+ new ExifTag("ThumbnailImageLength", 257),
+ new ExifTag("BitsPerSample", 258),
+ new ExifTag("Compression", 259),
+ new ExifTag("PhotometricInterpretation", 262),
+ new ExifTag("ImageDescription", 270),
+ new ExifTag("Make", 271),
+ new ExifTag("Model", 272),
+ new ExifTag("StripOffsets", 273),
+ new ExifTag("Orientation", 274),
+ new ExifTag("SamplesPerPixel", 277),
+ new ExifTag("RowsPerStrip", 278),
+ new ExifTag("StripByteCounts", 279),
+ new ExifTag("XResolution", 282),
+ new ExifTag("YResolution", 283),
+ new ExifTag("PlanarConfiguration", 284),
+ new ExifTag("ResolutionUnit", 296),
+ new ExifTag("TransferFunction", 301),
+ new ExifTag("Software", 305),
+ new ExifTag("DateTime", 306),
+ new ExifTag("Artist", 315),
+ new ExifTag("WhitePoint", 318),
+ new ExifTag("PrimaryChromaticities", 319),
+ new ExifTag("JPEGInterchangeFormat", 513),
+ new ExifTag("JPEGInterchangeFormatLength", 514),
+ new ExifTag("YCbCrCoefficients", 529),
+ new ExifTag("YCbCrSubSampling", 530),
+ new ExifTag("YCbCrPositioning", 531),
+ new ExifTag("ReferenceBlackWhite", 532),
+ new ExifTag("Copyright", 33432),
+ new ExifTag("ExifIFDPointer", 34665),
+ new ExifTag("GPSInfoIFDPointer", 34853),
+ };
+
+ // See JEITA CP-3451 Figure 5. page 9.
+ // The following values are used for indicating pointers to the other Image File Directorys.
+
+ // Indices of Exif Ifd tag groups
+ private static final int IFD_TIFF_HINT = 0;
+ private static final int IFD_EXIF_HINT = 1;
+ private static final int IFD_GPS_HINT = 2;
+ private static final int IFD_INTEROPERABILITY_HINT = 3;
+ private static final int IFD_THUMBNAIL_HINT = 4;
+ // List of Exif tag groups
+ private static final ExifTag[][] EXIF_TAGS = new ExifTag[][] {
+ IFD_TIFF_TAGS, IFD_EXIF_TAGS, IFD_GPS_TAGS, IFD_INTEROPERABILITY_TAGS,
+ IFD_THUMBNAIL_TAGS
+ };
+ // List of tags for pointing to the other image file directory offset.
+ private static final ExifTag[] IFD_POINTER_TAGS = new ExifTag[] {
+ new ExifTag("ExifIFDPointer", 34665),
+ new ExifTag("GPSInfoPointer", 34853),
+ new ExifTag("InteroperabilityIFDPointer", 40965),
+ };
+ // List of indices of the indicated tag groups according to the IFD_POINTER_TAGS
+ private static final int[] IFD_POINTER_TAG_HINTS = new int[] {
+ IFD_EXIF_HINT, IFD_GPS_HINT, IFD_INTEROPERABILITY_HINT
+ };
+ // Tags for indicating the thumbnail offset and length
+ private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG =
+ new ExifTag("JPEGInterchangeFormat", 513);
+ private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG =
+ new ExifTag("JPEGInterchangeFormatLength", 514);
+
+ // Mappings from tag number to tag name and each item represents one IFD tag group.
+ private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length];
+ // Mapping from tag name to tag number and the corresponding tag group.
+ private static final HashMap<String, Pair<Integer, Integer>> sExifTagMapForWriting
+ = new HashMap<>();
+
+ // See JPEG File Interchange Format Version 1.02.
+ // The following values are defined for handling JPEG streams. In this implementation, we are
+ // not only getting information from EXIF but also from some JPEG special segments such as
+ // MARKER_COM for user comment and MARKER_SOFx for image width and height.
+
+ // Identifier for APP1 segment in JPEG
+ private static final byte[] IDENTIFIER_APP1 = "Exif\0\0".getBytes(Charset.forName("US-ASCII"));
+ // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with
+ // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start
+ // of frame(baseline DCT) and the image size info exists in its beginning part.
+ private static final byte MARKER = (byte) 0xff;
+ private static final byte MARKER_SOI = (byte) 0xd8;
+ private static final byte MARKER_SOF0 = (byte) 0xc0;
+ private static final byte MARKER_SOF1 = (byte) 0xc1;
+ private static final byte MARKER_SOF2 = (byte) 0xc2;
+ private static final byte MARKER_SOF3 = (byte) 0xc3;
+ private static final byte MARKER_SOF5 = (byte) 0xc5;
+ private static final byte MARKER_SOF6 = (byte) 0xc6;
+ private static final byte MARKER_SOF7 = (byte) 0xc7;
+ private static final byte MARKER_SOF9 = (byte) 0xc9;
+ private static final byte MARKER_SOF10 = (byte) 0xca;
+ private static final byte MARKER_SOF11 = (byte) 0xcb;
+ private static final byte MARKER_SOF13 = (byte) 0xcd;
+ private static final byte MARKER_SOF14 = (byte) 0xce;
+ private static final byte MARKER_SOF15 = (byte) 0xcf;
+ private static final byte MARKER_SOS = (byte) 0xda;
+ private static final byte MARKER_APP1 = (byte) 0xe1;
+ private static final byte MARKER_COM = (byte) 0xfe;
+ private static final byte MARKER_EOI = (byte) 0xd9;
+
static {
- System.loadLibrary("jhead_jni");
System.loadLibrary("media_jni");
initRawNative();
-
sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+ // Build up the hash tables to look up Exif tags for reading Exif tags.
+ for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+ sExifTagMapsForReading[hint] = new HashMap();
+ for (ExifTag tag : EXIF_TAGS[hint]) {
+ sExifTagMapsForReading[hint].put(tag.number, tag.name);
+ }
+ }
+
+ // Build up the hash tables to look up Exif tags for writing Exif tags.
+ // There are some tags that have the same tag name in the different group. For that tags,
+ // Primary image TIFF IFD and Exif private IFD have a higher priority to map than the other
+ // tag groups. For the same tags, it writes one tag in the only one IFD group, which has the
+ // higher priority group.
+ for (int hint = EXIF_TAGS.length - 1; hint >= 0; --hint) {
+ for (ExifTag tag : EXIF_TAGS[hint]) {
+ sExifTagMapForWriting.put(tag.name, new Pair<>(tag.number, hint));
+ }
+ }
}
private final String mFilename;
- private final HashMap<String, String> mAttributes = new HashMap<>();
+ private final FileDescriptor mFileDescriptor;
+ private final InputStream mInputStream;
private boolean mIsRaw;
+ private final HashMap<String, String> mAttributes = new HashMap<>();
private boolean mHasThumbnail;
// The following values used for indicating a thumbnail position.
private int mThumbnailOffset;
private int mThumbnailLength;
-
- // Because the underlying implementation (jhead) uses static variables,
- // there can only be one user at a time for the native functions (and
- // they cannot keep state in the native code across function calls). We
- // use sLock to serialize the accesses.
- private static final Object sLock = new Object();
+ private byte[] mThumbnailBytes;
// Pattern to check non zero timestamp
private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
@@ -155,7 +489,35 @@ public class ExifInterface {
throw new IllegalArgumentException("filename cannot be null");
}
mFilename = filename;
- // First test whether a given file is a one of RAW format or not.
+ mFileDescriptor = null;
+ mInputStream = new FileInputStream(filename);
+ loadAttributes();
+ }
+
+ /**
+ * Reads Exif tags from the specified image file descriptor.
+ */
+ public ExifInterface(FileDescriptor fileDescriptor) throws IOException {
+ if (fileDescriptor == null) {
+ throw new IllegalArgumentException("parcelFileDescriptor cannot be null");
+ }
+ mFilename = null;
+ mFileDescriptor = fileDescriptor;
+ mInputStream = new FileInputStream(fileDescriptor);
+ loadAttributes();
+ }
+
+ /**
+ * Reads Exif tags from the specified image input stream. Attribute mutation is not supported
+ * for input streams.
+ */
+ public ExifInterface(InputStream inputStream) throws IOException {
+ if (inputStream == null) {
+ throw new IllegalArgumentException("inputStream cannot be null");
+ }
+ mFilename = null;
+ mFileDescriptor = null;
+ mInputStream = inputStream;
loadAttributes();
}
@@ -188,9 +550,9 @@ public class ExifInterface {
}
/**
- * Returns the double value of the specified rational tag. If there is no
- * such tag in the image file or the value cannot be parsed as double, return
- * <var>defaultValue</var>.
+ * Returns the double value of the tag that is specified as rational or contains a
+ * double-formatted value. If there is no such tag in the image file or the value cannot be
+ * parsed as double, return <var>defaultValue</var>.
*
* @param tag the name of the tag.
* @param defaultValue the value to return if the tag is not available.
@@ -200,7 +562,7 @@ public class ExifInterface {
if (value == null) return defaultValue;
try {
int index = value.indexOf("/");
- if (index == -1) return defaultValue;
+ if (index == -1) return Double.parseDouble(value);
double denom = Double.parseDouble(value.substring(index + 1));
if (denom == 0) return defaultValue;
double num = Double.parseDouble(value.substring(0, index));
@@ -217,6 +579,10 @@ public class ExifInterface {
* @param value the value of the tag.
*/
public void setAttribute(String tag, String value) {
+ if (value == null) {
+ mAttributes.remove(tag);
+ return;
+ }
mAttributes.put(tag, value);
}
@@ -231,68 +597,74 @@ public class ExifInterface {
* file has a thumbnail inside.
*/
private void loadAttributes() throws IOException {
- HashMap map = getRawAttributesNative(mFilename);
- mIsRaw = map != null;
- if (mIsRaw) {
- for (Object o : map.entrySet()) {
- Map.Entry entry = (Map.Entry) o;
- String attrName = (String) entry.getKey();
- String attrValue = (String) entry.getValue();
-
- switch (attrName) {
- case TAG_HAS_THUMBNAIL:
- mHasThumbnail = attrValue.equalsIgnoreCase("true");
- break;
- case TAG_THUMBNAIL_OFFSET:
- mThumbnailOffset = Integer.parseInt(attrValue);
- break;
- case TAG_THUMBNAIL_LENGTH:
- mThumbnailLength = Integer.parseInt(attrValue);
- break;
- default:
- mAttributes.put(attrName, attrValue);
- break;
- }
+ FileInputStream in = null;
+ try {
+ if (mFilename != null) {
+ in = new FileInputStream(mFilename);
}
- return;
- }
+ if (mFileDescriptor != null) {
+ in = new FileInputStream(mFileDescriptor);
+ }
+ if (in != null) {
+ // First test whether a given file is a one of RAW format or not.
+ HashMap map = getRawAttributesNative(Os.dup(in.getFD()));
+ mIsRaw = map != null;
+ if (mIsRaw) {
+ for (Object obj : map.entrySet()) {
+ Map.Entry entry = (Map.Entry) obj;
+ String attrName = (String) entry.getKey();
+ String attrValue = (String) entry.getValue();
- // format of string passed from native C code:
- // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
- // example:
- // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
+ switch (attrName) {
+ case TAG_HAS_THUMBNAIL:
+ mHasThumbnail = attrValue.equalsIgnoreCase("true");
+ break;
+ case TAG_THUMBNAIL_OFFSET:
+ mThumbnailOffset = Integer.parseInt(attrValue);
+ break;
+ case TAG_THUMBNAIL_LENGTH:
+ mThumbnailLength = Integer.parseInt(attrValue);
+ break;
+ default:
+ mAttributes.put(attrName, attrValue);
+ break;
+ }
+ }
- String attrStr;
- synchronized (sLock) {
- attrStr = getAttributesNative(mFilename);
+ if (DEBUG) {
+ printAttributes();
+ }
+ return;
+ }
+ }
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(in);
}
- // get count
- int ptr = attrStr.indexOf(' ');
- int count = Integer.parseInt(attrStr.substring(0, ptr));
- // skip past the space between item count and the rest of the attributes
- ++ptr;
-
- for (int i = 0; i < count; i++) {
- // extract the attribute name
- int equalPos = attrStr.indexOf('=', ptr);
- String attrName = attrStr.substring(ptr, equalPos);
- ptr = equalPos + 1; // skip past =
+ try {
+ if (mFileDescriptor != null) {
+ Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
+ }
- // extract the attribute value length
- int lenPos = attrStr.indexOf(' ', ptr);
- int attrLen = Integer.parseInt(attrStr.substring(ptr, lenPos));
- ptr = lenPos + 1; // skip pas the space
+ getJpegAttributes(mInputStream);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(mInputStream);
+ }
- // extract the attribute value
- String attrValue = attrStr.substring(ptr, ptr + attrLen);
- ptr += attrLen;
+ if (DEBUG) {
+ printAttributes();
+ }
+ }
- if (attrName.equals(TAG_HAS_THUMBNAIL)) {
- mHasThumbnail = attrValue.equalsIgnoreCase("true");
- } else {
- mAttributes.put(attrName, attrValue);
- }
+ // Prints out attributes for debugging.
+ private void printAttributes() {
+ Log.d(TAG, "The size of tags: " + mAttributes.size());
+ for (Map.Entry<String, String> entry : mAttributes.entrySet()) {
+ Log.d(TAG, "tagName: " + entry.getKey() + ", tagValue: " + entry.getValue());
}
}
@@ -307,33 +679,63 @@ public class ExifInterface {
throw new UnsupportedOperationException(
"ExifInterface does not support saving attributes on RAW formats.");
}
-
- // format of string passed to native C code:
- // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
- // example:
- // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
- StringBuilder sb = new StringBuilder();
- int size = mAttributes.size();
- if (mAttributes.containsKey(TAG_HAS_THUMBNAIL)) {
- --size;
+ if (mFileDescriptor == null && mFilename == null) {
+ throw new UnsupportedOperationException(
+ "ExifInterface does not support saving attributes for input streams.");
}
- sb.append(size).append(" ");
- for (Map.Entry<String, String> entry : mAttributes.entrySet()) {
- String key = entry.getKey();
- if (key.equals(TAG_HAS_THUMBNAIL)) {
- // this is a fake attribute not saved as an exif tag
- continue;
+
+ // Keep the thumbnail in memory
+ mThumbnailBytes = getThumbnail();
+
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ File tempFile = null;
+ try {
+ // Move the original file to temporary file.
+ if (mFilename != null) {
+ tempFile = new File(mFilename + ".tmp");
+ File originalFile = new File(mFilename);
+ if (!originalFile.renameTo(tempFile)) {
+ throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath());
+ }
+ }
+ if (mFileDescriptor != null) {
+ tempFile = File.createTempFile("temp", "jpg");
+ Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
+ in = new FileInputStream(mFileDescriptor);
+ out = new FileOutputStream(tempFile);
+ Streams.copy(in, out);
}
- String val = entry.getValue();
- sb.append(key).append("=");
- sb.append(val.length()).append(" ");
- sb.append(val);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
}
- String s = sb.toString();
- synchronized (sLock) {
- saveAttributesNative(mFilename, s);
- commitChangesNative(mFilename);
+
+ in = null;
+ out = null;
+ try {
+ // Save the new file.
+ in = new FileInputStream(tempFile);
+ if (mFilename != null) {
+ out = new FileOutputStream(mFilename);
+ }
+ if (mFileDescriptor != null) {
+ Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
+ out = new FileOutputStream(mFileDescriptor);
+ }
+ saveJpegAttributes(in, out);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ tempFile.delete();
}
+
+ // Discard the thumbnail in memory
+ mThumbnailBytes = null;
}
/**
@@ -349,27 +751,41 @@ public class ExifInterface {
* {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}
*/
public byte[] getThumbnail() {
- if (mIsRaw) {
- if (mHasThumbnail) {
- try (RandomAccessFile file = new RandomAccessFile(mFilename, "r")) {
- if (file.length() < mThumbnailLength + mThumbnailOffset) {
- throw new IOException("Corrupted image.");
- }
- file.seek(mThumbnailOffset);
-
- byte[] buffer = new byte[mThumbnailLength];
- file.readFully(buffer);
- return buffer;
- } catch (IOException e) {
- // Couldn't get a thumbnail image.
- }
- }
+ if (!mHasThumbnail) {
return null;
}
+ if (mThumbnailBytes != null) {
+ return mThumbnailBytes;
+ }
- synchronized (sLock) {
- return getThumbnailNative(mFilename);
+ // Read the thumbnail.
+ FileInputStream in = null;
+ try {
+ if (mFileDescriptor != null) {
+ Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
+ in = new FileInputStream(mFileDescriptor);
+ }
+ if (mFilename != null) {
+ in = new FileInputStream(mFilename);
+ }
+ if (in == null) {
+ // Should not be reached this.
+ throw new FileNotFoundException();
+ }
+ if (in.skip(mThumbnailOffset) != mThumbnailOffset) {
+ throw new IOException("Corrupted image");
+ }
+ byte[] buffer = new byte[mThumbnailLength];
+ if (in.read(buffer) != mThumbnailLength) {
+ throw new IOException("Corrupted image");
+ }
+ return buffer;
+ } catch (IOException | ErrnoException e) {
+ // Couldn't get a thumbnail image.
+ } finally {
+ IoUtils.closeQuietly(in);
}
+ return null;
}
/**
@@ -381,16 +797,10 @@ public class ExifInterface {
* @hide
*/
public long[] getThumbnailRange() {
- if (mIsRaw) {
- long[] range = new long[2];
- range[0] = mThumbnailOffset;
- range[1] = mThumbnailLength;
- return range;
- }
-
- synchronized (sLock) {
- return getThumbnailRangeNative(mFilename);
- }
+ long[] range = new long[2];
+ range[0] = mThumbnailOffset;
+ range[1] = mThumbnailLength;
+ return range;
}
/**
@@ -399,10 +809,10 @@ public class ExifInterface {
* Exif tags are not available.
*/
public boolean getLatLong(float output[]) {
- String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE);
- String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF);
- String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE);
- String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
+ String latValue = mAttributes.get(TAG_GPS_LATITUDE);
+ String latRef = mAttributes.get(TAG_GPS_LATITUDE_REF);
+ String lngValue = mAttributes.get(TAG_GPS_LONGITUDE);
+ String lngRef = mAttributes.get(TAG_GPS_LONGITUDE_REF);
if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
try {
@@ -428,7 +838,7 @@ public class ExifInterface {
int ref = getAttributeInt(TAG_GPS_ALTITUDE_REF, -1);
if (altitude >= 0 && ref >= 0) {
- return (double) (altitude * ((ref == 1) ? -1 : 1));
+ return (altitude * ((ref == 1) ? -1 : 1));
} else {
return defaultValue;
}
@@ -461,6 +871,7 @@ public class ExifInterface {
}
msecs += sub;
} catch (NumberFormatException e) {
+ // Ignored
}
}
return msecs;
@@ -493,8 +904,7 @@ public class ExifInterface {
}
}
- private static float convertRationalLatLonToFloat(
- String rationalString, String ref) {
+ private static float convertRationalLatLonToFloat(String rationalString, String ref) {
try {
String [] parts = rationalString.split(",");
@@ -522,22 +932,1062 @@ public class ExifInterface {
}
}
- // JNI methods for JPEG.
- private static native boolean appendThumbnailNative(String fileName,
- String thumbnailFileName);
+ // Loads EXIF attributes from a JPEG input stream.
+ private void getJpegAttributes(InputStream inputStream) throws IOException {
+ // See JPEG File Interchange Format Specification page 5.
+ if (DEBUG) {
+ Log.d(TAG, "getJpegAttributes starting with: " + inputStream);
+ }
+ DataInputStream dataInputStream = new DataInputStream(inputStream);
+ byte marker;
+ int bytesRead = 0;
+ ++bytesRead;
+ if ((marker = dataInputStream.readByte()) != MARKER) {
+ throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
+ }
+ ++bytesRead;
+ if (dataInputStream.readByte() != MARKER_SOI) {
+ throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
+ }
+ while (true) {
+ ++bytesRead;
+ marker = dataInputStream.readByte();
+ if (marker != MARKER) {
+ throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff));
+ }
+ ++bytesRead;
+ marker = dataInputStream.readByte();
+ if (DEBUG) {
+ Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff));
+ }
+
+ // EOI indicates the end of an image and in case of SOS, JPEG image stream starts and
+ // the image data will terminate right after.
+ if (marker == MARKER_EOI || marker == MARKER_SOS) {
+ break;
+ }
+ bytesRead += 2;
+ int length = dataInputStream.readUnsignedShort() - 2;
+ if (length < 0)
+ throw new IOException("Invalid length");
+ bytesRead += length;
+ switch (marker) {
+ case MARKER_APP1: {
+ if (DEBUG) {
+ Log.d(TAG, "MARKER_APP1");
+ }
+ bytesRead -= length;
+ if (length < 6) {
+ throw new IOException("Invalid exif");
+ }
+ byte[] identifier = new byte[6];
+ if (inputStream.read(identifier) != 6) {
+ throw new IOException("Invalid exif");
+ }
+ if (!Arrays.equals(identifier, IDENTIFIER_APP1)) {
+ throw new IOException("Invalid app1 identifier");
+ }
+ bytesRead += 6;
+ length -= 6;
+ if (length <= 0) {
+ throw new IOException("Invalid exif");
+ }
+ byte[] bytes = new byte[length];
+ if (dataInputStream.read(bytes) != length) {
+ throw new IOException("Invalid exif");
+ }
+ readExifSegment(bytes, bytesRead);
+ bytesRead += length;
+ length = 0;
+ break;
+ }
+
+ case MARKER_COM: {
+ byte[] bytes = new byte[length];
+ if (dataInputStream.read(bytes) != length) {
+ throw new IOException("Invalid exif");
+ }
+ mAttributes.put("UserComment",
+ new String(bytes, Charset.forName("US-ASCII")));
+ break;
+ }
+
+ case MARKER_SOF0:
+ case MARKER_SOF1:
+ case MARKER_SOF2:
+ case MARKER_SOF3:
+ case MARKER_SOF5:
+ case MARKER_SOF6:
+ case MARKER_SOF7:
+ case MARKER_SOF9:
+ case MARKER_SOF10:
+ case MARKER_SOF11:
+ case MARKER_SOF13:
+ case MARKER_SOF14:
+ case MARKER_SOF15: {
+ dataInputStream.skipBytes(1);
+ mAttributes.put("ImageLength",
+ String.valueOf(dataInputStream.readUnsignedShort()));
+ mAttributes.put("ImageWidth",
+ String.valueOf(dataInputStream.readUnsignedShort()));
+ length -= 5;
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+ if (length < 0) {
+ throw new IOException("Invalid length");
+ }
+ dataInputStream.skipBytes(length);
+ }
+ }
+
+ // Stores a new JPEG image with EXIF attributes into a given output stream.
+ private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream)
+ throws IOException {
+ // See JPEG File Interchange Format Specification page 5.
+ if (DEBUG) {
+ Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream
+ + ", outputStream: " + outputStream + ")");
+ }
+ DataInputStream dataInputStream = new DataInputStream(inputStream);
+ ExifDataOutputStream dataOutputStream = new ExifDataOutputStream(outputStream);
+ int bytesRead = 0;
+ ++bytesRead;
+ if (dataInputStream.readByte() != MARKER) {
+ throw new IOException("Invalid marker");
+ }
+ dataOutputStream.writeByte(MARKER);
+ ++bytesRead;
+ if (dataInputStream.readByte() != MARKER_SOI) {
+ throw new IOException("Invalid marker");
+ }
+ dataOutputStream.writeByte(MARKER_SOI);
+
+ byte[] bytes = new byte[4096];
+
+ while (true) {
+ ++bytesRead;
+ if (dataInputStream.readByte() != MARKER) {
+ throw new IOException("Invalid marker");
+ }
+ dataOutputStream.writeByte(MARKER);
+ ++bytesRead;
+ byte marker = dataInputStream.readByte();
+ dataOutputStream.writeByte(marker);
+ switch (marker) {
+ case MARKER_APP1: {
+ // Rewrite EXIF segment
+ int length = dataInputStream.readUnsignedShort() - 2;
+ if (length < 0)
+ throw new IOException("Invalid length");
+ bytesRead += 2;
+ int read;
+ while ((read = dataInputStream.read(
+ bytes, 0, Math.min(length, bytes.length))) > 0) {
+ length -= read;
+ }
+ bytesRead += length;
+ writeExifSegment(dataOutputStream, bytesRead);
+ break;
+ }
+ case MARKER_EOI:
+ case MARKER_SOS: {
+ // Copy all the remaining data
+ Streams.copy(dataInputStream, dataOutputStream);
+ return;
+ }
+ default: {
+ // Copy JPEG segment
+ int length = dataInputStream.readUnsignedShort();
+ dataOutputStream.writeUnsignedShort(length);
+ if (length < 0)
+ throw new IOException("Invalid length");
+ length -= 2;
+ bytesRead += 2;
+ int read;
+ while ((read = dataInputStream.read(
+ bytes, 0, Math.min(length, bytes.length))) > 0) {
+ dataOutputStream.write(bytes, 0, read);
+ length -= read;
+ }
+ bytesRead += length;
+ break;
+ }
+ }
+ }
+ }
+
+ // Reads the given EXIF byte area and save its tag data into attributes.
+ private void readExifSegment(byte[] exifBytes, int exifOffsetFromBeginning) throws IOException {
+ // Parse TIFF Headers. See JEITA CP-3451C Table 1. page 10.
+ ByteOrderAwarenessDataInputStream dataInputStream =
+ new ByteOrderAwarenessDataInputStream(exifBytes);
+
+ // Read byte align
+ short byteOrder = dataInputStream.readShort();
+ switch (byteOrder) {
+ case BYTE_ALIGN_II:
+ if (DEBUG) {
+ Log.d(TAG, "readExifSegment: Byte Align II");
+ }
+ dataInputStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+ break;
+ case BYTE_ALIGN_MM:
+ if (DEBUG) {
+ Log.d(TAG, "readExifSegment: Byte Align MM");
+ }
+ dataInputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+ break;
+ default:
+ throw new IOException("Invalid byte order: " + Integer.toHexString(byteOrder));
+ }
+
+ int startCode = dataInputStream.readUnsignedShort();
+ if (startCode != 0x2a) {
+ throw new IOException("Invalid exif start: " + Integer.toHexString(startCode));
+ }
+
+ // Read first ifd offset
+ long firstIfdOffset = dataInputStream.readUnsignedInt();
+ if (firstIfdOffset < 8 || firstIfdOffset >= exifBytes.length) {
+ throw new IOException("Invalid first Ifd offset: " + firstIfdOffset);
+ }
+ firstIfdOffset -= 8;
+ if (firstIfdOffset > 0) {
+ if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset)
+ throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
+ }
+
+ // Read primary image TIFF image file directory.
+ readImageFileDirectory(dataInputStream, IFD_TIFF_HINT);
+
+ // Process thumbnail.
+ try {
+ int jpegInterchangeFormat = Integer.parseInt(
+ mAttributes.get(JPEG_INTERCHANGE_FORMAT_TAG.name));
+ int jpegInterchangeFormatLength = Integer.parseInt(
+ mAttributes.get(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name));
+ // The following code limits the size of thumbnail size not to overflow EXIF data area.
+ jpegInterchangeFormatLength = Math.min(jpegInterchangeFormat
+ + jpegInterchangeFormatLength, exifOffsetFromBeginning + exifBytes.length)
+ - jpegInterchangeFormat;
+ if (jpegInterchangeFormat > 0 && jpegInterchangeFormatLength > 0) {
+ mHasThumbnail = true;
+ mThumbnailOffset = exifOffsetFromBeginning + jpegInterchangeFormat;
+ mThumbnailLength = jpegInterchangeFormatLength;
+
+ // Do not store a thumbnail in memory if the given input can be re-read.
+ if (mFileDescriptor == null && mFilename == null) {
+ byte[] thumbnailBytes = new byte[jpegInterchangeFormatLength];
+ dataInputStream.seek(jpegInterchangeFormat);
+ dataInputStream.readFully(thumbnailBytes);
+ mThumbnailBytes = thumbnailBytes;
+
+ if (DEBUG) {
+ Bitmap bitmap = BitmapFactory.decodeByteArray(
+ thumbnailBytes, 0, thumbnailBytes.length);
+ Log.d(TAG, "Thumbnail offset: " + mThumbnailOffset + ", length: "
+ + mThumbnailLength + ", width: " + bitmap.getWidth() + ", height: "
+ + bitmap.getHeight());
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ // Ignored the corrupted image.
+ }
+
+ // For compatibility, keep data formats as follows.
+ convertToInt(TAG_IMAGE_WIDTH);
+ convertToInt(TAG_IMAGE_LENGTH);
+ convertToInt(TAG_ORIENTATION);
+ convertToInt(TAG_FLASH);
+ convertToRational(TAG_FOCAL_LENGTH);
+ convertToDouble(TAG_DIGITAL_ZOOM_RATIO);
+ convertToDouble(TAG_EXPOSURE_TIME);
+ convertToDouble(TAG_APERTURE);
+ convertToDouble(TAG_SUBJECT_DISTANCE);
+ convertToInt(TAG_ISO);
+ convertToDouble(TAG_EXPOSURE_BIAS_VALUE);
+ convertToInt(TAG_WHITE_BALANCE);
+ convertToInt(TAG_LIGHT_SOURCE);
+ convertToInt(TAG_METERING_MODE);
+ convertToInt(TAG_EXPOSURE_PROGRAM);
+ convertToInt(TAG_EXPOSURE_MODE);
+ convertToRational(TAG_GPS_ALTITUDE);
+ convertToInt(TAG_GPS_ALTITUDE_REF);
+ convertToRational(TAG_GPS_LONGITUDE);
+ convertToRational(TAG_GPS_LATITUDE);
+ convertToTimetamp(TAG_GPS_TIMESTAMP);
+
+ // The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag.
+ String valueOfDateTimeOriginal = mAttributes.get("DateTimeOriginal");
+ if (valueOfDateTimeOriginal != null) {
+ mAttributes.put(TAG_DATETIME, valueOfDateTimeOriginal);
+ }
+
+ // Add the default value.
+ if (!mAttributes.containsKey(TAG_IMAGE_WIDTH)) {
+ mAttributes.put(TAG_IMAGE_WIDTH, "0");
+ }
+ if (!mAttributes.containsKey(TAG_IMAGE_LENGTH)) {
+ mAttributes.put(TAG_IMAGE_LENGTH, "0");
+ }
+ if (!mAttributes.containsKey(TAG_ORIENTATION)) {
+ mAttributes.put(TAG_ORIENTATION, "0");
+ }
+ if (!mAttributes.containsKey(TAG_LIGHT_SOURCE)) {
+ mAttributes.put(TAG_LIGHT_SOURCE, "0");
+ }
+ }
+
+ // Converts the tag value to timestamp; Otherwise deletes the given tag.
+ private void convertToTimetamp(String tagName) {
+ String entryValue = mAttributes.get(tagName);
+ if (entryValue == null) return;
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ String[] components = entryValue.split(",");
+ if (dataFormat == IFD_FORMAT_SRATIONAL && components.length == 3) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (String component : components) {
+ if (stringBuilder.length() > 0) {
+ stringBuilder.append(":");
+ }
+ String[] rationalNumber = component.split("/");
+ int numerator = Integer.parseInt(rationalNumber[0]);
+ int denominator = Integer.parseInt(rationalNumber[1]);
+ if (denominator == 0) {
+ numerator = 0;
+ denominator = 1;
+ }
+ int value = numerator / denominator;
+ stringBuilder.append(String.format("%02d", value));
+ }
+ mAttributes.put(tagName, stringBuilder.toString());
+ } else if (dataFormat != IFD_FORMAT_STRING) {
+ mAttributes.remove(tagName);
+ }
+ }
+
+ // Checks the tag value of a given tag formatted in double type; Otherwise try to convert it to
+ // double type or delete it.
+ private void convertToDouble(String tagName) {
+ String entryValue = mAttributes.get(tagName);
+ if (entryValue == null) return;
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ switch (dataFormat) {
+ case IFD_FORMAT_SRATIONAL: {
+ StringBuilder stringBuilder = new StringBuilder();
+ String[] components = entryValue.split(",");
+ for (String component : components) {
+ if (stringBuilder.length() > 0) {
+ stringBuilder.append(",");
+ }
+ String[] rationalNumber = component.split("/");
+ int numerator = Integer.parseInt(rationalNumber[0]);
+ int denominator = Integer.parseInt(rationalNumber[1]);
+ if (denominator == 0) {
+ numerator = 0;
+ denominator = 1;
+ }
+ stringBuilder.append((double) numerator / denominator);
+ }
+ mAttributes.put(tagName, stringBuilder.toString());
+ break;
+ }
+ case IFD_FORMAT_DOUBLE:
+ // Keep it as is.
+ break;
+ default:
+ mAttributes.remove(tagName);
+ break;
+ }
+ }
+
+ // Checks the tag value of a given tag formatted in int type; Otherwise deletes the tag value.
+ private void convertToRational(String tagName) {
+ String entryValue = mAttributes.get(tagName);
+ if (entryValue == null) return;
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ switch (dataFormat) {
+ case IFD_FORMAT_SLONG:
+ case IFD_FORMAT_DOUBLE: {
+ StringBuilder stringBuilder = new StringBuilder();
+ String[] components = entryValue.split(",");
+ for (String component : components) {
+ if (stringBuilder.length() > 0) {
+ stringBuilder.append(",");
+ }
+ double doubleValue = Double.parseDouble(component);
+ stringBuilder.append((int) (doubleValue * 10000.0)).append("/").append(10000);
+ }
+ mAttributes.put(tagName, stringBuilder.toString());
+ break;
+ }
+ case IFD_FORMAT_SRATIONAL:
+ // Keep it as is.
+ break;
+ default:
+ mAttributes.remove(tagName);
+ break;
+ }
+ }
+
+ // Checks the tag value of a given tag formatted in int type; Otherwise deletes the tag value.
+ private void convertToInt(String tagName) {
+ String entryValue = mAttributes.get(tagName);
+ if (entryValue == null) return;
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ if (dataFormat != IFD_FORMAT_SLONG) {
+ mAttributes.remove(tagName);
+ }
+ }
+
+ // Reads image file directory, which is a tag group in EXIF.
+ private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream, int hint)
+ throws IOException {
+ // See JEITA CP-3451 Figure 5. page 9.
+ short numberOfDirectoryEntry = dataInputStream.readShort();
+
+ if (DEBUG) {
+ Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
+ }
+
+ for (short i = 0; i < numberOfDirectoryEntry; ++i) {
+ int tagNumber = dataInputStream.readUnsignedShort();
+ int dataFormat = dataInputStream.readUnsignedShort();
+ int numberOfComponents = dataInputStream.readInt();
+ long nextEntryOffset = dataInputStream.peek() + 4; // next four bytes is for data
+ // offset or value.
+
+ if (DEBUG) {
+ Log.d(TAG, String.format("tagNumber: %d, dataFormat: %d, numberOfComponents: %d",
+ tagNumber, dataFormat, numberOfComponents));
+ }
+
+ // Read a value from data field or seek to the value offset which is stored in data
+ // field if the size of the entry value is bigger than 4.
+ int byteCount = numberOfComponents * IFD_FORMAT_BYTES_PER_FORMAT[dataFormat];
+ if (byteCount > 4) {
+ long offset = dataInputStream.readUnsignedInt();
+ if (DEBUG) {
+ Log.d(TAG, "seek to data offset: " + offset);
+ }
+ dataInputStream.seek(offset);
+ }
+
+ // Look up a corresponding tag from tag number
+ String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber);
+ // Skip if the parsed tag number is not defined.
+ if (tagName == null) {
+ dataInputStream.seek(nextEntryOffset);
+ continue;
+ }
+
+ // Recursively parse IFD when a IFD pointer tag appears.
+ int innerIfdHint = getIfdHintFromTagNumber(tagNumber);
+ if (innerIfdHint >= 0) {
+ long offset = -1L;
+ // Get offset from data field
+ switch (dataFormat) {
+ case IFD_FORMAT_USHORT: {
+ offset = dataInputStream.readUnsignedShort();
+ break;
+ }
+ case IFD_FORMAT_SSHORT: {
+ offset = dataInputStream.readShort();
+ break;
+ }
+ case IFD_FORMAT_ULONG: {
+ offset = dataInputStream.readUnsignedInt();
+ break;
+ }
+ case IFD_FORMAT_SLONG: {
+ offset = dataInputStream.readInt();
+ break;
+ }
+ default: {
+ // Nothing to do
+ break;
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tagName));
+ }
+ if (offset > 0L) {
+ dataInputStream.seek(offset);
+ readImageFileDirectory(dataInputStream, innerIfdHint);
+ }
+
+ dataInputStream.seek(nextEntryOffset);
+ continue;
+ }
+
+ if (numberOfComponents == 1 || dataFormat == IFD_FORMAT_STRING
+ || dataFormat == IFD_FORMAT_UNDEFINED) {
+ String entryValue = readExifEntryValue(
+ dataInputStream, dataFormat, numberOfComponents);
+ if (entryValue != null) {
+ mAttributes.put(tagName, entryValue);
+ }
+ } else {
+ StringBuilder entryValueBuilder = new StringBuilder();
+ for (int c = 0; c < numberOfComponents; ++c) {
+ if (entryValueBuilder.length() > 0) {
+ entryValueBuilder.append(",");
+ }
+ entryValueBuilder.append(readExifEntryValue(
+ dataInputStream, dataFormat, numberOfComponents));
+ }
+ mAttributes.put(tagName, entryValueBuilder.toString());
+ }
+
+ if (dataInputStream.peek() != nextEntryOffset) {
+ dataInputStream.seek(nextEntryOffset);
+ }
+ }
- private static native void saveAttributesNative(String fileName,
- String compressedAttributes);
+ long nextIfdOffset = dataInputStream.readUnsignedInt();
+ if (DEBUG) {
+ Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
+ }
+ // The next IFD offset needs to be bigger than 8 since the first IFD offset is at least 8.
+ if (nextIfdOffset > 8) {
+ dataInputStream.seek(nextIfdOffset);
+ readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
+ }
+ }
+
+ // Reads a value from where the entry value are stored.
+ private String readExifEntryValue(ByteOrderAwarenessDataInputStream dataInputStream,
+ int dataFormat, int numberOfComponents) throws IOException {
+ // See TIFF 6.0 spec Types. page 15.
+ switch (dataFormat) {
+ case IFD_FORMAT_BYTE: {
+ return String.valueOf(dataInputStream.readByte());
+ }
+ case IFD_FORMAT_SBYTE: {
+ return String.valueOf(dataInputStream.readByte() & 0xff);
+ }
+ case IFD_FORMAT_USHORT: {
+ return String.valueOf(dataInputStream.readUnsignedShort());
+ }
+ case IFD_FORMAT_SSHORT: {
+ return String.valueOf(dataInputStream.readUnsignedInt());
+ }
+ case IFD_FORMAT_ULONG: {
+ return String.valueOf(dataInputStream.readInt());
+ }
+ case IFD_FORMAT_SLONG: {
+ return String.valueOf(dataInputStream.readInt());
+ }
+ case IFD_FORMAT_URATIONAL:
+ case IFD_FORMAT_SRATIONAL: {
+ int numerator = dataInputStream.readInt();
+ int denominator = dataInputStream.readInt();
+ return numerator + "/" + denominator;
+ }
+ case IFD_FORMAT_SINGLE: {
+ return String.valueOf(dataInputStream.readFloat());
+ }
+ case IFD_FORMAT_DOUBLE: {
+ return String.valueOf(dataInputStream.readDouble());
+ }
+ case IFD_FORMAT_UNDEFINED: // Usually UNDEFINED format is ASCII.
+ case IFD_FORMAT_STRING: {
+ byte[] bytes = new byte[numberOfComponents];
+ dataInputStream.readFully(bytes);
+ int index = 0;
+ if (numberOfComponents >= EXIF_ASCII_PREFIX.length) {
+ boolean same = true;
+ for (int i = 0; i < EXIF_ASCII_PREFIX.length; ++i) {
+ if (bytes[i] != EXIF_ASCII_PREFIX[i]) {
+ same = false;
+ break;
+ }
+ }
+ if (same) {
+ index = EXIF_ASCII_PREFIX.length;
+ }
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ while (true) {
+ int ch = bytes[index];
+ if (ch < 0)
+ throw new EOFException();
+ if (ch == 0)
+ break;
+ if (ch >= 32)
+ stringBuilder.append((char) ch);
+ else
+ stringBuilder.append('?');
+ ++index;
+ if (index == numberOfComponents)
+ break;
+ }
+ return stringBuilder.toString();
+ }
+ default: {
+ // Nothing to do
+ return null;
+ }
+ }
+ }
+
+ // Gets the corresponding IFD group index of the given tag number for writing Exif Tags.
+ private static int getIfdHintFromTagNumber(int tagNumber) {
+ for (int i = 0; i < IFD_POINTER_TAG_HINTS.length; ++i) {
+ if (IFD_POINTER_TAGS[i].number == tagNumber)
+ return IFD_POINTER_TAG_HINTS[i];
+ }
+ return -1;
+ }
+
+ // Writes an Exif segment into the given output stream.
+ private int writeExifSegment(ExifDataOutputStream dataOutputStream, int exifOffsetFromBeginning)
+ throws IOException {
+ // The following variables are for calculating each IFD tag group size in bytes.
+ int[] ifdOffsets = new int[EXIF_TAGS.length];
+ int[] ifdDataSizes = new int[EXIF_TAGS.length];
+
+ // Maps to store tags per IFD tag group
+ HashMap[] ifdTags = new HashMap[EXIF_TAGS.length];
+ for (int i = 0; i < EXIF_TAGS.length; ++i) {
+ ifdTags[i] = new HashMap();
+ }
- private static native String getAttributesNative(String fileName);
+ // Remove IFD pointer tags (we'll re-add it later.)
+ for (ExifTag tag : IFD_POINTER_TAGS) {
+ mAttributes.remove(tag.name);
+ }
- private static native void commitChangesNative(String fileName);
+ // Assign tags to the corresponding group
+ for (Map.Entry<String, String> entry : mAttributes.entrySet()) {
+ Pair<Integer, Integer> pair = sExifTagMapForWriting.get(entry.getKey());
+ if (pair != null) {
+ int tagNumber = pair.first;
+ int hint = pair.second;
+ ifdTags[hint].put(tagNumber, entry.getValue());
+ }
+ }
- private static native byte[] getThumbnailNative(String fileName);
+ // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD
+ // offset when there is one or more tags in the thumbnail IFD.
+ if (!ifdTags[IFD_INTEROPERABILITY_HINT].isEmpty()) {
+ ifdTags[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].number, "0");
+ }
+ if (!ifdTags[IFD_EXIF_HINT].isEmpty()) {
+ ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].number, "0");
+ }
+ if (!ifdTags[IFD_GPS_HINT].isEmpty()) {
+ ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].number, "0");
+ }
+ if (mHasThumbnail) {
+ ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.number, "0");
+ ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.number,
+ String.valueOf(mThumbnailLength));
+ }
+
+ // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry
+ // value which has a bigger size than 4 bytes.
+ for (int i = 0; i < 5; ++i) {
+ int sum = 0;
+ for (Object entry : ifdTags[i].entrySet()) {
+ String entryValue = (String) ((Map.Entry) entry).getValue();
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ int size = getSizeOfExifEntryValue(dataFormat, entryValue);
+ if (size > 4) {
+ sum += size;
+ }
+ }
+ ifdDataSizes[i] += sum;
+ }
+
+ // Calculate IFD offsets.
+ int position = 8;
+ for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+ if (!ifdTags[hint].isEmpty()) {
+ ifdOffsets[hint] = position;
+ position += 2 + ifdTags[hint].size() * 12 + 4 + ifdDataSizes[hint];
+ }
+ }
+ if (mHasThumbnail) {
+ int thumbnailOffset = position;
+ ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.number,
+ String.valueOf(thumbnailOffset));
+ ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.number,
+ String.valueOf(mThumbnailLength));
+ mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
+ position += mThumbnailLength;
+ }
- private static native long[] getThumbnailRangeNative(String fileName);
+ // Calculate the total size
+ int totalSize = position + 8; // eight bytes is for header part.
+ if (DEBUG) {
+ Log.d(TAG, "totalSize length: " + totalSize);
+ for (int i = 0; i < 5; ++i) {
+ Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d",
+ i, ifdOffsets[i], ifdTags[i].size(), ifdDataSizes[i]));
+ }
+ }
+
+ // Update IFD pointer tags with the calculated offsets.
+ if (!ifdTags[IFD_EXIF_HINT].isEmpty()) {
+ ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].number,
+ String.valueOf(ifdOffsets[IFD_EXIF_HINT]));
+ }
+ if (!ifdTags[IFD_GPS_HINT].isEmpty()) {
+ ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].number,
+ String.valueOf(ifdOffsets[IFD_GPS_HINT]));
+ }
+ if (!ifdTags[IFD_INTEROPERABILITY_HINT].isEmpty()) {
+ ifdTags[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].number,
+ String.valueOf(ifdOffsets[IFD_INTEROPERABILITY_HINT]));
+ }
+
+ // Write TIFF Headers. See JEITA CP-3451C Table 1. page 10.
+ dataOutputStream.writeUnsignedShort(totalSize);
+ dataOutputStream.write(IDENTIFIER_APP1);
+ dataOutputStream.writeShort(BYTE_ALIGN_MM);
+ dataOutputStream.writeUnsignedShort(0x2a);
+ dataOutputStream.writeUnsignedInt(8);
+
+ // Write IFD groups. See JEITA CP-3451C Figure 7. page 12.
+ for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+ if (!ifdTags[hint].isEmpty()) {
+ // See JEITA CP-3451C 4.6.2 IFD structure. page 13.
+ // Write entry count
+ dataOutputStream.writeUnsignedShort(ifdTags[hint].size());
+
+ // Write entry info
+ int dataOffset = ifdOffsets[hint] + 2 + ifdTags[hint].size() * 12 + 4;
+ for (Object obj : ifdTags[hint].entrySet()) {
+ Map.Entry entry = (Map.Entry) obj;
+ int tagNumber = (int) entry.getKey();
+ String entryValue = (String) entry.getValue();
+
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ int numberOfComponents = getNumberOfComponentsInExifEntryValue(dataFormat,
+ entryValue);
+ int byteCount = getSizeOfExifEntryValue(dataFormat, entryValue);
+
+ dataOutputStream.writeUnsignedShort(tagNumber);
+ dataOutputStream.writeUnsignedShort(dataFormat);
+ dataOutputStream.writeInt(numberOfComponents);
+ if (byteCount > 4) {
+ dataOutputStream.writeUnsignedInt(dataOffset);
+ dataOffset += byteCount;
+ } else {
+ int bytesWritten = writeExifEntryValue(dataOutputStream, entryValue);
+ // Fill zero up to 4 bytes
+ if (bytesWritten < 4) {
+ for (int i = bytesWritten; i < 4; ++i) {
+ dataOutputStream.write(0);
+ }
+ }
+ }
+ }
+
+ // Write the next offset. It writes the offset of thumbnail IFD if there is one or
+ // more tags in the thumbnail IFD when the current IFD is the primary image TIFF
+ // IFD; Otherwise 0.
+ if (hint == 0 && !ifdTags[IFD_THUMBNAIL_HINT].isEmpty()) {
+ dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_THUMBNAIL_HINT]);
+ } else {
+ dataOutputStream.writeUnsignedInt(0);
+ }
+
+ // Write values of data field exceeding 4 bytes after the next offset.
+ for (Object obj : ifdTags[hint].entrySet()) {
+ Map.Entry entry = (Map.Entry) obj;
+ String entryValue = (String) entry.getValue();
+
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+ int byteCount = getSizeOfExifEntryValue(dataFormat, entryValue);
+ if (byteCount > 4) {
+ writeExifEntryValue(dataOutputStream, entryValue);
+ }
+ }
+ }
+ }
+
+ // Write thumbnail
+ if (mHasThumbnail) {
+ dataOutputStream.write(getThumbnail());
+ }
+
+ return totalSize;
+ }
+
+ // Writes EXIF entry value and its entry value type will be automatically determined.
+ private static int writeExifEntryValue(ExifDataOutputStream dataOutputStream, String entryValue)
+ throws IOException {
+ int bytesWritten = 0;
+ int dataFormat = getDataFormatOfExifEntryValue(entryValue);
+
+ // Values can be composed of several components. Each component is separated by char ','.
+ String[] components = entryValue.split(",");
+ for (String component : components) {
+ switch (dataFormat) {
+ case IFD_FORMAT_SLONG:
+ dataOutputStream.writeInt(Integer.parseInt(component));
+ bytesWritten += 4;
+ break;
+ case IFD_FORMAT_DOUBLE:
+ dataOutputStream.writeDouble(Double.parseDouble(component));
+ bytesWritten += 8;
+ break;
+ case IFD_FORMAT_STRING:
+ byte[] asciiArray = (component + '\0').getBytes(Charset.forName("US-ASCII"));
+ dataOutputStream.write(asciiArray);
+ bytesWritten += asciiArray.length;
+ break;
+ case IFD_FORMAT_SRATIONAL:
+ String[] rationalNumber = component.split("/");
+ dataOutputStream.writeInt(Integer.parseInt(rationalNumber[0]));
+ dataOutputStream.writeInt(Integer.parseInt(rationalNumber[1]));
+ bytesWritten += 8;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+ return bytesWritten;
+ }
+
+ // Determines the data format of EXIF entry value.
+ private static int getDataFormatOfExifEntryValue(String entryValue) {
+ // See TIFF 6.0 spec Types. page 15.
+ // Take the first component if there are more than one component.
+ if (entryValue.contains(",")) {
+ entryValue = entryValue.split(",")[0];
+ }
+
+ if (entryValue.contains("/")) {
+ return IFD_FORMAT_SRATIONAL;
+ }
+ try {
+ Integer.parseInt(entryValue);
+ return IFD_FORMAT_SLONG;
+ } catch (NumberFormatException e) {
+ // Ignored
+ }
+ try {
+ Double.parseDouble(entryValue);
+ return IFD_FORMAT_DOUBLE;
+ } catch (NumberFormatException e) {
+ // Ignored
+ }
+ return IFD_FORMAT_STRING;
+ }
+
+ // Determines the size of EXIF entry value.
+ private static int getSizeOfExifEntryValue(int dataFormat, String entryValue) {
+ // See TIFF 6.0 spec Types page 15.
+ int bytesEstimated = 0;
+ String[] components = entryValue.split(",");
+ for (String component : components) {
+ switch (dataFormat) {
+ case IFD_FORMAT_SLONG:
+ bytesEstimated += 4;
+ break;
+ case IFD_FORMAT_DOUBLE:
+ bytesEstimated += 8;
+ break;
+ case IFD_FORMAT_STRING:
+ bytesEstimated
+ += (component + '\0').getBytes(Charset.forName("US-ASCII")).length;
+ break;
+ case IFD_FORMAT_SRATIONAL:
+ bytesEstimated += 8;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+ return bytesEstimated;
+ }
+
+ // Determines the number of components of EXIF entry value.
+ private static int getNumberOfComponentsInExifEntryValue(int dataFormat, String entryValue) {
+ if (dataFormat == IFD_FORMAT_STRING) {
+ return (entryValue + '\0').getBytes(Charset.forName("US-ASCII")).length;
+ }
+ int count = 1;
+ for (int i = 0; i < entryValue.length(); ++i) {
+ if (entryValue.charAt(i) == ',') {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ // An input stream to parse EXIF data area, which can be written in either little or big endian
+ // order.
+ private static class ByteOrderAwarenessDataInputStream extends ByteArrayInputStream {
+ private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
+ private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
+
+ private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
+ private final long mLength;
+ private long mPosition;
+
+ public ByteOrderAwarenessDataInputStream(byte[] bytes) {
+ super(bytes);
+ mLength = bytes.length;
+ mPosition = 0L;
+ }
+
+ public void setByteOrder(ByteOrder byteOrder) {
+ mByteOrder = byteOrder;
+ }
+
+ public void seek(long byteCount) throws IOException {
+ mPosition = 0L;
+ reset();
+ if (skip(byteCount) != byteCount)
+ throw new IOException("Couldn't seek up to the byteCount");
+ }
+
+ public long peek() {
+ return mPosition;
+ }
+
+ public void readFully(byte[] buffer) throws IOException {
+ mPosition += buffer.length;
+ if (mPosition > mLength)
+ throw new EOFException();
+ if (super.read(buffer, 0, buffer.length) != buffer.length) {
+ throw new IOException("Couldn't read up to the length of buffer");
+ }
+ }
+
+ public byte readByte() throws IOException {
+ ++mPosition;
+ if (mPosition > mLength)
+ throw new EOFException();
+ int ch = super.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (byte) ch;
+ }
+
+ public short readShort() throws IOException {
+ mPosition += 2;
+ if (mPosition > mLength)
+ throw new EOFException();
+ int ch1 = super.read();
+ int ch2 = super.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ if (mByteOrder == LITTLE_ENDIAN) {
+ return (short) ((ch2 << 8) + (ch1));
+ } else if (mByteOrder == BIG_ENDIAN) {
+ return (short) ((ch1 << 8) + (ch2));
+ }
+ throw new IOException("Invalid byte order: " + mByteOrder);
+ }
+
+ public int readInt() throws IOException {
+ mPosition += 4;
+ if (mPosition > mLength)
+ throw new EOFException();
+ int ch1 = super.read();
+ int ch2 = super.read();
+ int ch3 = super.read();
+ int ch4 = super.read();
+ if ((ch1 | ch2 | ch3 | ch4) < 0)
+ throw new EOFException();
+ if (mByteOrder == LITTLE_ENDIAN) {
+ return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1);
+ } else if (mByteOrder == BIG_ENDIAN) {
+ return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
+ }
+ throw new IOException("Invalid byte order: " + mByteOrder);
+ }
+
+ @Override
+ public long skip(long byteCount) {
+ long skipped = super.skip(Math.min(byteCount, mLength - mPosition));
+ mPosition += skipped;
+ return skipped;
+ }
+
+ public int readUnsignedShort() throws IOException {
+ mPosition += 2;
+ if (mPosition > mLength)
+ throw new EOFException();
+ int ch1 = super.read();
+ int ch2 = super.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ if (mByteOrder == LITTLE_ENDIAN) {
+ return ((ch2 << 8) + (ch1));
+ } else if (mByteOrder == BIG_ENDIAN) {
+ return ((ch1 << 8) + (ch2));
+ }
+ throw new IOException("Invalid byte order: " + mByteOrder);
+ }
+
+ public long readUnsignedInt() throws IOException {
+ return readInt() & 0xffffffffL;
+ }
+
+ public long readLong() throws IOException {
+ mPosition += 8;
+ if (mPosition > mLength)
+ throw new EOFException();
+ int ch1 = super.read();
+ int ch2 = super.read();
+ int ch3 = super.read();
+ int ch4 = super.read();
+ int ch5 = super.read();
+ int ch6 = super.read();
+ int ch7 = super.read();
+ int ch8 = super.read();
+ if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0)
+ throw new EOFException();
+ if (mByteOrder == LITTLE_ENDIAN) {
+ return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40)
+ + ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16)
+ + ((long) ch2 << 8) + (long) ch1);
+ } else if (mByteOrder == BIG_ENDIAN) {
+ return (((long) ch1 << 56) + ((long) ch2 << 48) + ((long) ch3 << 40)
+ + ((long) ch4 << 32) + ((long) ch5 << 24) + ((long) ch6 << 16)
+ + ((long) ch7 << 8) + (long) ch8);
+ }
+ throw new IOException("Invalid byte order: " + mByteOrder);
+ }
+
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readLong());
+ }
+ }
+
+ // An output stream to write EXIF data area, that will be written in big endian byte order.
+ private static class ExifDataOutputStream extends DataOutputStream {
+ public ExifDataOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public void writeUnsignedShort(int val) throws IOException {
+ writeShort((short) val);
+ }
+
+ public void writeUnsignedInt(long val) throws IOException {
+ writeInt((int) val);
+ }
+ }
// JNI methods for RAW formats.
private static native void initRawNative();
- private static native HashMap getRawAttributesNative(String filename);
+ private static native HashMap getRawAttributesNative(FileDescriptor fileDescriptor);
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index abe92c727cc5..987a8b6a48ee 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -54,10 +54,6 @@ interface IAudioService {
void setMasterMute(boolean mute, int flags, String callingPackage, int userId);
- boolean isMasterMono();
-
- void setMasterMono(boolean mute, String callingPackage, int userId);
-
int getStreamVolume(int streamType);
int getStreamMinVolume(int streamType);
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 397ab15c5aba..c08f4bf0eb19 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -153,6 +153,7 @@ public class ImageReader implements AutoCloseable {
mSurface = nativeGetSurface();
+ mIsReaderValid = true;
// Estimate the native buffer allocation size and register it so it gets accounted for
// during GC. Note that this doesn't include the buffers required by the buffer queue
// itself and the buffers requested by the producer.
@@ -326,7 +327,11 @@ public class ImageReader implements AutoCloseable {
*/
private int acquireNextSurfaceImage(SurfaceImage si) {
synchronized (mCloseLock) {
- int status = nativeImageSetup(si);
+ // A null image will eventually be returned if ImageReader is already closed.
+ int status = ACQUIRE_NO_BUFS;
+ if (mIsReaderValid) {
+ status = nativeImageSetup(si);
+ }
switch (status) {
case ACQUIRE_SUCCESS:
@@ -498,6 +503,7 @@ public class ImageReader implements AutoCloseable {
* acquire operations.
*/
synchronized (mCloseLock) {
+ mIsReaderValid = false;
for (Image image : mAcquiredImages) {
image.close();
}
@@ -613,6 +619,7 @@ public class ImageReader implements AutoCloseable {
private final Object mListenerLock = new Object();
private final Object mCloseLock = new Object();
+ private boolean mIsReaderValid = false;
private OnImageAvailableListener mListener;
private ListenerHandler mListenerHandler;
// Keep track of the successfully acquired Images. This need to be thread safe as the images
@@ -638,7 +645,14 @@ public class ImageReader implements AutoCloseable {
synchronized (mListenerLock) {
listener = mListener;
}
- if (listener != null) {
+
+ // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
+ // closed, as application could acquire next image in the onImageAvailable() callback.
+ boolean isReaderValid = false;
+ synchronized (mCloseLock) {
+ isReaderValid = mIsReaderValid;
+ }
+ if (listener != null && isReaderValid) {
listener.onImageAvailable(ImageReader.this);
}
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index d06da975d0f7..646ab4ef1804 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -65,6 +65,7 @@ import java.util.Map;
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
* <tr><td>{@link #KEY_CHANNEL_COUNT}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_SAMPLE_RATE}</td><td>Integer</td><td></td></tr>
+ * <tr><td>{@link #KEY_PCM_ENCODING}</td><td>Integer</td><td>optional</td></tr>
* <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if <em>decoding</em> AAC audio content, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr>
* <tr><td>{@link #KEY_AAC_PROFILE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired profile.</td></tr>
* <tr><td>{@link #KEY_AAC_SBR_MODE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired SBR mode.</td></tr>
@@ -197,6 +198,26 @@ public final class MediaFormat {
public static final String KEY_FRAME_RATE = "frame-rate";
/**
+ * A key describing the raw audio sample encoding/format.
+ *
+ * <p>The associated value is an integer, using one of the
+ * {@link AudioFormat}.ENCODING_PCM_ values.</p>
+ *
+ * <p>This is an optional key for audio decoders and encoders specifying the
+ * desired raw audio sample format during {@link MediaCodec#configure
+ * MediaCodec.configure(&hellip;)} call. Use {@link MediaCodec#getInputFormat
+ * MediaCodec.getInput}/{@link MediaCodec#getOutputFormat OutputFormat(&hellip;)}
+ * to confirm the actual format. For the PCM decoder this key specifies both
+ * input and output sample encodings.</p>
+ *
+ * <p>This key is also used by {@link MediaExtractor} to specify the sample
+ * format of audio data, if it is specified.</p>
+ *
+ * <p>If this key is missing, the raw audio sample format is signed 16-bit short.</p>
+ */
+ public static final String KEY_PCM_ENCODING = "pcm-encoding";
+
+ /**
* A key describing the capture rate of a video format in frames/sec.
* <p>
* When capture rate is different than the frame rate, it means that the
@@ -564,7 +585,7 @@ public final class MediaFormat {
public static final String KEY_IS_TIMED_TEXT = "is-timed-text";
// The following color aspect values must be in sync with the ones in HardwareAPI.h.
- /*
+ /**
* An optional key describing the color primaries, white point and
* luminance factors for video content.
*
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 4b6b4fad4de7..8618ec98c6c3 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -32,8 +32,8 @@ import java.nio.ByteBuffer;
import java.util.Map;
/**
- * MediaMuxer facilitates muxing elementary streams. Currently only supports an
- * mp4 file as the output and at most one audio and/or one video elementary
+ * MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or
+ * webm file as the output and at most one audio and/or one video elementary
* stream.
* <p>
* It is generally used like this:
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 26e466e181d9..adf85517c344 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -57,6 +57,7 @@ import android.media.SubtitleTrack.RenderingWidget;
import android.media.SyncParams;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.Preconditions;
import libcore.io.IoBridge;
import libcore.io.Libcore;
@@ -964,8 +965,8 @@ public class MediaPlayer implements SubtitleController.Listener
* @param uri the Content URI of the data you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
- public void setDataSource(Context context, Uri uri)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+ public void setDataSource(@NonNull Context context, @NonNull Uri uri)
+ throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(context, uri, null);
}
@@ -981,47 +982,46 @@ public class MediaPlayer implements SubtitleController.Listener
* to disallow or allow cross domain redirection.
* @throws IllegalStateException if it is called in an invalid state
*/
- public void setDataSource(Context context, Uri uri, Map<String, String> headers)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+ public void setDataSource(@NonNull Context context, @NonNull Uri uri,
+ @Nullable Map<String, String> headers) throws IOException, IllegalArgumentException,
+ SecurityException, IllegalStateException {
+ final ContentResolver resolver = context.getContentResolver();
final String scheme = uri.getScheme();
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
setDataSource(uri.getPath());
return;
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
&& Settings.AUTHORITY.equals(uri.getAuthority())) {
- // Redirect ringtones to go directly to underlying provider
- uri = RingtoneManager.getActualDefaultRingtoneUri(context,
- RingtoneManager.getDefaultType(uri));
- if (uri == null) {
- throw new FileNotFoundException("Failed to resolve default ringtone");
- }
- }
-
- AssetFileDescriptor fd = null;
- try {
- ContentResolver resolver = context.getContentResolver();
- fd = resolver.openAssetFileDescriptor(uri, "r");
- if (fd == null) {
+ // Try cached ringtone first since the actual provider may not be
+ // encryption aware, or it may be stored on CE media storage
+ final int type = RingtoneManager.getDefaultType(uri);
+ final Uri cacheUri = RingtoneManager.getCacheForType(type);
+ final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
+ if (attemptDataSource(resolver, cacheUri)) {
+ return;
+ } else if (attemptDataSource(resolver, actualUri)) {
return;
- }
- // Note: using getDeclaredLength so that our behavior is the same
- // as previous versions when the content provider is returning
- // a full file.
- if (fd.getDeclaredLength() < 0) {
- setDataSource(fd.getFileDescriptor());
} else {
- setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
+ setDataSource(uri.toString(), headers);
}
- return;
- } catch (SecurityException | IOException ex) {
- Log.w(TAG, "Couldn't open file on client side; trying server side: " + ex);
- } finally {
- if (fd != null) {
- fd.close();
+ } else {
+ // Try requested Uri locally first, or fallback to media server
+ if (attemptDataSource(resolver, uri)) {
+ return;
+ } else {
+ setDataSource(uri.toString(), headers);
}
}
+ }
- setDataSource(uri.toString(), headers);
+ private boolean attemptDataSource(ContentResolver resolver, Uri uri) {
+ try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
+ setDataSource(afd);
+ return true;
+ } catch (NullPointerException | SecurityException | IOException ex) {
+ Log.w(TAG, "Couldn't open " + uri + ": " + ex);
+ return false;
+ }
}
/**
@@ -1102,6 +1102,26 @@ public class MediaPlayer implements SubtitleController.Listener
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
/**
+ * Sets the data source (AssetFileDescriptor) to use. It is the caller's
+ * responsibility to close the file descriptor. It is safe to do so as soon
+ * as this call returns.
+ *
+ * @param afd the AssetFileDescriptor for the file you want to play
+ */
+ public void setDataSource(@NonNull AssetFileDescriptor afd)
+ throws IOException, IllegalArgumentException, IllegalStateException {
+ Preconditions.checkNotNull(afd);
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (afd.getDeclaredLength() < 0) {
+ setDataSource(afd.getFileDescriptor());
+ } else {
+ setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
+ }
+ }
+
+ /**
* Sets the data source (FileDescriptor) to use. It is the caller's responsibility
* to close the file descriptor. It is safe to do so as soon as this call returns.
*
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index f09f6542d2e7..60444e0c20ca 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -277,6 +277,30 @@ public class MediaRecorder
public static final int HOTWORD = 1999;
}
+ // TODO make AudioSource static (API change) and move this method inside the AudioSource class
+ /**
+ * @hide
+ * @param source An audio source to test
+ * @return true if the source is only visible to system components
+ */
+ public static boolean isSystemOnlyAudioSource(int source) {
+ switch(source) {
+ case AudioSource.DEFAULT:
+ case AudioSource.MIC:
+ case AudioSource.VOICE_UPLINK:
+ case AudioSource.VOICE_DOWNLINK:
+ case AudioSource.VOICE_CALL:
+ case AudioSource.CAMCORDER:
+ case AudioSource.VOICE_RECOGNITION:
+ case AudioSource.VOICE_COMMUNICATION:
+ //case REMOTE_SUBMIX: considered "system" as it requires system permissions
+ case AudioSource.UNPROCESSED:
+ return false;
+ default:
+ return true;
+ }
+ }
+
/**
* Defines the video source. These constants are used with
* {@link MediaRecorder#setVideoSource(int)}.
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 025029e75ec1..feb490de2c3e 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -18,9 +18,12 @@ package android.media;
import com.android.internal.database.SortCursor;
+import libcore.io.Streams;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -33,6 +36,9 @@ import android.provider.Settings;
import android.provider.Settings.System;
import android.util.Log;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -654,8 +660,21 @@ public class RingtoneManager {
if (setting == null) return;
Settings.System.putString(context.getContentResolver(), setting,
ringtoneUri != null ? ringtoneUri.toString() : null);
+
+ // Stream selected ringtone into cache so it's available for playback
+ // when CE storage is still locked
+ if (ringtoneUri != null) {
+ final ContentResolver cr = context.getContentResolver();
+ final Uri cacheUri = getCacheForType(type);
+ try (InputStream in = cr.openInputStream(ringtoneUri);
+ OutputStream out = cr.openOutputStream(cacheUri)) {
+ Streams.copy(in, out);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to cache ringtone: " + e);
+ }
+ }
}
-
+
private static String getSettingForType(int type) {
if ((type & TYPE_RINGTONE) != 0) {
return Settings.System.RINGTONE;
@@ -667,7 +686,20 @@ public class RingtoneManager {
return null;
}
}
-
+
+ /** {@hide} */
+ public static Uri getCacheForType(int type) {
+ if ((type & TYPE_RINGTONE) != 0) {
+ return Settings.System.RINGTONE_CACHE_URI;
+ } else if ((type & TYPE_NOTIFICATION) != 0) {
+ return Settings.System.NOTIFICATION_SOUND_CACHE_URI;
+ } else if ((type & TYPE_ALARM) != 0) {
+ return Settings.System.ALARM_ALERT_CACHE_URI;
+ } else {
+ return null;
+ }
+ }
+
/**
* Returns whether the given {@link Uri} is one of the default ringtones.
*
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 4ffac6dd93be..55fb82bbdcc5 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -277,6 +277,7 @@ public class AudioMix {
mRouteFlags = ROUTE_FLAG_RENDER;
}
if (mFormat == null) {
+ // FIXME Can we eliminate this? Will AudioMix work with an unspecified sample rate?
int rate = AudioSystem.getPrimaryOutputSamplingRate();
if (rate <= 0) {
rate = 44100;
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 54543ec43f89..e197141e0214 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -42,7 +42,7 @@ import java.util.Objects;
@SystemApi
public class AudioMixingRule {
- private AudioMixingRule(int mixType, ArrayList<AttributeMatchCriterion> criteria) {
+ private AudioMixingRule(int mixType, ArrayList<AudioMixMatchCriterion> criteria) {
mCriteria = criteria;
mTargetMixType = mixType;
}
@@ -91,21 +91,21 @@ public class AudioMixingRule {
public static final int RULE_EXCLUDE_UID =
RULE_EXCLUSION_MASK | RULE_MATCH_UID;
- static final class AttributeMatchCriterion {
+ static final class AudioMixMatchCriterion {
final AudioAttributes mAttr;
- final Integer mIntProp;
+ final int mIntProp;
final int mRule;
/** input parameters must be valid */
- AttributeMatchCriterion(AudioAttributes attributes, int rule) {
+ AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
mAttr = attributes;
- mIntProp = null;
+ mIntProp = Integer.MIN_VALUE;
mRule = rule;
}
/** input parameters must be valid */
- AttributeMatchCriterion(Integer intProp, int rule) {
+ AudioMixMatchCriterion(Integer intProp, int rule) {
mAttr = null;
- mIntProp = intProp;
+ mIntProp = intProp.intValue();
mRule = rule;
}
@@ -125,10 +125,10 @@ public class AudioMixingRule {
dest.writeInt(mAttr.getCapturePreset());
break;
case RULE_MATCH_UID:
- dest.writeInt(mIntProp.intValue());
+ dest.writeInt(mIntProp);
break;
default:
- Log.e("AttributeMatchCriterion", "Unknown match rule" + match_rule
+ Log.e("AudioMixMatchCriterion", "Unknown match rule" + match_rule
+ " when writing to Parcel");
dest.writeInt(-1);
}
@@ -137,8 +137,8 @@ public class AudioMixingRule {
private final int mTargetMixType;
int getTargetMixType() { return mTargetMixType; }
- private final ArrayList<AttributeMatchCriterion> mCriteria;
- ArrayList<AttributeMatchCriterion> getCriteria() { return mCriteria; }
+ private final ArrayList<AudioMixMatchCriterion> mCriteria;
+ ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; }
@Override
public int hashCode() {
@@ -205,7 +205,7 @@ public class AudioMixingRule {
*/
@SystemApi
public static class Builder {
- private ArrayList<AttributeMatchCriterion> mCriteria;
+ private ArrayList<AudioMixMatchCriterion> mCriteria;
private int mTargetMixType = AudioMix.MIX_TYPE_INVALID;
/**
@@ -213,7 +213,7 @@ public class AudioMixingRule {
*/
@SystemApi
public Builder() {
- mCriteria = new ArrayList<AttributeMatchCriterion>();
+ mCriteria = new ArrayList<AudioMixMatchCriterion>();
}
/**
@@ -378,10 +378,10 @@ public class AudioMixingRule {
throw new IllegalArgumentException("Incompatible rule for mix");
}
synchronized (mCriteria) {
- Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
+ Iterator<AudioMixMatchCriterion> crIterator = mCriteria.iterator();
final int match_rule = rule & ~RULE_EXCLUSION_MASK;
while (crIterator.hasNext()) {
- final AttributeMatchCriterion criterion = crIterator.next();
+ final AudioMixMatchCriterion criterion = crIterator.next();
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
// "usage"-based rule
@@ -413,7 +413,7 @@ public class AudioMixingRule {
break;
case RULE_MATCH_UID:
// "usage"-based rule
- if (criterion.mIntProp.intValue() == intProp.intValue()) {
+ if (criterion.mIntProp == intProp.intValue()) {
if (criterion.mRule == rule) {
// rule already exists, we're done
return this;
@@ -431,10 +431,10 @@ public class AudioMixingRule {
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
+ mCriteria.add(new AudioMixMatchCriterion(attrToMatch, rule));
break;
case RULE_MATCH_UID:
- mCriteria.add(new AttributeMatchCriterion(intProp, rule));
+ mCriteria.add(new AudioMixMatchCriterion(intProp, rule));
break;
default:
throw new IllegalStateException("Unreachable code in addRuleInternal()");
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 5ad61265f439..5d2bac02a5e0 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -17,7 +17,7 @@
package android.media.audiopolicy;
import android.media.AudioFormat;
-import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion;
+import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -86,9 +86,9 @@ public class AudioPolicyConfig implements Parcelable {
dest.writeInt(mix.getFormat().getEncoding());
dest.writeInt(mix.getFormat().getChannelMask());
// write mix rules
- final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
+ final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
dest.writeInt(criteria.size());
- for (AttributeMatchCriterion criterion : criteria) {
+ for (AudioMixMatchCriterion criterion : criteria) {
criterion.writeToParcel(dest);
}
}
@@ -150,8 +150,8 @@ public class AudioPolicyConfig implements Parcelable {
textDump += " channels=0x";
textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n";
// write mix rules
- final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
- for (AttributeMatchCriterion criterion : criteria) {
+ final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
+ for (AudioMixMatchCriterion criterion : criteria) {
switch(criterion.mRule) {
case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE:
textDump += " exclude usage ";
@@ -171,11 +171,11 @@ public class AudioPolicyConfig implements Parcelable {
break;
case AudioMixingRule.RULE_MATCH_UID:
textDump += " match UID ";
- textDump += criterion.mIntProp.toString();
+ textDump += criterion.mIntProp;
break;
case AudioMixingRule.RULE_EXCLUDE_UID:
textDump += " exclude UID ";
- textDump += criterion.mIntProp.toString();
+ textDump += criterion.mIntProp;
break;
default:
textDump += "invalid rule!";
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 56b25144d948..9e67c151b8cc 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -73,7 +73,6 @@ public final class MediaBrowser {
* Used as an int extra field to denote the page number to subscribe.
* The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
*
- * @see android.service.media.MediaBrowserService.BrowserRoot
* @see #EXTRA_PAGE_SIZE
*/
public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
@@ -82,7 +81,6 @@ public final class MediaBrowser {
* Used as an int extra field to denote the number of media items in a page.
* The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
*
- * @see android.service.media.MediaBrowserService.BrowserRoot
* @see #EXTRA_PAGE
*/
public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
@@ -470,7 +468,7 @@ public final class MediaBrowser {
sub = new Subscription();
mSubscriptions.put(parentId, sub);
}
- sub.add(callback, options);
+ sub.putCallback(options, callback);
// If we are connected, tell the service that we are watching. If we aren't connected,
// the service will be told when we connect.
@@ -502,7 +500,7 @@ public final class MediaBrowser {
Subscription sub = mSubscriptions.get(parentId);
// Tell the service if necessary.
- if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
+ if (sub != null && sub.removeCallback(options) && mState == CONNECT_STATE_CONNECTED) {
try {
// NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
// it will break the action of support library which expects removeSubscription will
@@ -860,7 +858,7 @@ public final class MediaBrowser {
*
* @param parentId The media id of the parent media item.
* @param children The children which were loaded, or null if the id is invalid.
- * @param options A bundle of service-specific arguments to send to the media
+ * @param options A bundle of service-specific arguments sent to the media
* browse service. The contents of this bundle may affect the
* information returned when browsing.
*/
@@ -1093,7 +1091,16 @@ public final class MediaBrowser {
return mCallbacks;
}
- public void add(SubscriptionCallback callback, Bundle options) {
+ public SubscriptionCallback getCallback(Bundle options) {
+ for (int i = 0; i < mOptionsList.size(); ++i) {
+ if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
+ return mCallbacks.get(i);
+ }
+ }
+ return null;
+ }
+
+ public void putCallback(Bundle options, SubscriptionCallback callback) {
for (int i = 0; i < mOptionsList.size(); ++i) {
if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
mCallbacks.set(i, callback);
@@ -1104,7 +1111,7 @@ public final class MediaBrowser {
mOptionsList.add(options);
}
- public boolean remove(Bundle options) {
+ public boolean removeCallback(Bundle options) {
for (int i = 0; i < mOptionsList.size(); ++i) {
if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
mCallbacks.remove(i);
@@ -1114,14 +1121,5 @@ public final class MediaBrowser {
}
return false;
}
-
- public SubscriptionCallback getCallback(Bundle options) {
- for (int i = 0; i < mOptionsList.size(); ++i) {
- if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
- return mCallbacks.get(i);
- }
- }
- return null;
- }
}
}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bd0019f0f1d8..3affee5c0aa7 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -50,4 +50,6 @@ interface ISession {
void setPlaybackToLocal(in AudioAttributes attributes);
void setPlaybackToRemote(int control, int max);
void setCurrentVolume(int currentVolume);
+
+ String getCallingPackage();
}
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index adb6b0600f97..893bd3c8cbb1 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -29,6 +29,10 @@ oneway interface ISessionCallback {
void onMediaButton(in Intent mediaButtonIntent, int sequenceNumber, in ResultReceiver cb);
// These callbacks are for the TransportPerformer
+ void onPrepare();
+ void onPrepareFromMediaId(String mediaId, in Bundle extras);
+ void onPrepareFromSearch(String query, in Bundle extras);
+ void onPrepareFromUri(in Uri uri, in Bundle extras);
void onPlay();
void onPlayFromMediaId(String mediaId, in Bundle extras);
void onPlayFromSearch(String query, in Bundle extras);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 285e5f7a0880..249bcdc802ce 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -50,6 +50,10 @@ interface ISessionController {
void setVolumeTo(int value, int flags, String packageName);
// These commands are for the TransportControls
+ void prepare();
+ void prepareFromMediaId(String mediaId, in Bundle extras);
+ void prepareFromSearch(String string, in Bundle extras);
+ void prepareFromUri(in Uri uri, in Bundle extras);
void play();
void playFromMediaId(String mediaId, in Bundle extras);
void playFromSearch(String string, in Bundle extras);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 3d9b60deed2f..622900f5c7f9 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -592,6 +592,95 @@ public final class MediaController {
}
/**
+ * Request that the player prepare its playback. In other words, other sessions can continue
+ * to play during the preparation of this session. This method can be used to speed up the
+ * start of the playback. Once the preparation is done, the session will change its playback
+ * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
+ * start playback.
+ */
+ public void prepare() {
+ try {
+ mSessionBinder.prepare();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare.", e);
+ }
+ }
+
+ /**
+ * Request that the player prepare playback for a specific media id. In other words, other
+ * sessions can continue to play during the preparation of this session. This method can be
+ * used to speed up the start of the playback. Once the preparation is done, the session
+ * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+ * {@link #play} can be called to start playback. If the preparation is not needed,
+ * {@link #playFromMediaId} can be directly called without this method.
+ *
+ * @param mediaId The id of the requested media.
+ * @param extras Optional extras that can include extra information about the media item
+ * to be prepared.
+ */
+ public void prepareFromMediaId(String mediaId, Bundle extras) {
+ if (TextUtils.isEmpty(mediaId)) {
+ throw new IllegalArgumentException(
+ "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);
+ }
+ }
+
+ /**
+ * Request that the player prepare playback for a specific search query. An empty or null
+ * query should be treated as a request to prepare any music. In other words, other sessions
+ * can continue to play during the preparation of this session. This method can be used to
+ * speed up the start of the playback. Once the preparation is done, the session will
+ * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+ * {@link #play} can be called to start playback. If the preparation is not needed,
+ * {@link #playFromSearch} can be directly called without this method.
+ *
+ * @param query The search query.
+ * @param extras Optional extras that can include extra information
+ * about the query.
+ */
+ public void prepareFromSearch(String query, Bundle extras) {
+ if (query == null) {
+ // This is to remain compatible with
+ // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
+ query = "";
+ }
+ try {
+ mSessionBinder.prepareFromSearch(query, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
+ }
+ }
+
+ /**
+ * Request that the player prepare playback for a specific {@link Uri}. In other words,
+ * other sessions can continue to play during the preparation of this session. This method
+ * can be used to speed up the start of the playback. Once the preparation is done, the
+ * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+ * {@link #play} can be called to start playback. If the preparation is not needed,
+ * {@link #playFromUri} can be directly called without this method.
+ *
+ * @param uri The URI of the requested media.
+ * @param extras Optional extras that can include extra information about the media item
+ * to be prepared.
+ */
+ 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.");
+ }
+ try {
+ mSessionBinder.prepareFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
+ }
+ }
+
+ /**
* Request that the player start its playback at its current position.
*/
public void play() {
@@ -605,7 +694,6 @@ public final class MediaController {
/**
* Request that the player start playback for a specific media id.
*
- * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param mediaId The id of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
@@ -627,10 +715,9 @@ public final class MediaController {
* An empty or null query should be treated as a request to play any
* music.
*
- * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param query The search query.
* @param extras Optional extras that can include extra information
- * about the query.
+ * about the query.
*/
public void playFromSearch(String query, Bundle extras) {
if (query == null) {
@@ -648,8 +735,7 @@ public final class MediaController {
/**
* Request that the player start playback for a specific {@link Uri}.
*
- * @see PlaybackState#EXTRA_PREPARE_ONLY
- * @param uri The URI of the requested media.
+ * @param uri The URI of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
*/
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 8c5b19c36f11..0bd1713c4a34 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,12 +87,6 @@ public final class MediaSession {
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
- * Set this flag on the session to indicate that it can handle
- * the {@link PlaybackState#EXTRA_PREPARE_ONLY} field.
- */
- public static final int FLAG_HANDLES_PREPARE_ONLY = 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.
@@ -106,7 +100,6 @@ public final class MediaSession {
@IntDef(flag = true, value = {
FLAG_HANDLES_MEDIA_BUTTONS,
FLAG_HANDLES_TRANSPORT_CONTROLS,
- FLAG_HANDLES_PREPARE_ONLY,
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
@@ -519,6 +512,38 @@ public final class MediaSession {
}
}
+ /**
+ * Returns the name of the package that sent the last media button, transport control, or
+ * command from controllers and the system. This is only valid while in a request callback, such
+ * as {@link Callback#onPlay}.
+ *
+ * @hide
+ */
+ public String getCallingPackage() {
+ try {
+ return mBinder.getCallingPackage();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in getCallingPackage.", e);
+ }
+ return null;
+ }
+
+ private void dispatchPrepare() {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE);
+ }
+
+ private void dispatchPrepareFromMediaId(String mediaId, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
+ }
+
+ private void dispatchPrepareFromSearch(String query, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
+ }
+
+ private void dispatchPrepareFromUri(Uri uri, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
+ }
+
private void dispatchPlay() {
postToCallback(CallbackMessageHandler.MSG_PLAY);
}
@@ -805,16 +830,54 @@ public final class MediaSession {
}
/**
- * Override to handle requests to begin playback.
+ * Override to handle requests to prepare playback. During the preparation, a session should
+ * not hold audio focus in order to allow other sessions play seamlessly. The state of
+ * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
+ * done.
*/
- public void onPlay() {
+ public void onPrepare() {
}
/**
- * Override to handle requests to play a specific mediaId that was
- * provided by your app's {@link MediaBrowserService}.
+ * Override to handle requests to prepare for playing a specific mediaId that was provided
+ * by your app's {@link MediaBrowserService}. During the preparation, a session should not
+ * hold audio focus in order to allow other sessions play seamlessly. The state of playback
+ * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+ * The playback of the prepared content should start in the implementation of
+ * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
+ * playback without preparation.
*/
- public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ public void onPrepareFromMediaId(String mediaId, Bundle extras) {
+ }
+
+ /**
+ * Override to handle requests to prepare playback from a search query. An empty query
+ * indicates that the app may prepare any music. The implementation should attempt to make a
+ * smart choice about what to play. During the preparation, a session should not hold audio
+ * focus in order to allow other sessions play seamlessly. The state of playback should be
+ * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
+ * of the prepared content should start in the implementation of {@link #onPlay}. Override
+ * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
+ */
+ public void onPrepareFromSearch(String query, Bundle extras) {
+ }
+
+ /**
+ * Override to handle requests to prepare a specific media item represented by a URI.
+ * During the preparation, a session should not hold audio focus in order to allow
+ * other sessions play seamlessly. The state of playback should be updated to
+ * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+ * The playback of the prepared content should start in the implementation of
+ * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
+ * for starting playback without preparation.
+ */
+ public void onPrepareFromUri(Uri uri, Bundle extras) {
+ }
+
+ /**
+ * Override to handle requests to begin playback.
+ */
+ public void onPlay() {
}
/**
@@ -827,6 +890,13 @@ public final class MediaSession {
}
/**
+ * Override to handle requests to play a specific mediaId that was
+ * provided by your app's {@link MediaBrowserService}.
+ */
+ public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ }
+
+ /**
* Override to handle requests to play a specific media item represented by a URI.
*/
public void onPlayFromUri(Uri uri, Bundle extras) {
@@ -937,6 +1007,38 @@ public final class MediaSession {
}
@Override
+ public void onPrepare() {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepare();
+ }
+ }
+
+ @Override
+ public void onPrepareFromMediaId(String mediaId, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepareFromMediaId(mediaId, extras);
+ }
+ }
+
+ @Override
+ public void onPrepareFromSearch(String query, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepareFromSearch(query, extras);
+ }
+ }
+
+ @Override
+ public void onPrepareFromUri(Uri uri, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepareFromUri(uri, extras);
+ }
+ }
+
+ @Override
public void onPlay() {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1162,24 +1264,28 @@ public final class MediaSession {
private class CallbackMessageHandler extends Handler {
- private static final int MSG_PLAY = 1;
- private static final int MSG_PLAY_MEDIA_ID = 2;
- private static final int MSG_PLAY_SEARCH = 3;
- private static final int MSG_SKIP_TO_ITEM = 4;
- private static final int MSG_PAUSE = 5;
- private static final int MSG_STOP = 6;
- private static final int MSG_NEXT = 7;
- private static final int MSG_PREVIOUS = 8;
- private static final int MSG_FAST_FORWARD = 9;
- private static final int MSG_REWIND = 10;
- private static final int MSG_SEEK_TO = 11;
- private static final int MSG_RATE = 12;
- private static final int MSG_CUSTOM_ACTION = 13;
- private static final int MSG_MEDIA_BUTTON = 14;
- private static final int MSG_COMMAND = 15;
- private static final int MSG_ADJUST_VOLUME = 16;
- private static final int MSG_SET_VOLUME = 17;
- private static final int MSG_PLAY_URI = 18;
+ private static final int MSG_COMMAND = 1;
+ private static final int MSG_MEDIA_BUTTON = 2;
+ private static final int MSG_PREPARE = 3;
+ private static final int MSG_PREPARE_MEDIA_ID = 4;
+ private static final int MSG_PREPARE_SEARCH = 5;
+ private static final int MSG_PREPARE_URI = 6;
+ private static final int MSG_PLAY = 7;
+ private static final int MSG_PLAY_MEDIA_ID = 8;
+ private static final int MSG_PLAY_SEARCH = 9;
+ private static final int MSG_PLAY_URI = 10;
+ private static final int MSG_SKIP_TO_ITEM = 11;
+ private static final int MSG_PAUSE = 12;
+ private static final int MSG_STOP = 13;
+ private static final int MSG_NEXT = 14;
+ private static final int MSG_PREVIOUS = 15;
+ private static final int MSG_FAST_FORWARD = 16;
+ private static final int MSG_REWIND = 17;
+ private static final int MSG_SEEK_TO = 18;
+ private static final int MSG_RATE = 19;
+ private static final int MSG_CUSTOM_ACTION = 20;
+ private static final int MSG_ADJUST_VOLUME = 21;
+ private static final int MSG_SET_VOLUME = 22;
private MediaSession.Callback mCallback;
@@ -1210,6 +1316,25 @@ public final class MediaSession {
public void handleMessage(Message msg) {
VolumeProvider vp;
switch (msg.what) {
+ case MSG_COMMAND:
+ Command cmd = (Command) msg.obj;
+ mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
+ break;
+ case MSG_MEDIA_BUTTON:
+ mCallback.onMediaButtonEvent((Intent) msg.obj);
+ break;
+ case MSG_PREPARE:
+ mCallback.onPrepare();
+ break;
+ case MSG_PREPARE_MEDIA_ID:
+ mCallback.onPrepareFromMediaId((String) msg.obj, msg.getData());
+ break;
+ case MSG_PREPARE_SEARCH:
+ mCallback.onPrepareFromSearch((String) msg.obj, msg.getData());
+ break;
+ case MSG_PREPARE_URI:
+ mCallback.onPrepareFromUri((Uri) msg.obj, msg.getData());
+ break;
case MSG_PLAY:
mCallback.onPlay();
break;
@@ -1252,13 +1377,6 @@ public final class MediaSession {
case MSG_CUSTOM_ACTION:
mCallback.onCustomAction((String) msg.obj, msg.getData());
break;
- case MSG_MEDIA_BUTTON:
- mCallback.onMediaButtonEvent((Intent) msg.obj);
- break;
- case MSG_COMMAND:
- Command cmd = (Command) msg.obj;
- mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
- break;
case MSG_ADJUST_VOLUME:
synchronized (mLock) {
vp = mVolumeProvider;
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 1079a1f9a107..1485cd782605 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -133,19 +133,32 @@ public final class PlaybackState implements Parcelable {
public static final long ACTION_PLAY_FROM_URI = 1 << 13;
/**
- * Used as an optional boolean extra field in
- * {@link MediaController.TransportControls#playFromMediaId},
- * {@link MediaController.TransportControls#playFromSearch}, and
- * {@link MediaController.TransportControls#playFromUri}. Value of {@code true} overrides
- * the default behavior of starting the playback after preparing. Check
- * {@link MediaSession#FLAG_HANDLES_PREPARE_ONLY} to see if the media session supports this.
+ * Indicates this session supports the prepare command.
*
- * @see MediaSession#FLAG_HANDLES_PREPARE_ONLY
- * @see MediaController.TransportControls#playFromMediaId
- * @see MediaController.TransportControls#playFromSearch
- * @see MediaController.TransportControls#playFromUri
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PREPARE = 1 << 14;
+
+ /**
+ * Indicates this session supports the prepare from media id command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
+
+ /**
+ * Indicates this session supports the prepare from search command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
+
+ /**
+ * Indicates this session supports the prepare from URI command.
+ *
+ * @see Builder#setActions(long)
*/
- public static final String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
+ public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
/**
* This is the default playback state and indicates that no media has been
@@ -330,6 +343,10 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*/
public int getState() {
@@ -380,6 +397,10 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
* <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
* <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
* </ul>
*/
public long getActions() {
@@ -831,6 +852,10 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*
* @param state The current state of playback.
@@ -870,6 +895,10 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*
* @param state The current state of playback.
@@ -900,6 +929,10 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
* <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
* <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
* </ul>
*
* @param actions The set of actions allowed.
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 707db06fdd54..df0961bd17d4 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -16,12 +16,17 @@
package android.media.soundtrigger;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.media.AudioFormat;
import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Slog;
@@ -29,6 +34,8 @@ import android.util.Slog;
import com.android.internal.app.ISoundTriggerService;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.UUID;
/**
@@ -45,6 +52,12 @@ public final class SoundTriggerDetector {
private static final boolean DBG = false;
private static final String TAG = "SoundTriggerDetector";
+ private static final int MSG_AVAILABILITY_CHANGED = 1;
+ private static final int MSG_SOUND_TRIGGER_DETECTED = 2;
+ private static final int MSG_DETECTION_ERROR = 3;
+ private static final int MSG_DETECTION_PAUSE = 4;
+ private static final int MSG_DETECTION_RESUME = 5;
+
private final Object mLock = new Object();
private final ISoundTriggerService mSoundTriggerService;
@@ -53,7 +66,121 @@ public final class SoundTriggerDetector {
private final Handler mHandler;
private final RecognitionCallback mRecognitionCallback;
- public abstract class Callback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {
+ RECOGNITION_FLAG_NONE,
+ RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
+ RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ })
+ public @interface RecognitionFlags {}
+
+ /**
+ * Empty flag for {@link #startRecognition(int)}.
+ *
+ * @hide
+ */
+ public static final int RECOGNITION_FLAG_NONE = 0;
+
+ /**
+ * Recognition flag for {@link #startRecognition(int)} that indicates
+ * whether the trigger audio for hotword needs to be captured.
+ */
+ public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 0x1;
+
+ /**
+ * Recognition flag for {@link #startRecognition(int)} that indicates
+ * whether the recognition should keep going on even after the
+ * model triggers.
+ * If this flag is specified, it's possible to get multiple
+ * triggers after a call to {@link #startRecognition(int)}, if the model
+ * triggers multiple times.
+ * When this isn't specified, the default behavior is to stop recognition once the
+ * trigger happenss, till the caller starts recognition again.
+ */
+ public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 0x2;
+
+ /**
+ * Additional payload for {@link Callback#onDetected}.
+ */
+ public static class EventPayload {
+ private final boolean mTriggerAvailable;
+
+ // Indicates if {@code captureSession} can be used to continue capturing more audio
+ // from the DSP hardware.
+ private final boolean mCaptureAvailable;
+ // The session to use when attempting to capture more audio from the DSP hardware.
+ private final int mCaptureSession;
+ private final AudioFormat mAudioFormat;
+ // Raw data associated with the event.
+ // This is the audio that triggered the keyphrase if {@code isTriggerAudio} is true.
+ private final byte[] mData;
+
+ private EventPayload(boolean triggerAvailable, boolean captureAvailable,
+ AudioFormat audioFormat, int captureSession, byte[] data) {
+ mTriggerAvailable = triggerAvailable;
+ mCaptureAvailable = captureAvailable;
+ mCaptureSession = captureSession;
+ mAudioFormat = audioFormat;
+ mData = data;
+ }
+
+ /**
+ * Gets the format of the audio obtained using {@link #getTriggerAudio()}.
+ * May be null if there's no audio present.
+ */
+ @Nullable
+ public AudioFormat getCaptureAudioFormat() {
+ return mAudioFormat;
+ }
+
+ /**
+ * Gets the raw audio that triggered the keyphrase.
+ * This may be null if the trigger audio isn't available.
+ * If non-null, the format of the audio can be obtained by calling
+ * {@link #getCaptureAudioFormat()}.
+ *
+ * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ */
+ @Nullable
+ public byte[] getTriggerAudio() {
+ if (mTriggerAvailable) {
+ return mData;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the session ID to start a capture from the DSP.
+ * This may be null if streaming capture isn't possible.
+ * If non-null, the format of the audio that can be captured can be
+ * obtained using {@link #getCaptureAudioFormat()}.
+ *
+ * TODO: Candidate for Public API when the API to start capture with a session ID
+ * is made public.
+ *
+ * TODO: Add this to {@link #getCaptureAudioFormat()}:
+ * "Gets the format of the audio obtained using {@link #getTriggerAudio()}
+ * or {@link #getCaptureSession()}. May be null if no audio can be obtained
+ * for either the trigger or a streaming session."
+ *
+ * TODO: Should this return a known invalid value instead?
+ *
+ * @hide
+ */
+ @Nullable
+ public Integer getCaptureSession() {
+ if (mCaptureAvailable) {
+ return mCaptureSession;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public static abstract class Callback {
/**
* Called when the availability of the sound model changes.
*/
@@ -63,7 +190,7 @@ public final class SoundTriggerDetector {
* Called when the sound model has triggered (such as when it matched a
* given sound pattern).
*/
- public abstract void onDetected();
+ public abstract void onDetected(@NonNull EventPayload eventPayload);
/**
* Called when the detection fails due to an error.
@@ -95,9 +222,9 @@ public final class SoundTriggerDetector {
mSoundModelId = soundModelId;
mCallback = callback;
if (handler == null) {
- mHandler = new Handler();
+ mHandler = new MyHandler();
} else {
- mHandler = handler;
+ mHandler = new MyHandler(handler.getLooper());
}
mRecognitionCallback = new RecognitionCallback();
}
@@ -107,13 +234,19 @@ public final class SoundTriggerDetector {
* {@link Callback}.
* @return Indicates whether the call succeeded or not.
*/
- public boolean startRecognition() {
+ public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
if (DBG) {
Slog.d(TAG, "startRecognition()");
}
+ boolean captureTriggerAudio =
+ (recognitionFlags & RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0;
+
+ boolean allowMultipleTriggers =
+ (recognitionFlags & RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0;
try {
mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId),
- mRecognitionCallback);
+ mRecognitionCallback, new RecognitionConfig(captureTriggerAudio,
+ allowMultipleTriggers, null, null));
} catch (RemoteException e) {
return false;
}
@@ -144,17 +277,30 @@ public final class SoundTriggerDetector {
/**
* Callback that handles events from the lower sound trigger layer.
+ *
+ * Note that these callbacks will be called synchronously from the SoundTriggerService
+ * layer and thus should do minimal work (such as sending a message on a handler to do
+ * the real work).
* @hide
*/
- private static class RecognitionCallback extends
- IRecognitionStatusCallback.Stub {
+ private class RecognitionCallback extends IRecognitionStatusCallback.Stub {
/**
* @hide
*/
@Override
- public void onDetected(SoundTrigger.RecognitionEvent event) {
- Slog.e(TAG, "onDetected()" + event);
+ public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
+ Slog.d(TAG, "onGenericSoundTriggerDetected()" + event);
+ Message.obtain(mHandler,
+ MSG_SOUND_TRIGGER_DETECTED,
+ new EventPayload(event.triggerInData, event.captureAvailable,
+ event.captureFormat, event.captureSession, event.data))
+ .sendToTarget();
+ }
+
+ @Override
+ public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent event) {
+ Slog.e(TAG, "Ignoring onKeyphraseDetected() called for " + event);
}
/**
@@ -162,7 +308,8 @@ public final class SoundTriggerDetector {
*/
@Override
public void onError(int status) {
- Slog.e(TAG, "onError()" + status);
+ Slog.d(TAG, "onError()" + status);
+ mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
}
/**
@@ -170,7 +317,8 @@ public final class SoundTriggerDetector {
*/
@Override
public void onRecognitionPaused() {
- Slog.e(TAG, "onRecognitionPaused()");
+ Slog.d(TAG, "onRecognitionPaused()");
+ mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE);
}
/**
@@ -178,7 +326,44 @@ public final class SoundTriggerDetector {
*/
@Override
public void onRecognitionResumed() {
- Slog.e(TAG, "onRecognitionResumed()");
+ Slog.d(TAG, "onRecognitionResumed()");
+ mHandler.sendEmptyMessage(MSG_DETECTION_RESUME);
+ }
+ }
+
+ private class MyHandler extends Handler {
+
+ MyHandler() {
+ super();
+ }
+
+ MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mCallback == null) {
+ Slog.w(TAG, "Received message: " + msg.what + " for NULL callback.");
+ return;
+ }
+ switch (msg.what) {
+ case MSG_SOUND_TRIGGER_DETECTED:
+ mCallback.onDetected((EventPayload) msg.obj);
+ break;
+ case MSG_DETECTION_ERROR:
+ mCallback.onError();
+ break;
+ case MSG_DETECTION_PAUSE:
+ mCallback.onRecognitionPaused();
+ break;
+ case MSG_DETECTION_RESUME:
+ mCallback.onRecognitionResumed();
+ break;
+ default:
+ super.handleMessage(msg);
+
+ }
}
}
}
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 8ef5ca0f62d8..5dd4e85efa2c 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -45,8 +45,7 @@ oneway interface ITvInputClient {
void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
// For the recording session
- void onConnected(int seq);
- void onRecordingStarted(int seq);
+ void onTuned(int seq);
void onRecordingStopped(in Uri recordedProgramUri, int seq);
void onError(int error, int seq);
}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index d18933385463..3ec7656dd3f2 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -41,7 +41,7 @@ import android.view.Surface;
interface ITvInputManager {
List<TvInputInfo> getTvInputList(int userId);
TvInputInfo getTvInputInfo(in String inputId, int userId);
- void setTvInputInfo(in TvInputInfo inputInfo, int userId);
+ void updateTvInputInfo(in TvInputInfo inputInfo, int userId);
int getTvInputState(in String inputId, int userId);
List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
@@ -87,8 +87,7 @@ interface ITvInputManager {
void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId);
// For the recording session
- void connect(in IBinder sessionToken, in Uri channelUri, in Bundle params, int userId);
- void startRecording(in IBinder sessionToken, int userId);
+ void startRecording(in IBinder sessionToken, in Uri programHint, int userId);
void stopRecording(in IBinder sessionToken, int userId);
// For TV input hardware binding
diff --git a/media/java/android/media/tv/ITvInputManagerCallback.aidl b/media/java/android/media/tv/ITvInputManagerCallback.aidl
index 395c9f3b384e..0f8bf2fb3a1d 100644
--- a/media/java/android/media/tv/ITvInputManagerCallback.aidl
+++ b/media/java/android/media/tv/ITvInputManagerCallback.aidl
@@ -26,8 +26,6 @@ oneway interface ITvInputManagerCallback {
void onInputAdded(in String inputId);
void onInputRemoved(in String inputId);
void onInputUpdated(in String inputId);
-
void onInputStateChanged(in String inputId, int state);
-
- void onTvInputInfoChanged(in TvInputInfo TvInputInfo);
+ void onTvInputInfoUpdated(in TvInputInfo TvInputInfo);
}
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 408a76277845..b1ce8d4975f8 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -56,8 +56,6 @@ oneway interface ITvInputSession {
void timeShiftEnablePositionTracking(boolean enable);
// For the recording session
- void connect(in Uri channelUri, in Bundle params);
- void disconnect();
- void startRecording();
+ void startRecording(in Uri programHint);
void stopRecording();
}
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index cb6a05e07b0d..60d6f0df9855 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -42,8 +42,7 @@ oneway interface ITvInputSessionCallback {
void onTimeShiftCurrentPositionChanged(long timeMs);
// For the recording session
- void onConnected();
- void onRecordingStarted();
+ void onTuned();
void onRecordingStopped(in Uri recordedProgramUri);
void onError(int error);
}
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 4ac58766ca94..56103adc784d 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.media.PlaybackParams;
@@ -65,10 +66,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
private static final int DO_TIME_SHIFT_SEEK_TO = 17;
private static final int DO_TIME_SHIFT_SET_PLAYBACK_PARAMS = 18;
private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 19;
- private static final int DO_CONNECT = 20;
- private static final int DO_DISCONNECT = 21;
- private static final int DO_START_RECORDING = 22;
- private static final int DO_STOP_RECORDING = 23;
+ private static final int DO_START_RECORDING = 20;
+ private static final int DO_STOP_RECORDING = 21;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -90,6 +89,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
}
}
+ // For the recording session
public ITvInputSessionWrapper(Context context,
TvInputService.RecordingSession recordingSessionImpl) {
mIsRecordingSession = true;
@@ -99,25 +99,28 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
@Override
public void executeMessage(Message msg) {
- if (!mIsRecordingSession && mTvInputSessionImpl == null) {
- return;
- }
- if (mIsRecordingSession && mTvInputRecordingSessionImpl == null) {
+ if ((mIsRecordingSession && mTvInputRecordingSessionImpl == null)
+ || (!mIsRecordingSession && mTvInputSessionImpl == null)) {
return;
}
long startTime = System.nanoTime();
switch (msg.what) {
case DO_RELEASE: {
- mTvInputSessionImpl.release();
- mTvInputSessionImpl = null;
- if (mReceiver != null) {
- mReceiver.dispose();
- mReceiver = null;
- }
- if (mChannel != null) {
- mChannel.dispose();
- mChannel = null;
+ if (mIsRecordingSession) {
+ mTvInputRecordingSessionImpl.release();
+ mTvInputRecordingSessionImpl = null;
+ } else {
+ mTvInputSessionImpl.release();
+ mTvInputSessionImpl = null;
+ if (mReceiver != null) {
+ mReceiver.dispose();
+ mReceiver = null;
+ }
+ if (mChannel != null) {
+ mChannel.dispose();
+ mChannel = null;
+ }
}
break;
}
@@ -141,7 +144,11 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
}
case DO_TUNE: {
SomeArgs args = (SomeArgs) msg.obj;
- mTvInputSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
+ if (mIsRecordingSession) {
+ mTvInputRecordingSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
+ } else {
+ mTvInputSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
+ }
args.recycle();
break;
}
@@ -208,19 +215,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mTvInputSessionImpl.timeShiftEnablePositionTracking((Boolean) msg.obj);
break;
}
- case DO_CONNECT: {
- SomeArgs args = (SomeArgs) msg.obj;
- mTvInputRecordingSessionImpl.connect((Uri) args.arg1, (Bundle) args.arg2);
- args.recycle();
- break;
- }
- case DO_DISCONNECT: {
- mTvInputRecordingSessionImpl.disconnect();
- mTvInputRecordingSessionImpl = null;
- break;
- }
case DO_START_RECORDING: {
- mTvInputRecordingSessionImpl.startRecording();
+ mTvInputRecordingSessionImpl.startRecording((Uri) msg.obj);
break;
}
case DO_STOP_RECORDING: {
@@ -250,7 +246,9 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
@Override
public void release() {
- mTvInputSessionImpl.scheduleOverlayViewCleanup();
+ if (!mIsRecordingSession) {
+ mTvInputSessionImpl.scheduleOverlayViewCleanup();
+ }
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE));
}
@@ -354,20 +352,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
}
@Override
- public void connect(Uri channelUri, Bundle params) {
- // Clear the pending connect requests.
- mCaller.removeMessages(DO_CONNECT);
- mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CONNECT, channelUri, params));
- }
-
- @Override
- public void disconnect() {
- mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_DISCONNECT));
- }
-
- @Override
- public void startRecording() {
- mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_START_RECORDING));
+ public void startRecording(@Nullable Uri programHint) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_RECORDING, programHint));
}
@Override
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 62a01dcf8808..a33219583e3c 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.ComponentName;
@@ -25,8 +26,10 @@ import android.content.Intent;
import android.net.Uri;
import android.os.IBinder;
import android.provider.BaseColumns;
+import android.text.TextUtils;
import android.util.ArraySet;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -52,6 +55,13 @@ public final class TvContract {
/** The authority for the TV provider. */
public static final String AUTHORITY = "android.media.tv";
+ /**
+ * Permission to read TV listings. This is required to read all the TV channel and program
+ * information available on the system.
+ * @hide
+ */
+ public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
+
private static final String PATH_CHANNEL = "channel";
private static final String PATH_PROGRAM = "program";
private static final String PATH_RECORDED_PROGRAM = "recorded_program";
@@ -303,33 +313,28 @@ public final class TvContract {
}
/**
- * Returns true, if {@code uri} is a channel URI.
- * @hide
+ * Returns {@code true}, if {@code uri} is a channel URI.
*/
public static final boolean isChannelUri(Uri uri) {
return isChannelUriForTunerInput(uri) || isChannelUriForPassthroughInput(uri);
}
/**
- * Returns true, if {@code uri} is a channel URI for a tuner input.
- * @hide
+ * Returns {@code true}, if {@code uri} is a channel URI for a tuner input.
*/
public static final boolean isChannelUriForTunerInput(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
}
/**
- * Returns true, if {@code uri} is a channel URI for a passthrough input.
- * @hide
+ * Returns {@code true}, if {@code uri} is a channel URI for a pass-through input.
*/
- @SystemApi
public static final boolean isChannelUriForPassthroughInput(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
}
/**
- * Returns true, if {@code uri} is a program URI.
- * @hide
+ * Returns {@code true}, if {@code uri} is a program URI.
*/
public static final boolean isProgramUri(Uri uri) {
return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PROGRAM);
@@ -961,8 +966,9 @@ public final class TvContract {
* 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_NUMBER},
- * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+ * 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
*/
@@ -974,19 +980,65 @@ public final class TvContract {
* <p>Can be empty.
*
* <p>Type: INTEGER
+ *
+ * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
*/
+ @Deprecated
public static final String COLUMN_SEASON_NUMBER = "season_number";
/**
+ * 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 number of this TV program for episodic TV shows.
*
* <p>Can be empty.
*
* <p>Type: INTEGER
+ *
+ * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
*/
+ @Deprecated
public static final String COLUMN_EPISODE_NUMBER = "episode_number";
/**
+ * 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.
@@ -1020,22 +1072,28 @@ public final class TvContract {
*
* <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.
+ * 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_BROADCAST_GENRE = "broadcast_genre";
/**
* The comma-separated canonical genre string of this TV program.
*
- * <p>Canonical genres are defined in {@link Genres}. Use
- * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
- * Use {@link Genres#decode Genres.decode()} to get the canonical genre strings from the
- * text stored in this column.
+ * <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";
@@ -1303,44 +1361,108 @@ public final class TvContract {
CANONICAL_GENRES.add(TECH_SCIENCE);
}
+ private static final char DOUBLE_QUOTE = '"';
+ private static final char COMMA = ',';
+ private static final String DELIMITER = ",";
+
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
private Genres() {}
/**
- * Encodes canonical genre strings to a text that can be put into the database.
+ * Encodes genre strings to a text that can be put into the database.
*
- * @param genres Canonical genre strings. Use the strings defined in this class.
+ * @param genres Genre strings.
* @return an encoded genre string that can be inserted into the
- * {@link #COLUMN_CANONICAL_GENRE} column.
+ * {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
*/
- public static String encode(String... genres) {
+ public static String encode(@NonNull String... genres) {
+ if (genres == null) {
+ // MNC and before will throw a NPE.
+ return null;
+ }
StringBuilder sb = new StringBuilder();
String separator = "";
for (String genre : genres) {
- sb.append(separator).append(genre);
- separator = ",";
+ sb.append(separator).append(encodeToCsv(genre));
+ separator = DELIMITER;
+ }
+ return sb.toString();
+ }
+
+ private static String encodeToCsv(String genre) {
+ StringBuilder sb = new StringBuilder();
+ int length = genre.length();
+ for (int i = 0; i < length; ++i) {
+ char c = genre.charAt(i);
+ switch (c) {
+ case DOUBLE_QUOTE:
+ sb.append(DOUBLE_QUOTE);
+ break;
+ case COMMA:
+ sb.append(DOUBLE_QUOTE);
+ break;
+ }
+ sb.append(c);
}
return sb.toString();
}
/**
- * Decodes the canonical genre strings from the text stored in the database.
+ * Decodes the genre strings from the text stored in the database.
*
* @param genres The encoded genre string retrieved from the
- * {@link #COLUMN_CANONICAL_GENRE} column.
- * @return canonical genre strings.
+ * {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
+ * @return genre strings.
*/
- public static String[] decode(String genres) {
- return genres.split("\\s*,\\s*");
+ public static String[] decode(@NonNull String genres) {
+ if (TextUtils.isEmpty(genres)) {
+ // MNC and before will throw a NPE for {@code null} genres.
+ return EMPTY_STRING_ARRAY;
+ }
+ if (genres.indexOf(COMMA) == -1 && genres.indexOf(DOUBLE_QUOTE) == -1) {
+ return new String[] {genres.trim()};
+ }
+ StringBuilder sb = new StringBuilder();
+ List<String> results = new ArrayList<>();
+ int length = genres.length();
+ boolean escape = false;
+ for (int i = 0; i < length; ++i) {
+ char c = genres.charAt(i);
+ switch (c) {
+ case DOUBLE_QUOTE:
+ if (!escape) {
+ escape = true;
+ continue;
+ }
+ break;
+ case COMMA:
+ if (!escape) {
+ String string = sb.toString().trim();
+ if (string.length() > 0) {
+ results.add(string);
+ }
+ sb = new StringBuilder();
+ continue;
+ }
+ break;
+ }
+ sb.append(c);
+ escape = false;
+ }
+ String string = sb.toString().trim();
+ if (string.length() > 0) {
+ results.add(string);
+ }
+ return results.toArray(new String[results.size()]);
}
/**
- * Check whether a given genre is canonical or not.
+ * Returns whether a given text is a canonical genre defined in {@link Genres}.
*
* @param genre The name of genre to be checked.
* @return {@code true} if the genre is canonical, otherwise {@code false}.
- * @hide
*/
- @SystemApi
public static boolean isCanonical(String genre) {
return CANONICAL_GENRES.contains(genre);
}
@@ -1366,6 +1488,17 @@ public final class TvContract {
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
/**
+ * The ID of the TV input service that is associated with this recorded program.
+ *
+ * <p>Use {@link #buildInputId} to build the ID.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: TEXT
+ */
+ 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}.
@@ -1381,8 +1514,9 @@ public final class TvContract {
* 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_NUMBER},
- * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
+ * 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
@@ -1390,24 +1524,46 @@ public final class TvContract {
public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
/**
- * The season number of this recorded TV program for episodic TV shows.
+ * 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: INTEGER
- * @see Programs#COLUMN_SEASON_NUMBER
+ * <p>Type: TEXT
*/
- public static final String COLUMN_SEASON_NUMBER = Programs.COLUMN_SEASON_NUMBER;
+ public static final String COLUMN_SEASON_DISPLAY_NUMBER =
+ Programs.COLUMN_SEASON_DISPLAY_NUMBER;
/**
- * The episode number of this recorded TV program for episodic TV shows.
+ * 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: INTEGER
- * @see Programs#COLUMN_EPISODE_NUMBER
+ * <p>Type: TEXT
*/
- public static final String COLUMN_EPISODE_NUMBER = Programs.COLUMN_EPISODE_NUMBER;
+ 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.
@@ -1441,7 +1597,10 @@ public final class TvContract {
*
* <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.
+ * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
+ * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
+ * Use {@link Genres#decode Genres.decode()} to get the broadcast genre strings from the
+ * text stored in the column.
*
* <p>Type: TEXT
* @see Programs#COLUMN_BROADCAST_GENRE
@@ -1454,7 +1613,7 @@ public final class TvContract {
* <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 this column.
+ * genre strings from the text stored in the column.
*
* <p>Type: TEXT
* @see Programs#COLUMN_CANONICAL_GENRE
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index c6dece454de3..6e0f5f2c1a43 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -105,31 +105,38 @@ public final class TvInputInfo implements Parcelable {
public static final int TYPE_DISPLAY_PORT = 1008;
/**
- * The ID of the TV input to provide to the setup activity and settings activity.
+ * Used as a String extra field in setup intents created by {@link #createSetupIntent()} to
+ * supply the ID of a specific TV input to set up.
*/
public static final String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID";
private final ResolveInfo mService;
+
private final String mId;
- private final String mParentId;
private final int mType;
- private final int mTunerCount;
- private final boolean mCanRecord;
private final boolean mIsHardwareInput;
- private final Bundle mExtras;
-
- // Attributes from XML meta data.
- private String mSetupActivity;
- private String mSettingsActivity;
- private HdmiDeviceInfo mHdmiDeviceInfo;
- private int mLabelResId;
- // TODO: Remove when createTvInputInfo() is removed.
+ // TODO: Remove mLabel and mIconUri when createTvInputInfo() is removed.
private String mLabel;
- private Icon mIcon;
- // TODO: Remove when createTvInputInfo() is removed.
private Uri mIconUri;
- private boolean mIsConnectedToHdmiSwitch;
+
+ private final int mLabelResId;
+ private final Icon mIcon;
+ private final Icon mIconStandby;
+ private final Icon mIconDisconnected;
+
+ // Attributes from XML meta data.
+ private final String mSetupActivity;
+ private final String mSettingsActivity;
+ private final boolean mCanRecord;
+ private final int mTunerCount;
+
+ // Attributes specific to HDMI
+ private final HdmiDeviceInfo mHdmiDeviceInfo;
+ private final boolean mIsConnectedToHdmiSwitch;
+ private final String mParentId;
+
+ private final Bundle mExtras;
/**
* Create a new instance of the TvInputInfo class, instantiating it from the given Context,
@@ -239,31 +246,26 @@ public final class TvInputInfo implements Parcelable {
.build();
}
- /**
- * Constructor.
- *
- * @param service The ResolveInfo returned from the package manager about this TV input service.
- * @param id ID of this TV input. Should be generated via generateInputId*().
- * @param parentId ID of this TV input's parent input. {@code null} if none exists.
- * @param type The type of this TV input service.
- * @param isHardwareInput {@code true} if this TV input represents a hardware device.
- * {@code false} otherwise.
- * @param isConnectedToHdmiSwitch Whether a CEC device for this TV input is connected to an HDMI
- * switch, i.e., the device isn't directly connected to a HDMI port.
- * @param tunerCount The number of tuners this TV input has.
- * @param canRecord Whether this TV input can record TV programs.
- */
- private TvInputInfo(ResolveInfo service, String id, String parentId, int type,
- boolean isHardwareInput, boolean isConnectedToHdmiSwitch, int tunerCount,
- boolean canRecord, Bundle extras) {
+ private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
+ int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
+ String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
+ HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
+ Bundle extras) {
mService = service;
mId = id;
- mParentId = parentId;
mType = type;
mIsHardwareInput = isHardwareInput;
- mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
- mTunerCount = tunerCount;
+ mLabelResId = labelResId;
+ mIcon = icon;
+ mIconStandby = iconStandby;
+ mIconDisconnected = iconDisconnected;
+ mSetupActivity = setupActivity;
+ mSettingsActivity = settingsActivity;
mCanRecord = canRecord;
+ mTunerCount = tunerCount;
+ mHdmiDeviceInfo = hdmiDeviceInfo;
+ mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
+ mParentId = parentId;
mExtras = extras;
}
@@ -421,9 +423,7 @@ public final class TvInputInfo implements Parcelable {
* @param context Supplies a {@link Context} used to check if this TV input is hidden.
* @return {@code true} if the user marked this TV input hidden in settings. {@code false}
* otherwise.
- * @hide
*/
- @SystemApi
public boolean isHidden(Context context) {
return TvInputSettings.isHidden(context, mId, UserHandle.myUserId());
}
@@ -451,9 +451,7 @@ public final class TvInputInfo implements Parcelable {
* @param context Supplies a {@link Context} used to load the custom label.
* @return a CharSequence containing the TV input's custom label. {@code null} if there is no
* custom label.
- * @hide
*/
- @SystemApi
public CharSequence loadCustomLabel(Context context) {
return TvInputSettings.getCustomLabel(context, mId, UserHandle.myUserId());
}
@@ -482,6 +480,36 @@ public final class TvInputInfo implements Parcelable {
return loadServiceIcon(context);
}
+ /**
+ * Loads the user-displayed icon for this TV input per input state.
+ *
+ * @param context Supplies a {@link Context} used to load the icon.
+ * @param state The input state. Should be one of the followings.
+ * {@link TvInputManager#INPUT_STATE_CONNECTED},
+ * {@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY} and
+ * {@link TvInputManager#INPUT_STATE_DISCONNECTED}.
+ * @return a Drawable containing the TV input's icon for the given state or {@code null} if such
+ * an icon is not defined.
+ * @hide
+ */
+ @SystemApi
+ public Drawable loadIcon(@NonNull Context context, int state) {
+ if (state == TvInputManager.INPUT_STATE_CONNECTED) {
+ return loadIcon(context);
+ } else if (state == TvInputManager.INPUT_STATE_CONNECTED_STANDBY) {
+ if (mIconStandby != null) {
+ return mIconStandby.loadDrawable(context);
+ }
+ } else if (state == TvInputManager.INPUT_STATE_DISCONNECTED) {
+ if (mIconDisconnected != null) {
+ return mIconDisconnected.loadDrawable(context);
+ }
+ } else {
+ throw new IllegalArgumentException("Unknown state: " + state);
+ }
+ return null;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -503,21 +531,23 @@ public final class TvInputInfo implements Parcelable {
}
TvInputInfo obj = (TvInputInfo) o;
- return TextUtils.equals(mId, obj.mId)
- && TextUtils.equals(mParentId, obj.mParentId)
- && Objects.equals(mService, obj.mService)
- && TextUtils.equals(mSetupActivity, obj.mSetupActivity)
- && TextUtils.equals(mSettingsActivity, obj.mSettingsActivity)
+ return Objects.equals(mService, obj.mService)
+ && TextUtils.equals(mId, obj.mId)
&& mType == obj.mType
- && mTunerCount == obj.mTunerCount
- && mCanRecord == obj.mCanRecord
&& mIsHardwareInput == obj.mIsHardwareInput
- && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
- && Objects.equals(mIcon, obj.mIcon)
+ && TextUtils.equals(mLabel, obj.mLabel)
&& Objects.equals(mIconUri, obj.mIconUri)
&& mLabelResId == obj.mLabelResId
- && TextUtils.equals(mLabel, obj.mLabel)
+ && Objects.equals(mIcon, obj.mIcon)
+ && Objects.equals(mIconStandby, obj.mIconStandby)
+ && Objects.equals(mIconDisconnected, obj.mIconDisconnected)
+ && TextUtils.equals(mSetupActivity, obj.mSetupActivity)
+ && TextUtils.equals(mSettingsActivity, obj.mSettingsActivity)
+ && mCanRecord == obj.mCanRecord
+ && mTunerCount == obj.mTunerCount
+ && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
&& mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch
+ && TextUtils.equals(mParentId, obj.mParentId)
&& Objects.equals(mExtras, obj.mExtras);
}
@@ -536,21 +566,23 @@ public final class TvInputInfo implements Parcelable {
*/
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mId);
- dest.writeString(mParentId);
mService.writeToParcel(dest, flags);
- dest.writeString(mSetupActivity);
- dest.writeString(mSettingsActivity);
+ dest.writeString(mId);
dest.writeInt(mType);
- dest.writeInt(mTunerCount);
- dest.writeByte(mCanRecord ? (byte) 1 : 0);
dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
- dest.writeParcelable(mHdmiDeviceInfo, flags);
- dest.writeParcelable(mIcon, flags);
+ dest.writeString(mLabel);
dest.writeParcelable(mIconUri, flags);
dest.writeInt(mLabelResId);
- dest.writeString(mLabel);
+ dest.writeParcelable(mIcon, flags);
+ dest.writeParcelable(mIconStandby, flags);
+ dest.writeParcelable(mIconDisconnected, flags);
+ dest.writeString(mSetupActivity);
+ dest.writeString(mSettingsActivity);
+ dest.writeByte(mCanRecord ? (byte) 1 : 0);
+ dest.writeInt(mTunerCount);
+ dest.writeParcelable(mHdmiDeviceInfo, flags);
dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
+ dest.writeString(mParentId);
dest.writeBundle(mExtras);
}
@@ -576,21 +608,23 @@ public final class TvInputInfo implements Parcelable {
};
private TvInputInfo(Parcel in) {
- mId = in.readString();
- mParentId = in.readString();
mService = ResolveInfo.CREATOR.createFromParcel(in);
- mSetupActivity = in.readString();
- mSettingsActivity = in.readString();
+ mId = in.readString();
mType = in.readInt();
- mTunerCount = in.readInt();
- mCanRecord = in.readByte() == 1;
mIsHardwareInput = in.readByte() == 1;
- mHdmiDeviceInfo = in.readParcelable(null);
- mIcon = in.readParcelable(null);
+ mLabel = in.readString();
mIconUri = in.readParcelable(null);
mLabelResId = in.readInt();
- mLabel = in.readString();
+ mIcon = in.readParcelable(null);
+ mIconStandby = in.readParcelable(null);
+ mIconDisconnected = in.readParcelable(null);
+ mSetupActivity = in.readString();
+ mSettingsActivity = in.readString();
+ mCanRecord = in.readByte() == 1;
+ mTunerCount = in.readInt();
+ mHdmiDeviceInfo = in.readParcelable(null);
mIsConnectedToHdmiSwitch = in.readByte() == 1;
+ mParentId = in.readString();
mExtras = in.readBundle();
}
@@ -626,13 +660,17 @@ public final class TvInputInfo implements Parcelable {
private final Context mContext;
private final ResolveInfo mResolveInfo;
- private Icon mIcon;
private int mLabelResId;
- private int mTunerCount = 1;
- private boolean mCanRecord;
+ private Icon mIcon;
+ private Icon mIconStandby;
+ private Icon mIconDisconnected;
+ private String mSetupActivity;
+ private String mSettingsActivity;
+ private Boolean mCanRecord;
+ private Integer mTunerCount;
+ private TvInputHardwareInfo mTvInputHardwareInfo;
private HdmiDeviceInfo mHdmiDeviceInfo;
private String mParentId;
- private TvInputHardwareInfo mTvInputHardwareInfo;
private Bundle mExtras;
/**
@@ -680,6 +718,31 @@ public final class TvInputInfo implements Parcelable {
}
/**
+ * Sets the icon for a given input state.
+ *
+ * @param icon The icon that represents this TV input for the given state.
+ * @param state The input state. Should be one of the followings.
+ * {@link TvInputManager#INPUT_STATE_CONNECTED},
+ * {@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY} and
+ * {@link TvInputManager#INPUT_STATE_DISCONNECTED}.
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ * @hide
+ */
+ @SystemApi
+ public Builder setIcon(Icon icon, int state) {
+ if (state == TvInputManager.INPUT_STATE_CONNECTED) {
+ this.mIcon = icon;
+ } else if (state == TvInputManager.INPUT_STATE_CONNECTED_STANDBY) {
+ this.mIconStandby = icon;
+ } else if (state == TvInputManager.INPUT_STATE_DISCONNECTED) {
+ this.mIconDisconnected = icon;
+ } else {
+ throw new IllegalArgumentException("Unknown state: " + state);
+ }
+ return this;
+ }
+
+ /**
* Sets the label.
*
* @param resId The resource ID of the text to use.
@@ -795,20 +858,19 @@ public final class TvInputInfo implements Parcelable {
type = TYPE_HDMI;
isHardwareInput = true;
isConnectedToHdmiSwitch = (mHdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
- mTunerCount = 0;
} else if (mTvInputHardwareInfo != null) {
id = generateInputId(componentName, mTvInputHardwareInfo);
type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER);
isHardwareInput = true;
- mTunerCount = 0;
} else {
id = generateInputId(componentName);
type = TYPE_TUNER;
}
-
- TvInputInfo info = new TvInputInfo(mResolveInfo, id, mParentId, type, isHardwareInput,
- isConnectedToHdmiSwitch, mTunerCount, mCanRecord, mExtras);
- return parseServiceMetadata(type, info);
+ parseServiceMetadata(type);
+ return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabelResId, mIcon,
+ mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
+ mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
+ mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
}
private static String generateInputId(ComponentName name) {
@@ -830,7 +892,7 @@ public final class TvInputInfo implements Parcelable {
+ tvInputHardwareInfo.getDeviceId();
}
- private TvInputInfo parseServiceMetadata(int inputType, TvInputInfo info)
+ private void parseServiceMetadata(int inputType)
throws XmlPullParserException, IOException {
ServiceInfo si = mResolveInfo.serviceInfo;
PackageManager pm = mContext.getPackageManager();
@@ -857,26 +919,32 @@ public final class TvInputInfo implements Parcelable {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.TvInputService);
- info.mSetupActivity = sa.getString(
+ mSetupActivity = sa.getString(
com.android.internal.R.styleable.TvInputService_setupActivity);
if (DEBUG) {
- Log.d(TAG, "Setup activity loaded. [" + info.mSetupActivity + "] for "
- + si.name);
+ Log.d(TAG, "Setup activity loaded. [" + mSetupActivity + "] for " + si.name);
}
- if (inputType == TYPE_TUNER && TextUtils.isEmpty(info.mSetupActivity)) {
+ if (inputType == TYPE_TUNER && TextUtils.isEmpty(mSetupActivity)) {
throw new XmlPullParserException("Setup activity not found in " + si.name);
}
- info.mSettingsActivity = sa.getString(
+ mSettingsActivity = sa.getString(
com.android.internal.R.styleable.TvInputService_settingsActivity);
if (DEBUG) {
- Log.d(TAG, "Settings activity loaded. [" + info.mSettingsActivity + "] for "
+ Log.d(TAG, "Settings activity loaded. [" + mSettingsActivity + "] for "
+ si.name);
}
+ if (mCanRecord == null) {
+ mCanRecord = sa.getBoolean(
+ com.android.internal.R.styleable.TvInputService_canRecord, false);
+ }
+ if (mTunerCount == null && inputType == TYPE_TUNER) {
+ mTunerCount = sa.getInt(
+ com.android.internal.R.styleable.TvInputService_tunerCount, 1);
+ }
sa.recycle();
} catch (NameNotFoundException e) {
throw new XmlPullParserException("Unable to create context for: " + si.packageName);
}
- return info;
}
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 1cd19589cb94..2703b1ae13e8 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -83,110 +83,127 @@ public final class TvInputManager {
static final int VIDEO_UNAVAILABLE_REASON_END = 4;
/**
- * A generic reason. Video is not available due to an unspecified error.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable due to
+ * an unspecified error.
*/
public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = VIDEO_UNAVAILABLE_REASON_START;
/**
- * Video is not available because the TV input is in the middle of tuning to a new channel.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * the corresponding TV input is in the middle of tuning to a new channel.
*/
public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1;
/**
- * Video is not available due to the weak TV signal.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable due to
+ * weak TV signal.
*/
public static final int VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2;
/**
- * Video is not available because the TV input stopped the playback temporarily to buffer more
- * data.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * the corresponding TV input has stopped playback temporarily to buffer more data.
*/
public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3;
/**
- * Video is not available because the current program is audio-only.
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * the current TV program is audio-only.
*/
public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = VIDEO_UNAVAILABLE_REASON_END;
/**
- * Status prior to calling {@link TvInputService.Session#notifyTimeShiftStatusChanged}.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Unknown status. Also
+ * the status prior to calling {@code notifyTimeShiftStatusChanged}.
*/
public static final int TIME_SHIFT_STATUS_UNKNOWN = 0;
/**
- * The TV input does not support time shifting.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: The current TV input
+ * does not support time shifting.
*/
public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1;
/**
- * Time shifting is currently not available but might work again later.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Time shifting is
+ * currently unavailable but might work again later.
*/
public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2;
/**
- * Time shifting is currently available. In this status, the application assumes it can
- * pause/resume playback, seek to a specified time position and set playback rate and audio
- * mode.
+ * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
+ * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Time shifting is
+ * currently available. In this status, the application assumes it can pause/resume playback,
+ * seek to a specified time position and set playback rate and audio mode.
*/
public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
- public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
-
/**
- * RecordingError when a requested operation cannot be completed due to a problem that does not
- * fit under any other error code.
+ * Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
+ * {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
+ * yet started.
*/
- public static final int RECORDING_ERROR_UNKNOWN = 0;
+ public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
/**
- * RecordingError when an attempt to connect to a recording session has failed or the
- * established connection has been disconnected without a known reason.
+ * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
+ * completed due to a problem that does not fit under any other error codes.
*/
- public static final int RECORDING_ERROR_CONNECTION_FAILED = 1;
+ public static final int RECORDING_ERROR_UNKNOWN = 0;
/**
- * RecordingError when recording cannot proceed due to insufficient storage space.
+ * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed due to
+ * insufficient storage space.
*/
- public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2;
+ public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1;
/**
- * RecordingError when recording cannot proceed because the required recording resource is not
- * able to be allocated.
+ * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed because
+ * a required recording resource was not able to be allocated.
*/
- public static final int RECORDING_ERROR_RESOURCE_BUSY = 3;
+ public static final int RECORDING_ERROR_RESOURCE_BUSY = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_CONNECTION_FAILED,
- RECORDING_ERROR_INSUFFICIENT_SPACE, RECORDING_ERROR_RESOURCE_BUSY})
+ @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
+ RECORDING_ERROR_RESOURCE_BUSY})
public @interface RecordingError {}
/**
- * The TV input is connected.
+ * State for {@link #getInputState(String)} and
+ * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected.
*
- * <p>This state indicates that a source device is connected to the input port and is in the
- * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input.
+ * <p>This state indicates that a source device is connected to the input port and in the normal
+ * operation mode. It is mostly relevant to hardware inputs such as HDMI input.
* Non-hardware inputs are considered connected all the time.
- *
- * @see #getInputState
- * @see TvInputManager.TvInputCallback#onInputStateChanged
*/
public static final int INPUT_STATE_CONNECTED = 0;
+
/**
- * The TV input is connected but in standby mode.
+ * State for {@link #getInputState(String)} and
+ * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected but
+ * in standby mode.
*
- * <p>This state indicates that a source device is connected to the input port but is in standby
- * or low power mode. It is mostly relevant to hardware inputs such as HDMI inputs and Component
+ * <p>This state indicates that a source device is connected to the input port and in standby or
+ * low power mode. It is mostly relevant to hardware inputs such as HDMI inputs and Component
* inputs.
- *
- * @see #getInputState
- * @see TvInputManager.TvInputCallback#onInputStateChanged
*/
public static final int INPUT_STATE_CONNECTED_STANDBY = 1;
+
/**
- * The TV input is disconnected.
+ * State for {@link #getInputState(String)} and
+ * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is disconnected.
*
* <p>This state indicates that a source device is disconnected from the input port. It is
* mostly relevant to hardware inputs such as HDMI input.
*
- * @see #getInputState
- * @see TvInputManager.TvInputCallback#onInputStateChanged
*/
public static final int INPUT_STATE_DISCONNECTED = 2;
@@ -249,6 +266,14 @@ public final class TvInputManager {
public static final String META_DATA_CONTENT_RATING_SYSTEMS =
"android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+ /**
+ * Activity action to set up channel sources i.e.&nbsp;TV inputs of type
+ * {@link TvInputInfo#TYPE_TUNER}. When invoked, the system will display an appropriate UI for
+ * the user to initiate the individual setup flow provided by
+ * {@link android.R.attr#setupActivity} of each TV input service.
+ */
+ public static final String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
+
private final ITvInputManager mService;
private final Object mLock = new Object();
@@ -449,33 +474,29 @@ public final class TvInputManager {
public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
}
+ // For the recording session only
/**
- * This is called when a recording session initiated by a call to {@link
- * TvRecordingClient#connect(String, Uri)} has been established.
- */
- void onConnected(Session session) {
- }
-
- /**
- * This is called when TV program recording on the current channel has started.
- *
- * @param session A {@link TvInputManager.Session} associated with this callback.
+ * This is called when the recording session has been tuned to the given channel and is
+ * ready to start recording.
*/
- void onRecordingStarted(Session session) {
+ void onTuned(Session session) {
}
+ // For the recording session only
/**
- * This is called when TV program recording on the current channel has stopped. The passed
- * URI contains information about the new recorded program.
+ * This is called when the current recording session has stopped recording and created a
+ * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
+ * recorded program.
*
- * @param recordedProgramUri The URI for the new recorded program.
- * @see android.media.tv.TvContract.RecordedPrograms
+ * @param recordedProgramUri The URI for the newly recorded program.
**/
void onRecordingStopped(Session session, Uri recordedProgramUri) {
}
+ // For the recording session only
/**
- * This is called when an issue has occurred before or during recording.
+ * This is called when an issue has occurred. It may be called at any time after the current
+ * recording session is created until it is released.
*
* @param error The error code.
*/
@@ -632,21 +653,11 @@ public final class TvInputManager {
}
// For the recording session only
- void postConnected() {
+ void postTuned() {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onConnected(mSession);
- }
- });
- }
-
- // For the recording session only
- void postRecordingStarted() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mSessionCallback.onRecordingStarted(mSession);
+ mSessionCallback.onTuned(mSession);
}
});
}
@@ -724,11 +735,15 @@ public final class TvInputManager {
}
/**
- * This is called when the information about a given TV input has been changed.
+ * This is called when the information about an existing TV input has been updated.
+ *
+ * <p>Because the system automatically creates a <code>TvInputInfo</code> object for each TV
+ * input based on the information collected from the <code>AndroidManifest.xml</code>, this
+ * method is only called back when such information has changed dynamically.
*
- * @param inputInfo TvInputInfo object that contains the information about the TV input.
+ * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
*/
- public void onTvInputInfoChanged(TvInputInfo inputInfo) {
+ public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
}
}
@@ -781,11 +796,11 @@ public final class TvInputManager {
});
}
- public void postTvInputInfoChanged(final TvInputInfo inputInfo) {
+ public void postTvInputInfoUpdated(final TvInputInfo inputInfo) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mCallback.onTvInputInfoChanged(inputInfo);
+ mCallback.onTvInputInfoUpdated(inputInfo);
}
});
}
@@ -998,26 +1013,14 @@ public final class TvInputManager {
}
@Override
- public void onConnected(int seq) {
+ public void onTuned(int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postConnected();
- }
- }
-
- @Override
- public void onRecordingStarted(int seq) {
- synchronized (mSessionCallbackRecordMap) {
- SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
- if (record == null) {
- Log.e(TAG, "Callback not found for seq " + seq);
- return;
- }
- record.postRecordingStarted();
+ record.postTuned();
}
}
@@ -1086,10 +1089,10 @@ public final class TvInputManager {
}
@Override
- public void onTvInputInfoChanged(TvInputInfo inputInfo) {
+ public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
synchronized (mLock) {
for (TvInputCallbackRecord record : mCallbackRecords) {
- record.postTvInputInfoChanged(inputInfo);
+ record.postTvInputInfoUpdated(inputInfo);
}
}
}
@@ -1140,19 +1143,19 @@ public final class TvInputManager {
}
/**
- * Sets a new TvInputInfo object for a given input.
+ * Updates information about an existing TV input.
*
* <p>This is called internally only by {@link TvInputService}.
*
- * @param inputInfo The TvInputInfo object to set.
+ * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
* @throws IllegalArgumentException if the argument is {@code null}.
*/
- void setTvInputInfo(@NonNull TvInputInfo inputInfo) {
+ void updateTvInputInfo(@NonNull TvInputInfo inputInfo) {
Preconditions.checkNotNull(inputInfo);
try {
- mService.setTvInputInfo(inputInfo, mUserId);
+ mService.updateTvInputInfo(inputInfo, mUserId);
} catch (RemoteException e) {
- throw new RuntimeException("Error trying to set " + inputInfo, e);
+ throw new RuntimeException("Error trying to update " + inputInfo, e);
}
}
@@ -2013,48 +2016,25 @@ public final class TvInputManager {
}
/**
- * Connects to a given channel for TV program recording.
- */
- void connect(Uri channelUri) {
- connect(channelUri, null);
- }
-
- /**
- * Tunes to a given channel.
+ * Starts TV program recording in the current recording session.
*
- * @param channelUri The URI of a channel.
- * @param params Extra parameters.
- */
- void connect(@NonNull Uri channelUri, Bundle params) {
- Preconditions.checkNotNull(channelUri);
- if (mToken == null) {
- Log.w(TAG, "The session has been already released");
- return;
- }
- try {
- mService.connect(mToken, channelUri, params, mUserId);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Starts TV program recording for the current recording session.
+ * @param programHint The URI for the TV program to record as a hint, built by
+ * {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
*/
- void startRecording() {
+ void startRecording(@Nullable Uri programHint) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
- mService.startRecording(mToken, mUserId);
+ mService.startRecording(mToken, programHint, mUserId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
/**
- * Stops TV program recording for the current recording session.
+ * Stops TV program recording in the current recording session.
*/
void stopRecording() {
if (mToken == null) {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index d48b2c8b0816..db851a31d363 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -255,23 +255,29 @@ public abstract class TvInputService extends Service {
return null;
}
-
/**
- * Sets the TvInputInfo for this TV input.
+ * Updates the <code>TvInputInfo</code> for an existing TV input. A TV input service
+ * implementation may call this method to pass the application and system an up-to-date
+ * <code>TvInputInfo</code> object that describes itself.
+ *
+ * <p>The system automatically creates a <code>TvInputInfo</code> object for each TV input,
+ * based on the information collected from the <code>AndroidManifest.xml</code>, thus it is not
+ * necessary to call this method unless such information has changed dynamically.
+ * Use {@link TvInputInfo.Builder} to build a new <code>TvInputInfo</code> object.
*
- * <p>The system service automatically creates the TvInputInfo for each TV input based on
- * information collected from the AndroidManifest.xml, thus it is not necessary to call this
- * method unless the TV input has additional information to pass such as ability to record and
- * tuner count. Attempting to change information about a TV input that the calling package does
- * not own does nothing.
+ * <p>Attempting to change information about a TV input that the calling package does not own
+ * does nothing.
*
* @param context The application context.
- * @param inputInfo The TvInputInfo object that contains that new information.
+ * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
+ * @see TvInputManager.TvInputCallback#onTvInputInfoUpdated(TvInputInfo)
*/
- public static final void setTvInputInfo(Context context, TvInputInfo inputInfo) {
+ public static final void updateTvInputInfo(Context context, TvInputInfo inputInfo) {
TvInputManager manager = (TvInputManager) context.getSystemService(
Context.TV_INPUT_SERVICE);
- manager.setTvInputInfo(inputInfo);
+ if (manager != null) {
+ manager.updateTvInputInfo(inputInfo);
+ }
}
private boolean isPassthroughInput(String inputId) {
@@ -1545,7 +1551,7 @@ public abstract class TvInputService extends Service {
private final List<Runnable> mPendingActions = new ArrayList<>();
/**
- * Creates a new Recording Session for TV program recording.
+ * Creates a new RecordingSession.
*
* @param context The context of the application
*/
@@ -1554,51 +1560,41 @@ public abstract class TvInputService extends Service {
}
/**
- * Informs the application that recording session has been connected.
- */
- public void notifyConnected() {
- executeOrPostRunnableOnMainThread(new Runnable() {
- @MainThread
- @Override
- public void run() {
- try {
- if (DEBUG) Log.d(TAG, "notifyConnected");
- if (mSessionCallback != null) {
- mSessionCallback.onConnected();
- }
- } catch (RemoteException e) {
- Log.w(TAG, "error in notifyConnected", e);
- }
- }
- });
- }
-
- /**
- * Informs the application that recording has started.
+ * Informs the application that this recording session has been tuned to the given channel
+ * and is ready to start recording.
+ *
+ * <p>Upon receiving a call to {@link #onTune(Uri)}, the session is expected to tune to the
+ * passed channel and call this method to indicate that it is now available for immediate
+ * recording. When {@link #onStartRecording(Uri)} is called, recording must start with
+ * minimal delay.
*/
- public void notifyRecordingStarted() {
+ public void notifyTuned() {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
- if (DEBUG) Log.d(TAG, "notifyRecordingStarted");
+ if (DEBUG) Log.d(TAG, "notifyTuned");
if (mSessionCallback != null) {
- mSessionCallback.onRecordingStarted();
+ mSessionCallback.onTuned();
}
} catch (RemoteException e) {
- Log.w(TAG, "error in notifyRecordingStarted", e);
+ Log.w(TAG, "error in notifyTuned", e);
}
}
});
}
/**
- * Informs the application that recording has stopped successfully. Each TV input service
- * should create a new data entry in the recorded programs table upon completion of the
- * recording and send its URI.
+ * Informs the application that this recording session has stopped recording and created a
+ * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
+ * recorded program.
+ *
+ * <p>The recording session must call this method in response to {@link #onStopRecording()}.
+ * The session may call it even before receiving a call to {@link #onStopRecording()} if a
+ * partially recorded program is available when there is an error.
*
- * @param recordedProgramUri The URI of the new recorded program.
+ * @param recordedProgramUri The URI of the newly recorded program.
*/
public void notifyRecordingStopped(final Uri recordedProgramUri) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1618,12 +1614,18 @@ public abstract class TvInputService extends Service {
}
/**
- * Sends an error to the application at any moment.
+ * Informs the application that there is an error and this recording session is no longer
+ * able to start or continue recording. It may be called at any time after the recording
+ * session is created until {@link #onRelease()} is called.
+ *
+ * <p>The application may release the current session upon receiving the error code through
+ * {@link TvRecordingClient.RecordingCallback#onError(int)}. The session may call
+ * {@link #notifyRecordingStopped(Uri)} if a partially recorded but still playable program
+ * is available, before calling this method.
*
* @param error The error code. Should be one of the followings.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
- * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
* <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
* <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
* </ul>
@@ -1672,45 +1674,74 @@ public abstract class TvInputService extends Service {
}
/**
- * Called when the recording session is connected.
+ * Called when the application requests to tune to a given channel for TV program recording.
*
- * @param channelUri The URI of the channel.
+ * <p>The application may call this method before starting or after stopping recording, but
+ * not during recording.
+ *
+ * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+ * {@link #notifyError(int)} otherwise.
+ *
+ * @param channelUri The URI of a channel.
*/
- public abstract void onConnect(Uri channelUri);
+ public abstract void onTune(Uri channelUri);
/**
- * Called when the recording session is connected.
+ * Called when the application requests to tune to a given channel for TV program recording.
*
- * @param channelUri The URI of the channel.
+ * <p>The application may call this method before starting or after stopping recording, but
+ * not during recording.
+ *
+ * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+ * {@link #notifyError(int)} otherwise.
+ *
+ * @param channelUri The URI of a channel.
* @param params Extra parameters.
* @hide
*/
@SystemApi
- public void onConnect(Uri channelUri, Bundle params) {
- onConnect(channelUri);
+ public void onTune(Uri channelUri, Bundle params) {
+ onTune(channelUri);
}
/**
- * Called when the application requests to disconnect the current recording session.
+ * Called when the application requests to start TV program recording. Recording must start
+ * immediately when this method is called.
+ *
+ * <p>The application may supply the URI for a TV program as a hint for filling in program
+ * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+ * A non-null {@code programHint} implies the started recording should be of that specific
+ * program, whereas null {@code programHint} does not impose such a requirement and the
+ * recording can span across multiple TV programs. In either case, the application must call
+ * {@link TvRecordingClient#stopRecording()} to stop the recording.
+ *
+ * <p>The session must call {@link #notifyError(int)} if the start request cannot be
+ * fulfilled.
+ *
+ * @param programHint The URI for the TV program to record as a hint, built by
+ * {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
*/
- public abstract void onDisconnect();
+ public abstract void onStartRecording(@Nullable Uri programHint);
/**
- * Called when the application requests to start recording. Recording must start
- * immediately.
+ * Called when the application requests to stop TV program recording. Recording must stop
+ * immediately when this method is called.
+ *
+ * <p>The session must create a new data entry in the
+ * {@link android.media.tv.TvContract.RecordedPrograms} table that describes the newly
+ * recorded program and call {@link #notifyRecordingStopped(Uri)} with the URI to that
+ * entry.
+ * If the stop request cannot be fulfilled, the session must call {@link #notifyError(int)}.
*
- * <p>The session must call either {@link #notifyRecordingStarted()} or
- * {@link #notifyError(int)}}.
*/
- public abstract void onStartRecording();
+ public abstract void onStopRecording();
+
/**
- * Called when the application requests to stop recording. Recording must stop immediately.
- *
- * <p>The session must call either {@link #notifyRecordingStopped(Uri)} or
- * {@link #notifyError(int)}}.
+ * Called when the application requests to release all the resources held by this recording
+ * session.
*/
- public abstract void onStopRecording();
+ public abstract void onRelease();
/**
* Processes a private command sent from the application to the TV input. This can be used
@@ -1728,27 +1759,27 @@ public abstract class TvInputService extends Service {
}
/**
- * Calls {@link #onConnect(Uri, Bundle)}.
+ * Calls {@link #onTune(Uri, Bundle)}.
*
*/
- void connect(Uri channelUri, Bundle params) {
- onConnect(channelUri, params);
+ void tune(Uri channelUri, Bundle params) {
+ onTune(channelUri, params);
}
/**
- * Calls {@link #onDisconnect()}.
+ * Calls {@link #onRelease()}.
*
*/
- void disconnect() {
- onDisconnect();
+ void release() {
+ onRelease();
}
/**
- * Calls {@link #onStartRecording()}.
+ * Calls {@link #onStartRecording(Uri)}.
*
*/
- void startRecording() {
- onStartRecording();
+ void startRecording(@Nullable Uri programHint) {
+ onStartRecording(programHint);
}
/**
@@ -1907,6 +1938,15 @@ public abstract class TvInputService extends Service {
* </ul>
*/
public void onHardwareVideoUnavailable(int reason) { }
+
+ @Override
+ void release() {
+ if (mHardwareSession != null) {
+ mHardwareSession.release();
+ mHardwareSession = null;
+ }
+ super.release();
+ }
}
/** @hide */
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 1d80068fbdf8..1c920f57de2a 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -17,8 +17,10 @@
package android.media.tv;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
+import android.media.tv.TvInputManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -45,12 +47,14 @@ public class TvRecordingClient {
private TvInputManager.Session mSession;
private MySessionCallback mSessionCallback;
+ private boolean mIsRecordingStarted;
+ private boolean mIsTuned;
private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
/**
* Creates a new TvRecordingClient object.
*
- * @param context The application context to create the TvRecordingClient with.
+ * @param context The application context to create a TvRecordingClient with.
* @param tag A short name for debugging purposes.
* @param callback The callback to receive recording status changes.
* @param handler The handler to invoke the callback on.
@@ -63,25 +67,37 @@ public class TvRecordingClient {
}
/**
- * Connects to a given input for TV program recording. This will create a new recording session
- * from the TV input and establishes the connection between the application and the session.
+ * Tunes to a given channel for TV program recording. The first tune request will create a new
+ * recording session for the corresponding TV input and establish a connection between the
+ * application and the session. If recording has already started in the current recording
+ * session, this method throws an exception.
+ *
+ * <p>The application may call this method before starting or after stopping recording, but not
+ * during recording.
*
* <p>The recording session will respond by calling
- * {@link RecordingCallback#onConnected()} or {@link RecordingCallback#onError(int)}.
+ * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+ * {@link RecordingCallback#onError(int)} otherwise.
*
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel.
*/
- public void connect(String inputId, Uri channelUri) {
- connect(inputId, channelUri, null);
+ public void tune(String inputId, Uri channelUri) {
+ tune(inputId, channelUri, null);
}
/**
- * Connects to a given input for TV program recording. This will create a new recording session
- * from the TV input and establishes the connection between the application and the session.
+ * Tunes to a given channel for TV program recording. The first tune request will create a new
+ * recording session for the corresponding TV input and establish a connection between the
+ * application and the session. If recording has already started in the current recording
+ * session, this method throws an exception.
+ *
+ * <p>The application may call this method before starting or after stopping recording, but not
+ * during recording.
*
* <p>The recording session will respond by calling
- * {@link RecordingCallback#onConnected()} or {@link RecordingCallback#onError(int)}.
+ * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+ * {@link RecordingCallback#onError(int)} otherwise.
*
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel.
@@ -89,14 +105,17 @@ public class TvRecordingClient {
* @hide
*/
@SystemApi
- public void connect(String inputId, Uri channelUri, Bundle params) {
- if (DEBUG) Log.d(TAG, "connect(" + channelUri + ")");
+ public void tune(String inputId, Uri channelUri, Bundle params) {
+ if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
if (TextUtils.isEmpty(inputId)) {
throw new IllegalArgumentException("inputId cannot be null or an empty string");
}
+ if (mIsRecordingStarted) {
+ throw new IllegalStateException("tune failed - recording already started");
+ }
if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
if (mSession != null) {
- mSession.connect(channelUri, params);
+ mSession.tune(channelUri, params);
} else {
mSessionCallback.mChannelUri = channelUri;
mSessionCallback.mConnectionParams = params;
@@ -111,13 +130,11 @@ public class TvRecordingClient {
}
/**
- * Disconnects the established connection between the application and the recording session.
- *
- * <p>The recording session will respond by calling
- * {@link RecordingCallback#onDisconnected()} or {@link RecordingCallback#onError(int)}.
+ * Releases the resources in the current recording session immediately. This may be called at
+ * any time, however if the session is already released, it does nothing.
*/
- public void disconnect() {
- if (DEBUG) Log.d(TAG, "disconnect()");
+ public void release() {
+ if (DEBUG) Log.d(TAG, "release()");
resetInternal();
}
@@ -131,34 +148,57 @@ public class TvRecordingClient {
}
/**
- * Starts TV program recording for the current recording session. It is expected that recording
- * starts immediately after calling this method.
+ * Starts TV program recording in the current recording session. Recording is expected to start
+ * immediately when this method is called. If the current recording session has not yet tuned to
+ * any channel, this method throws an exception.
*
- * <p>The recording session will respond by calling
- * {@link RecordingCallback#onRecordingStarted()} or {@link RecordingCallback#onError(int)}.
+ * <p>The application may supply the URI for a TV program as a hint for filling in program
+ * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+ * A non-null {@code programHint} implies the started recording should be of that specific
+ * program, whereas null {@code programHint} does not impose such a requirement and the
+ * recording can span across multiple TV programs. In either case, the application must call
+ * {@link TvRecordingClient#stopRecording()} to stop the recording.
+ *
+ * <p>The recording session will respond by calling {@link RecordingCallback#onError(int)} if
+ * the start request cannot be fulfilled.
+ *
+ * @param programHint The URI for the TV program to record as a hint, built by
+ * {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
*/
- public void startRecording() {
+ public void startRecording(@Nullable Uri programHint) {
+ if (!mIsTuned) {
+ throw new IllegalStateException("startRecording failed - not yet tuned");
+ }
if (mSession != null) {
- mSession.startRecording();
+ mSession.startRecording(programHint);
+ mIsRecordingStarted = true;
}
}
/**
- * Stops TV program recording for the current recording session. It is expected that recording
- * stops immediately after calling this method.
+ * Stops TV program recording in the current recording session. Recording is expected to stop
+ * immediately when this method is called. If recording has not yet started in the current
+ * recording session, this method does nothing.
*
- * <p>The recording session will respond by calling
- * {@link RecordingCallback#onRecordingStopped(Uri)} or {@link RecordingCallback#onError(int)}.
+ * <p>The recording session is expected to create a new data entry in the
+ * {@link android.media.tv.TvContract.RecordedPrograms} table that describes the newly
+ * recorded program and pass the URI to that entry through to
+ * {@link RecordingCallback#onRecordingStopped(Uri)}.
+ * If the stop request cannot be fulfilled, the recording session will respond by calling
+ * {@link RecordingCallback#onError(int)}.
*/
public void stopRecording() {
+ if (!mIsRecordingStarted) {
+ Log.w(TAG, "stopRecording failed - recording not yet started");
+ }
if (mSession != null) {
mSession.stopRecording();
}
}
/**
- * Calls {@link TvInputService.RecordingSession#appPrivateCommand(String, Bundle)
- * TvInputService.RecordingSession.appPrivateCommand()} on the current TvView.
+ * Calls {@link TvInputService.RecordingSession#appPrivateCommand(String, Bundle)} for the
+ * current recording session.
*
* @param action The name of the private command to send. This <em>must</em> be a scoped name,
* i.e. prefixed with a package name you own, so that different developers will not
@@ -186,46 +226,46 @@ public class TvRecordingClient {
*/
public abstract static class RecordingCallback {
/**
- * This is called when a recording session initiated by a call to
- * {@link #connect(String, Uri)} has been established.
+ * This is called when an error occurred while establishing a connection to the recording
+ * session for the corresponding TV input.
+ *
+ * @param inputId The ID of the TV input bound to the current TvRecordingClient.
*/
- public void onConnected() {
+ public void onConnectionFailed(String inputId) {
}
/**
- * This is called when the established connection between the application and the recording
- * session has been disconnected. Disconnection can be initiated either by an explicit
- * request (i.e. a call to {@link #disconnect()} or by an error on the TV input service
- * side.
+ * This is called when the connection to the current recording session is lost.
+ *
+ * @param inputId The ID of the TV input bound to the current TvRecordingClient.
*/
- public void onDisconnected() {
+ public void onDisconnected(String inputId) {
}
/**
- * This is called when TV program recording on the current channel has started.
+ * This is called when the recording session has been tuned to the given channel and is
+ * ready to start recording.
*/
- public void onRecordingStarted() {
+ public void onTuned() {
}
/**
- * This is called when TV program recording on the current channel has stopped. The passed
- * URI contains information about the new recorded program.
+ * This is called when the current recording session has stopped recording and created a
+ * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
+ * recorded program.
*
- * @param recordedProgramUri The URI for the new recorded program.
- * @see android.media.tv.TvContract.RecordedPrograms
+ * @param recordedProgramUri The URI for the newly recorded program.
*/
public void onRecordingStopped(Uri recordedProgramUri) {
}
/**
- * This is called when an issue has occurred before or during recording. If the TV input
- * service cannot proceed recording due to this error, a call to {@link #onDisconnected()}
- * is expected to follow.
+ * This is called when an issue has occurred. It may be called at any time after the current
+ * recording session is created until it is released.
*
* @param error The error code. Should be one of the followings.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
- * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
* <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
* <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
* </ul>
@@ -277,23 +317,26 @@ public class TvRecordingClient {
mSession.sendAppPrivateCommand(command.first, command.second);
}
mPendingAppPrivateCommands.clear();
- mSession.connect(mChannelUri, mConnectionParams);
+ mSession.tune(mChannelUri, mConnectionParams);
} else {
mSessionCallback = null;
- mCallback.onError(TvInputManager.RECORDING_ERROR_CONNECTION_FAILED);
+ if (mCallback != null) {
+ mCallback.onConnectionFailed(mInputId);
+ }
}
}
@Override
- void onConnected(TvInputManager.Session session) {
+ void onTuned(TvInputManager.Session session) {
if (DEBUG) {
- Log.d(TAG, "onConnected()");
+ Log.d(TAG, "onTuned()");
}
if (this != mSessionCallback) {
- Log.w(TAG, "onConnected - session not created");
+ Log.w(TAG, "onTuned - session not created");
return;
}
- mCallback.onConnected();
+ mIsTuned = true;
+ mCallback.onTuned();
}
@Override
@@ -305,39 +348,32 @@ public class TvRecordingClient {
Log.w(TAG, "onSessionReleased - session not created");
return;
}
+ mIsTuned = false;
+ mIsRecordingStarted = false;
mSessionCallback = null;
mSession = null;
- mCallback.onDisconnected();
- }
-
- @Override
- public void onRecordingStarted(TvInputManager.Session session) {
- if (DEBUG) {
- Log.d(TAG, "onRecordingStarted()");
- }
- if (this != mSessionCallback) {
- Log.w(TAG, "onRecordingStarted - session not created");
- return;
+ if (mCallback != null) {
+ mCallback.onDisconnected(mInputId);
}
- mCallback.onRecordingStarted();
}
@Override
public void onRecordingStopped(TvInputManager.Session session, Uri recordedProgramUri) {
if (DEBUG) {
- Log.d(TAG, "onRecordingStopped()");
+ Log.d(TAG, "onRecordingStopped(recordedProgramUri= " + recordedProgramUri + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onRecordingStopped - session not created");
return;
}
+ mIsRecordingStarted = false;
mCallback.onRecordingStopped(recordedProgramUri);
}
@Override
public void onError(TvInputManager.Session session, int error) {
if (DEBUG) {
- Log.d(TAG, "onError()");
+ Log.d(TAG, "onError(error=" + error + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onError - session not created");
@@ -350,7 +386,8 @@ public class TvRecordingClient {
public void onSessionEvent(TvInputManager.Session session, String eventType,
Bundle eventArgs) {
if (DEBUG) {
- Log.d(TAG, "onSessionEvent(" + eventType + ")");
+ Log.d(TAG, "onSessionEvent(eventType=" + eventType + ", eventArgs=" + eventArgs
+ + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onSessionEvent - session not created");
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index ed432c463b8a..6a44b1e6e4e9 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -52,11 +52,14 @@ public final class TvTrackInfo implements Parcelable {
private final int mVideoHeight;
private final float mVideoFrameRate;
private final float mVideoPixelAspectRatio;
+ private final byte mVideoActiveFormatDescription;
+
private final Bundle mExtra;
private TvTrackInfo(int type, String id, String language, CharSequence description,
int audioChannelCount, int audioSampleRate, int videoWidth, int videoHeight,
- float videoFrameRate, float videoPixelAspectRatio, Bundle extra) {
+ float videoFrameRate, float videoPixelAspectRatio, byte videoActiveFormatDescription,
+ Bundle extra) {
mType = type;
mId = id;
mLanguage = language;
@@ -67,6 +70,7 @@ public final class TvTrackInfo implements Parcelable {
mVideoHeight = videoHeight;
mVideoFrameRate = videoFrameRate;
mVideoPixelAspectRatio = videoPixelAspectRatio;
+ mVideoActiveFormatDescription = videoActiveFormatDescription;
mExtra = extra;
}
@@ -81,6 +85,7 @@ public final class TvTrackInfo implements Parcelable {
mVideoHeight = in.readInt();
mVideoFrameRate = in.readFloat();
mVideoPixelAspectRatio = in.readFloat();
+ mVideoActiveFormatDescription = in.readByte();
mExtra = in.readBundle();
}
@@ -179,6 +184,20 @@ public final class TvTrackInfo implements Parcelable {
}
/**
+ * Returns the Active Format Description (AFD) code of the video.
+ * Valid only for {@link #TYPE_VIDEO} tracks.
+ *
+ * <p>The complete list of values are defined in ETSI TS 101 154 V1.7.1 Annex B, ATSC A/53 Part
+ * 4 and SMPTE 2016-1-2007.
+ */
+ public final byte getVideoActiveFormatDescription() {
+ if (mType != TYPE_VIDEO) {
+ throw new IllegalStateException("Not a video track");
+ }
+ return mVideoActiveFormatDescription;
+ }
+
+ /**
* Returns the extra information about the current track.
*/
public final Bundle getExtra() {
@@ -208,6 +227,7 @@ public final class TvTrackInfo implements Parcelable {
dest.writeInt(mVideoHeight);
dest.writeFloat(mVideoFrameRate);
dest.writeFloat(mVideoPixelAspectRatio);
+ dest.writeByte(mVideoActiveFormatDescription);
dest.writeBundle(mExtra);
}
@@ -238,6 +258,7 @@ public final class TvTrackInfo implements Parcelable {
private int mVideoHeight;
private float mVideoFrameRate;
private float mVideoPixelAspectRatio = 1.0f;
+ private byte mVideoActiveFormatDescription;
private Bundle mExtra;
/**
@@ -368,6 +389,25 @@ public final class TvTrackInfo implements Parcelable {
}
/**
+ * Sets the Active Format Description (AFD) code of the video.
+ * Valid only for {@link #TYPE_VIDEO} tracks.
+ *
+ * <p>This is needed for applications to be able to scale the video properly based on the
+ * information about where in the coded picture the active video is.
+ * The complete list of values are defined in ETSI TS 101 154 V1.7.1 Annex B, ATSC A/53 Part
+ * 4 and SMPTE 2016-1-2007.
+ *
+ * @param videoActiveFormatDescription The AFD code of the video.
+ */
+ public final Builder setVideoActiveFormatDescription(byte videoActiveFormatDescription) {
+ if (mType != TYPE_VIDEO) {
+ throw new IllegalStateException("Not a video track");
+ }
+ mVideoActiveFormatDescription = videoActiveFormatDescription;
+ return this;
+ }
+
+ /**
* Sets the extra information about the current track.
*
* @param extra The extra information.
@@ -385,7 +425,7 @@ public final class TvTrackInfo implements Parcelable {
public TvTrackInfo build() {
return new TvTrackInfo(mType, mId, mLanguage, mDescription, mAudioChannelCount,
mAudioSampleRate, mVideoWidth, mVideoHeight, mVideoFrameRate,
- mVideoPixelAspectRatio, mExtra);
+ mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra);
}
}
}
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 0132d2438470..5c4b52883391 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -539,8 +539,8 @@ public class TvView extends ViewGroup {
}
/**
- * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
- * TvInputService.Session.appPrivateCommand()} on the current TvView.
+ * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)} for the current
+ * session.
*
* @param action The name of the private command to send. This <em>must</em> be a scoped name,
* i.e. prefixed with a package name you own, so that different developers will not
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 3372524d138c..480acd991283 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -121,7 +121,7 @@ public abstract class MediaBrowserService extends Service {
* be thrown.
*
* @see MediaBrowserService#onLoadChildren
- * @see MediaBrowserService#onGetMediaItem
+ * @see MediaBrowserService#onLoadItem
*/
public class Result<T> {
private Object mDebug;
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a326f6feba45..fa9c48c59af0 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -43,14 +43,10 @@ LOCAL_SHARED_LIBRARIES := \
libcamera_client \
libmtp \
libusbhost \
- libjhead \
libexif \
libpiex \
libstagefright_amrnb_common
-LOCAL_REQUIRED_MODULES := \
- libjhead_jni
-
LOCAL_STATIC_LIBRARIES := \
libstagefright_amrnbenc
diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
index ba38569af8e8..f7481af776b9 100644
--- a/media/jni/android_media_ExifInterface.cpp
+++ b/media/jni/android_media_ExifInterface.cpp
@@ -83,28 +83,27 @@ static void ExifInterface_initRaw(JNIEnv *env) {
}
static jobject ExifInterface_getRawMetadata(
- JNIEnv* env, jclass /* clazz */, jstring jfilename) {
- const char* filenameChars = env->GetStringUTFChars(jfilename, NULL);
- if (filenameChars == NULL) {
+ JNIEnv* env, jclass /* clazz */, jobject jfileDescriptor) {
+ int fd = jniGetFDFromFileDescriptor(env, jfileDescriptor);
+ if (fd < 0) {
+ ALOGI("Invalid file descriptor");
return NULL;
}
- String8 filename(filenameChars);
- env->ReleaseStringUTFChars(jfilename, filenameChars);
piex::PreviewImageData image_data;
- std::unique_ptr<FileStream> stream(new FileStream(filename));
+ std::unique_ptr<FileStream> stream(new FileStream(fd));
- if (!GetExifFromRawImage(stream.get(), filename, image_data)) {
- ALOGI("Raw image not detected: %s", filename.string());
+ if (!GetExifFromRawImage(stream.get(), String8("[file descriptor]"), image_data)) {
+ ALOGI("Raw image not detected");
return NULL;
}
KeyedVector<String8, String8> map;
- if (image_data.thumbnail_length > 0) {
+ if (image_data.thumbnail.length > 0) {
map.add(String8("hasThumbnail"), String8("true"));
- map.add(String8("thumbnailOffset"), String8::format("%d", image_data.thumbnail_offset));
- map.add(String8("thumbnailLength"), String8::format("%d", image_data.thumbnail_length));
+ map.add(String8("thumbnailOffset"), String8::format("%d", image_data.thumbnail.offset));
+ map.add(String8("thumbnailLength"), String8::format("%d", image_data.thumbnail.length));
} else {
map.add(String8("hasThumbnail"), String8("false"));
}
@@ -263,7 +262,7 @@ static jobject ExifInterface_getRawMetadata(
static JNINativeMethod gMethods[] = {
{ "initRawNative", "()V", (void *)ExifInterface_initRaw },
- { "getRawAttributesNative", "(Ljava/lang/String;)Ljava/util/HashMap;",
+ { "getRawAttributesNative", "(Ljava/io/FileDescriptor;)Ljava/util/HashMap;",
(void*)ExifInterface_getRawMetadata },
};
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 4ac62f57a719..9e90a19f00cc 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -1264,6 +1264,14 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
static_cast<PublicFormat>(readerFormat));
int32_t fmt = applyFormatOverrides(buffer->flexFormat, readerHalFormat);
+ // Override the image format to HAL_PIXEL_FORMAT_YCbCr_420_888 if the actual format is
+ // NV21 or YV12. This could only happen when the Gralloc HAL version is v0.1 thus doesn't
+ // support lockycbcr(), the CpuConsumer need to use the lock() method in the
+ // lockNextBuffer() call. For Gralloc HAL v0.2 or newer, this format should already be
+ // overridden to HAL_PIXEL_FORMAT_YCbCr_420_888 for the flexible YUV compatible formats.
+ if (fmt == HAL_PIXEL_FORMAT_YCrCb_420_SP || fmt == HAL_PIXEL_FORMAT_YV12) {
+ fmt = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ }
PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
fmt, buffer->dataSpace);
return static_cast<jint>(publicFmt);
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index e414f4838583..35da84ce82e5 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -25,7 +25,9 @@
#include "JNIHelp.h"
#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
#include <media/ICrypto.h>
+#include <media/IMediaDrmService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -61,19 +63,30 @@ JCrypto::~JCrypto() {
// static
sp<ICrypto> JCrypto::MakeCrypto() {
sp<IServiceManager> sm = defaultServiceManager();
-
- sp<IBinder> binder =
- sm->getService(String16("media.player"));
-
- sp<IMediaPlayerService> service =
- interface_cast<IMediaPlayerService>(binder);
-
- if (service == NULL) {
- return NULL;
+ sp<ICrypto> crypto;
+
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.mediadrmservice.enable", value, NULL)
+ && (!strcmp("1", value) || !strcasecmp("true", value))) {
+ sp<IBinder> binder =
+ sm->getService(String16("media.drm"));
+ sp<IMediaDrmService> service =
+ interface_cast<IMediaDrmService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ crypto = service->makeCrypto();
+ } else {
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ crypto = service->makeCrypto();
}
- sp<ICrypto> crypto = service->makeCrypto();
-
if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
return NULL;
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index b8849c6e1879..73ddedf2bec1 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -28,7 +28,9 @@
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
+#include <cutils/properties.h>
#include <media/IDrm.h>
+#include <media/IMediaDrmService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
@@ -352,19 +354,30 @@ JDrm::~JDrm() {
// static
sp<IDrm> JDrm::MakeDrm() {
sp<IServiceManager> sm = defaultServiceManager();
-
- sp<IBinder> binder =
- sm->getService(String16("media.player"));
-
- sp<IMediaPlayerService> service =
- interface_cast<IMediaPlayerService>(binder);
-
- if (service == NULL) {
- return NULL;
+ sp<IDrm> drm;
+
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.mediadrmservice.enable", value, NULL)
+ && (!strcmp("1", value) || !strcasecmp("true", value))) {
+ sp<IBinder> binder =
+ sm->getService(String16("media.drm"));
+ sp<IMediaDrmService> service =
+ interface_cast<IMediaDrmService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ drm = service->makeDrm();
+ } else {
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+ if (service == NULL) {
+ return NULL;
+ }
+ drm = service->makeDrm();
}
- sp<IDrm> drm = service->makeDrm();
-
if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
return NULL;
}
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index c08a5e3daa5a..9c4f7c4b2aff 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -28,6 +28,19 @@
namespace android {
+FileStream::FileStream(const int fd)
+ : mPosition(0),
+ mSize(0) {
+ mFile = fdopen(fd, "r");
+ if (mFile == NULL) {
+ return;
+ }
+ // Get the size.
+ fseek(mFile, 0l, SEEK_END);
+ mSize = ftell(mFile);
+ fseek(mFile, 0l, SEEK_SET);
+}
+
FileStream::FileStream(const String8 filename)
: mPosition(0),
mSize(0) {
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 762c90458d01..a30e1be586f9 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -35,6 +35,7 @@ private:
size_t mSize;
public:
+ FileStream(const int fd);
FileStream(const String8 filename);
~FileStream();
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 6b9fdb65e50d..7c1142bfffc4 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -7,6 +7,8 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
LOCAL_STATIC_JAVA_LIBRARIES := easymocklib \
mockito-target \
core-tests \
diff --git a/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpg b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpg
new file mode 100644
index 000000000000..477cd3a574c3
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_ii.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpg b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpg
new file mode 100644
index 000000000000..78ac703850a1
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/image_exif_byte_order_mm.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dng b/media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dng
new file mode 100644
index 000000000000..5fcc720a5f8f
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/lg_g4_iso_800.dng
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
new file mode 100644
index 000000000000..8fc6adcb0dd9
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
@@ -0,0 +1,108 @@
+<?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>
+ <array name="exifbyteorderii_jpg">
+ <item>true</item>
+ <item>512</item>
+ <item>288</item>
+ <item>false</item>
+ <item>0.0</item>
+ <item>0.0</item>
+ <item>0.0</item>
+ <item>SAMSUNG</item>
+ <item>SM-N900S</item>
+ <item>2.200</item>
+ <item>2016:01:29 18:32:27</item>
+ <item>0.033</item>
+ <item>0</item>
+ <item>413/100</item>
+ <item />
+ <item />
+ <item />
+ <item />
+ <item />
+ <item />
+ <item />
+ <item />
+ <item />
+ <item>480</item>
+ <item>640</item>
+ <item>50</item>
+ <item>6</item>
+ <item>0</item>
+ </array>
+ <array name="exifbyteordermm_jpg">
+ <item>false</item>
+ <item>0</item>
+ <item>0</item>
+ <item>true</item>
+ <item>0.0</item>
+ <item>0.0</item>
+ <item>0.0</item>
+ <item>LGE</item>
+ <item>Nexus 5</item>
+ <item>2.400</item>
+ <item>2016:01:29 15:44:58</item>
+ <item>0.017</item>
+ <item>0</item>
+ <item>3970/1000</item>
+ <item>0/1000</item>
+ <item>0</item>
+ <item>1970:01:01</item>
+ <item>0/1,0/1,0/10000</item>
+ <item>N</item>
+ <item>0/1,0/1,0/10000</item>
+ <item>E</item>
+ <item>GPS</item>
+ <item>00:00:00</item>
+ <item>176</item>
+ <item>144</item>
+ <item>146</item>
+ <item>0</item>
+ <item>0</item>
+ </array>
+ <array name="lg_g4_iso_800_dng">
+ <item>false</item>
+ <item>0</item>
+ <item>0</item>
+ <item>true</item>
+ <item>53.834507</item>
+ <item>10.69585</item>
+ <item>0.0</item>
+ <item>LGE</item>
+ <item>LG-H815</item>
+ <item>1.800</item>
+ <item>2015:11:12 16:46:18</item>
+ <item>0.0040</item>
+ <item>0.0</item>
+ <item>442/100</item>
+ <item>0/1</item>
+ <item>0</item>
+ <item>1970:01:17</item>
+ <item>53/1,50/1,423/100</item>
+ <item>N</item>
+ <item>10/1,41/1,4506/100</item>
+ <item>E</item>
+ <item />
+ <item>18:08:10</item>
+ <item>337</item>
+ <item>600</item>
+ <item>800</item>
+ <item>1</item>
+ <item />
+ </array>
+</resources>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 11d90700bffd..61dede34bb5c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -50,6 +50,7 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
addMediaScannerUnitTests(suite);
addCameraUnitTests(suite);
addImageReaderTests(suite);
+ addExifInterfaceTests(suite);
return suite;
}
@@ -109,4 +110,8 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
private void addMediaScannerUnitTests(TestSuite suite) {
suite.addTestSuite(MediaInserterTest.class);
}
+
+ private void addExifInterfaceTests(TestSuite suite) {
+ suite.addTestSuite(ExifInterfaceTest.class);
+ }
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
new file mode 100644
index 000000000000..1c80746eb445
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -0,0 +1,418 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import com.android.mediaframeworktest.R;
+
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.ExifInterface;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.lang.reflect.Type;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+public class ExifInterfaceTest extends AndroidTestCase {
+ private static final String TAG = ExifInterface.class.getSimpleName();
+ private static final boolean VERBOSE = false; // lots of logging
+
+ private static final double DIFFERENCE_TOLERANCE = .005;
+ private static final int BUFFER_SIZE = 32768;
+
+ // List of files.
+ private static final String EXIF_BYTE_ORDER_II_JPEG = "ExifByteOrderII.jpg";
+ private static final String EXIF_BYTE_ORDER_MM_JPEG = "ExifByteOrderMM.jpg";
+ private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
+ private static final int[] IMAGE_RESOURCES = new int[] {
+ R.raw.image_exif_byte_order_ii, R.raw.image_exif_byte_order_mm, R.raw.lg_g4_iso_800 };
+ private static final String[] IMAGE_FILENAMES = new String[] {
+ EXIF_BYTE_ORDER_II_JPEG, EXIF_BYTE_ORDER_MM_JPEG, LG_G4_ISO_800_DNG };
+
+ private static final String[] EXIF_TAGS = {
+ ExifInterface.TAG_MAKE,
+ ExifInterface.TAG_MODEL,
+ ExifInterface.TAG_APERTURE,
+ ExifInterface.TAG_DATETIME,
+ ExifInterface.TAG_EXPOSURE_TIME,
+ ExifInterface.TAG_FLASH,
+ ExifInterface.TAG_FOCAL_LENGTH,
+ ExifInterface.TAG_GPS_ALTITUDE,
+ ExifInterface.TAG_GPS_ALTITUDE_REF,
+ ExifInterface.TAG_GPS_DATESTAMP,
+ ExifInterface.TAG_GPS_LATITUDE,
+ ExifInterface.TAG_GPS_LATITUDE_REF,
+ ExifInterface.TAG_GPS_LONGITUDE,
+ ExifInterface.TAG_GPS_LONGITUDE_REF,
+ ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ ExifInterface.TAG_GPS_TIMESTAMP,
+ ExifInterface.TAG_IMAGE_LENGTH,
+ ExifInterface.TAG_IMAGE_WIDTH,
+ ExifInterface.TAG_ISO,
+ ExifInterface.TAG_ORIENTATION,
+ ExifInterface.TAG_WHITE_BALANCE
+ };
+
+ private static class ExpectedValue {
+ // Thumbnail information.
+ public final boolean hasThumbnail;
+ public final int thumbnailWidth;
+ public final int thumbnailHeight;
+
+ // GPS information.
+ public final boolean hasLatLong;
+ public final float latitude;
+ public final float longitude;
+ public final float altitude;
+
+ // Values.
+ public final String make;
+ public final String model;
+ public final float aperture;
+ public final String datetime;
+ public final float exposureTime;
+ public final float flash;
+ public final String focalLength;
+ public final String gpsAltitude;
+ public final String gpsAltitudeRef;
+ public final String gpsDatestamp;
+ public final String gpsLatitude;
+ public final String gpsLatitudeRef;
+ public final String gpsLongitude;
+ public final String gpsLongitudeRef;
+ public final String gpsProcessingMethod;
+ public final String gpsTimestamp;
+ public final String imageLength;
+ public final String imageWidth;
+ public final String iso;
+ public final String whiteBalance;
+ public final String orientation;
+
+ private static String getString(TypedArray typedArray, int index) {
+ String stringValue = typedArray.getString(index);
+ if (stringValue == null || stringValue.equals("")) {
+ return null;
+ }
+ return stringValue.trim();
+ }
+
+ public ExpectedValue(TypedArray typedArray) {
+ // Reads thumbnail information.
+ hasThumbnail = typedArray.getBoolean(0, false);
+ thumbnailWidth = typedArray.getInt(1, 0);
+ thumbnailHeight = typedArray.getInt(2, 0);
+
+ // Reads GPS information.
+ hasLatLong = typedArray.getBoolean(3, false);
+ latitude = typedArray.getFloat(4, 0f);
+ longitude = typedArray.getFloat(5, 0f);
+ altitude = typedArray.getFloat(6, 0f);
+
+ // Read values.
+ make = getString(typedArray, 7);
+ model = getString(typedArray, 8);
+ aperture = typedArray.getFloat(9, 0f);
+ datetime = getString(typedArray, 10);
+ exposureTime = typedArray.getFloat(11, 0f);
+ flash = typedArray.getFloat(12, 0f);
+ focalLength = getString(typedArray, 13);
+ gpsAltitude = getString(typedArray, 14);
+ gpsAltitudeRef = getString(typedArray, 15);
+ gpsDatestamp = getString(typedArray, 16);
+ gpsLatitude = getString(typedArray, 17);
+ gpsLatitudeRef = getString(typedArray, 18);
+ gpsLongitude = getString(typedArray, 19);
+ gpsLongitudeRef = getString(typedArray, 20);
+ gpsProcessingMethod = getString(typedArray, 21);
+ gpsTimestamp = getString(typedArray, 22);
+ imageLength = getString(typedArray, 23);
+ imageWidth = getString(typedArray, 24);
+ iso = getString(typedArray, 25);
+ orientation = getString(typedArray, 26);
+ whiteBalance = getString(typedArray, 27);
+
+ typedArray.recycle();
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ byte[] buffer = new byte[BUFFER_SIZE];
+
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String outputPath = new File(Environment.getExternalStorageDirectory(),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ try (InputStream inputStream = getContext().getResources().openRawResource(
+ IMAGE_RESOURCES[i])) {
+ try (FileOutputStream outputStream = new FileOutputStream(outputPath)) {
+ Streams.copy(inputStream, outputStream);
+ }
+ }
+ }
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String imageFilePath = new File(Environment.getExternalStorageDirectory(),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ File imageFile = new File(imageFilePath);
+ if (imageFile.exists()) {
+ imageFile.delete();
+ }
+ }
+
+ super.tearDown();
+ }
+
+ private void printExifTagsAndValues(String fileName, ExifInterface exifInterface) {
+ // Prints thumbnail information.
+ if (exifInterface.hasThumbnail()) {
+ byte[] thumbnailBytes = exifInterface.getThumbnail();
+ if (thumbnailBytes != null) {
+ Log.v(TAG, fileName + " Thumbnail size = " + thumbnailBytes.length);
+ Bitmap bitmap = BitmapFactory.decodeByteArray(
+ thumbnailBytes, 0, thumbnailBytes.length);
+ if (bitmap == null) {
+ Log.e(TAG, fileName + " Corrupted thumbnail!");
+ } else {
+ Log.v(TAG, fileName + " Thumbnail size: " + bitmap.getWidth() + ", "
+ + bitmap.getHeight());
+ }
+ } else {
+ Log.e(TAG, fileName + " Corrupted image (no thumbnail)");
+ }
+ } else {
+ if (exifInterface.getThumbnail() != null) {
+ Log.e(TAG, fileName + " Corrupted image (a thumbnail exists)");
+ } else {
+ Log.v(TAG, fileName + " No thumbnail");
+ }
+ }
+
+ // Prints GPS information.
+ Log.v(TAG, fileName + " Altitude = " + exifInterface.getAltitude(.0));
+
+ float[] latLong = new float[2];
+ if (exifInterface.getLatLong(latLong)) {
+ Log.v(TAG, fileName + " Latitude = " + latLong[0]);
+ Log.v(TAG, fileName + " Longitude = " + latLong[1]);
+ } else {
+ Log.v(TAG, fileName + "No latlong data");
+ }
+
+ // Prints values.
+ for (String tagKey : EXIF_TAGS) {
+ String tagValue = exifInterface.getAttribute(tagKey);
+ Log.v(TAG, fileName + "Key{" + tagKey + "} = '" + tagValue + "'");
+ }
+ }
+
+ private void compareFloatTag(ExifInterface exifInterface, String tag, float expectedValue) {
+ String stringValue = exifInterface.getAttribute(tag);
+ float floatValue = 0f;
+
+ if (stringValue != null) {
+ floatValue = Float.parseFloat(stringValue);
+ }
+
+ assertEquals(expectedValue, floatValue, DIFFERENCE_TOLERANCE);
+ }
+
+ private void compareStringTag(ExifInterface exifInterface, String tag, String expectedValue) {
+ String stringValue = exifInterface.getAttribute(tag);
+ if (stringValue != null) {
+ stringValue = stringValue.trim();
+ }
+
+ assertEquals(expectedValue, stringValue);
+ }
+
+ private void compareWithExpectedValue(ExifInterface exifInterface,
+ ExpectedValue expectedValue) {
+ // Checks a thumbnail image.
+ assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
+ if (expectedValue.hasThumbnail) {
+ byte[] thumbnailBytes = exifInterface.getThumbnail();
+ assertNotNull(thumbnailBytes);
+ Bitmap thumbnailBitmap =
+ BitmapFactory.decodeByteArray(thumbnailBytes, 0, thumbnailBytes.length);
+ assertNotNull(thumbnailBitmap);
+ assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+ assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
+ } else {
+ assertNull(exifInterface.getThumbnail());
+ }
+
+ // Checks GPS information.
+ float[] latLong = new float[2];
+ assertEquals(expectedValue.hasLatLong, exifInterface.getLatLong(latLong));
+ if (expectedValue.hasLatLong) {
+ assertEquals(expectedValue.latitude, latLong[0], DIFFERENCE_TOLERANCE);
+ assertEquals(expectedValue.longitude, latLong[1], DIFFERENCE_TOLERANCE);
+ }
+ assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
+
+ // Checks values.
+ compareStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
+ compareStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
+ compareFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
+ compareStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
+ compareFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
+ compareFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
+ compareStringTag(exifInterface, ExifInterface.TAG_FOCAL_LENGTH, expectedValue.focalLength);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE, expectedValue.gpsAltitude);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_ALTITUDE_REF,
+ expectedValue.gpsAltitudeRef);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_DATESTAMP,
+ expectedValue.gpsDatestamp);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE, expectedValue.gpsLatitude);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_LATITUDE_REF,
+ expectedValue.gpsLatitudeRef);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE,
+ expectedValue.gpsLongitude);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_LONGITUDE_REF,
+ expectedValue.gpsLongitudeRef);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ expectedValue.gpsProcessingMethod);
+ compareStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP,
+ expectedValue.gpsTimestamp);
+ compareStringTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
+ compareStringTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
+ compareStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
+ compareStringTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
+ compareStringTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE,
+ expectedValue.whiteBalance);
+ }
+
+ private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
+ throws IOException {
+ ExpectedValue expectedValue = new ExpectedValue(
+ getContext().getResources().obtainTypedArray(typedArrayResourceId));
+ File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+ // Created via path.
+ ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+
+ // Created via InputStream.
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(imageFile.getAbsolutePath());
+ exifInterface = new ExifInterface(in);
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+
+ // Created via FileDescriptor.
+ try {
+ FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
+ exifInterface = new ExifInterface(fd);
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+
+ // Test for saving attributes.
+ try {
+ FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+ exifInterface = new ExifInterface(fd);
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(fd);
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+
+ // Test for modifying one attribute.
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
+ exifInterface.saveAttributes();
+ exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ }
+
+ private void testExifInterfaceForRaw(String fileName, int typedArrayResourceId)
+ throws IOException {
+ ExpectedValue expectedValue = new ExpectedValue(
+ getContext().getResources().obtainTypedArray(typedArrayResourceId));
+ File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+ // Created via path.
+ ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+
+ // Created via FileDescriptor.
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(imageFile);
+ exifInterface = new ExifInterface(in.getFD());
+ if (VERBOSE) {
+ printExifTagsAndValues(fileName, exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ public void testReadExifDataFromExifByteOrderIIJpeg() throws Throwable {
+ testExifInterfaceForJpeg(EXIF_BYTE_ORDER_II_JPEG, R.array.exifbyteorderii_jpg);
+ }
+
+ public void testReadExifDataFromExifByteOrderMMJpeg() throws Throwable {
+ testExifInterfaceForJpeg(EXIF_BYTE_ORDER_MM_JPEG, R.array.exifbyteordermm_jpg);
+ }
+
+ public void testReadExifDataFromLgG4Iso800Dng() throws Throwable {
+ testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
+ }
+}
diff --git a/opengl/java/android/opengl/GLES30.java b/opengl/java/android/opengl/GLES30.java
index 6cc6bfc5209f..74181c513753 100644
--- a/opengl/java/android/opengl/GLES30.java
+++ b/opengl/java/android/opengl/GLES30.java
@@ -1806,4 +1806,16 @@ public class GLES30 extends GLES20 {
java.nio.IntBuffer params
);
+ // C function void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset )
+
+ public static native void glReadPixels(
+ int x,
+ int y,
+ int width,
+ int height,
+ int format,
+ int type,
+ int offset
+ );
+
}
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 1a4e3eb18e14..6dfc3bbe8921 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
# The design lib requires that the client package use appcompat themes.
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
# Supplies material design components, e.g. Snackbar.
LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
@@ -29,6 +30,10 @@ LOCAL_AAPT_FLAGS := \
--extra-packages android.support.design \
--extra-packages android.support.v7.recyclerview
+LOCAL_JACK_FLAGS := \
+ -D jack.assert.policy=enable \
+ -D jack.optimization.inner-class.accessors=true
+
LOCAL_PACKAGE_NAME := DocumentsUI
LOCAL_CERTIFICATE := platform
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 9ac929ba9b28..637e06e1668d 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.documentsui">
+ <uses-permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.REMOVE_TASKS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
@@ -94,9 +95,8 @@
android:name=".OpenExternalDirectoryActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
- <action android:name="android.intent.action.OPEN_EXTERNAL_DIRECTORY" />
+ <action android:name="android.os.storage.action.OPEN_EXTERNAL_DIRECTORY" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="file" />
</intent-filter>
</activity>
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index e4881dd03446..000000000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index 66725e5c94ce..000000000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index cdf21b1e300b..000000000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index 050313f41c1b..000000000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png
deleted file mode 100644
index 8fddb85f2f02..000000000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_subdirectory_arrow_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_root_home.xml b/packages/DocumentsUI/res/drawable/ic_root_documents.xml
index 696ee0534b63..afd886d2adc5 100644
--- a/packages/DocumentsUI/res/drawable/ic_root_home.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_documents.xml
@@ -20,5 +20,5 @@ Copyright (C) 2015 The Android Open Source Project
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
- android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
+ android:pathData="M10 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V8c0,-1.1,-.9,-2,-2,-2h-8l-2,-2z"/>
</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml b/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
index 5723233b8213..0f34ba446373 100644
--- a/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
+++ b/packages/DocumentsUI/res/drawable/ic_subdirectory_arrow.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_subdirectory_arrow_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+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.
+-->
+<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:fillColor="?android:attr/colorControlNormal"
+ android:pathData="M19 15l-6 6,-1.42,-1.42L15.17 16H4V4h2v10h9.17l-3.59,-3.58L13 9l6 6z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/layout/directory_cluster.xml b/packages/DocumentsUI/res/layout/directory_cluster.xml
index 2fa09d39bdab..d84ef0823309 100644
--- a/packages/DocumentsUI/res/layout/directory_cluster.xml
+++ b/packages/DocumentsUI/res/layout/directory_cluster.xml
@@ -27,6 +27,7 @@
<FrameLayout
android:id="@+id/container_directory"
+ android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index e3def054fa0d..065102b18075 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -61,7 +61,7 @@
android:layout_gravity="start"
android:orientation="vertical"
android:elevation="16dp"
- android:background="@color/window_background">
+ android:background="@color/drawer_background">
<Toolbar
android:id="@+id/roots_toolbar"
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index 8414febfb7ca..84a928dc3d9b 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -16,11 +16,14 @@
<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
floating action buttons) to operate correctly. -->
+<!-- focusableInTouchMode is set in order to force key events to go to the activity's global key
+ callback, which is necessary for proper event routing. See BaseActivity.onKeyDown. -->
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/coordinator_layout">
+ android:id="@+id/coordinator_layout"
+ android:focusableInTouchMode="true">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 223d7290e72f..03c6a833ca7d 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,8 +17,10 @@
<com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:animateLayoutChanges="true">
+ android:background="@color/directory_background"
+ android:outlineProvider="bounds"
+ android:elevation="4dp"
+ android:orientation="vertical">
<ProgressBar
android:id="@+id/progressbar"
@@ -43,6 +45,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:background="@color/directory_background"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
android:visibility="gone">
<LinearLayout
@@ -80,8 +85,7 @@
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
- android:id="@+id/list"
- android:background="@color/window_background"
+ android:id="@+id/dir_list"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/DocumentsUI/res/layout/fragment_roots.xml b/packages/DocumentsUI/res/layout/fragment_roots.xml
index f3de3b43be50..b33b8d09b992 100644
--- a/packages/DocumentsUI/res/layout/fragment_roots.xml
+++ b/packages/DocumentsUI/res/layout/fragment_roots.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/list"
+<com.android.documentsui.RootsList xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/roots_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
index b0331bec6e49..a4f06d1cefe8 100644
--- a/packages/DocumentsUI/res/layout/item_dir_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -20,7 +20,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
- android:elevation="5dp"
+ android:elevation="@dimen/grid_item_elevation"
android:focusable="true" >
<LinearLayout
@@ -62,7 +62,7 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ellipsize="middle"
+ android:ellipsize="end"
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index dd02d1ca0051..af1703fbe423 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
- android:elevation="5dp"
+ android:elevation="@dimen/grid_item_elevation"
android:focusable="true">
<!-- Main item thumbnail. Comprised of two overlapping images, the
@@ -90,7 +90,7 @@
android:layout_alignParentTop="true"
android:layout_toEndOf="@id/icon_mime_sm"
android:singleLine="true"
- android:ellipsize="middle"
+ android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="@*android:color/primary_text_default_material_light" />
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 8d9837719fd7..b169ec89320a 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -80,7 +80,7 @@
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
- android:ellipsize="middle"
+ android:ellipsize="end"
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
diff --git a/packages/DocumentsUI/res/layout/item_subdir.xml b/packages/DocumentsUI/res/layout/item_subdir.xml
index b2a739ac579f..b8251d1eb865 100644
--- a/packages/DocumentsUI/res/layout/item_subdir.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir.xml
@@ -26,8 +26,8 @@
<ImageView
android:id="@+id/subdir"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
android:paddingEnd="8dp"
android:scaleType="centerInside"
android:visibility="gone"
@@ -40,7 +40,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
- android:ellipsize="middle"
+ android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorPrimary" />
diff --git a/packages/DocumentsUI/res/layout/item_subdir_title.xml b/packages/DocumentsUI/res/layout/item_subdir_title.xml
index 4c839d0ace20..de6c5234b47b 100644
--- a/packages/DocumentsUI/res/layout/item_subdir_title.xml
+++ b/packages/DocumentsUI/res/layout/item_subdir_title.xml
@@ -26,7 +26,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:ellipsize="middle"
+ android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index f53d69808929..235d22d0737b 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -16,11 +16,14 @@
<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
floating action buttons) to operate correctly. -->
+<!-- focusableInTouchMode is set in order to force key events to go to the activity's global key
+ callback, which is necessary for proper event routing. See BaseActivity.onKeyDown. -->
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/coordinator_layout">
+ android:id="@+id/coordinator_layout"
+ android:focusableInTouchMode="true">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index b8bc2893a2a3..9c665029a2de 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Deel via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopieer tans lêers"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Skuif tans lêers"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> oor"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopieer tans <xliff:g id="COUNT_1">%1$d</xliff:g> lêers.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
<string name="allow" msgid="7225948811296386551">"Laat toe"</string>
<string name="deny" msgid="2081879885755434506">"Weier"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index f28c43375090..c255e36181aa 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"በሚከተለው በኩል ያጋሩ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ፋይሎች በመገልበጥ ላይ"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ፋይሎችን በመውሰድ ላይ"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ቀርቷል"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች በመቅዳት ላይ።</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
<string name="allow" msgid="7225948811296386551">"ይፍቀዱ"</string>
<string name="deny" msgid="2081879885755434506">"ያስተባብሉ"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index c19e4060362e..79c2c6a44e59 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"مشاركة عبر"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"جارٍ نسخ الملفات"</string>
<string name="move_notification_title" msgid="6193835179777284805">"نقل الملفات"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"جارٍ حذف الملفات"</string>
<string name="copy_remaining" msgid="6283790937387975095">"المدة المتبقية: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="zero">جارٍ نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات.</item>
@@ -139,4 +140,13 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"تم تحويل بعض الملفات"</string>
<string name="allow" msgid="7225948811296386551">"السماح"</string>
<string name="deny" msgid="2081879885755434506">"رفض"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"هل تريد حذف الملفات؟"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="zero">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+ <item quantity="two">هل تريد بالتأكيد حذف ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+ <item quantity="few">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات؟</item>
+ <item quantity="many">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا؟</item>
+ <item quantity="other">هل تريد بالتأكيد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+ <item quantity="one">هل تريد بالتأكيد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 7fb1d068546c..8ba9036865b9 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -26,7 +26,7 @@
<string name="menu_list" msgid="7279285939892417279">"Siyahı görünüşü"</string>
<string name="menu_sort" msgid="7677740407158414452">"Bunlardan biri üzrə sırala"</string>
<string name="menu_search" msgid="3816712084502856974">"Axtarış"</string>
- <string name="menu_settings" msgid="8239065133341597825">"Yaddaş parametrləri"</string>
+ <string name="menu_settings" msgid="8239065133341597825">"Yaddaş ayarları"</string>
<string name="menu_open" msgid="432922957274920903">"Açın"</string>
<string name="menu_save" msgid="2394743337684426338">"Yadda saxlayın"</string>
<string name="menu_share" msgid="3075149983979628146">"Paylaşın"</string>
@@ -53,7 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Kökləri gizlədin"</string>
<string name="save_error" msgid="6167009778003223664">"Sənədi yadda saxlaya bilmədi"</string>
<string name="create_error" msgid="3735649141335444215">"Qovluq yaradıla bilmədi"</string>
- <string name="query_error" msgid="5999895349602476581">"Məzmun hal-hazırda yüklənmir"</string>
+ <string name="query_error" msgid="5999895349602476581">"Məzmun hazırda yüklənmir"</string>
<string name="root_recent" msgid="4470053704320518133">"Son"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ödənişsiz"</string>
<string name="root_type_service" msgid="2178854894416775409">"Saxlama xidmətləri"</string>
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Bunun vasitəsilə paylaş:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fayllar kopyalanır"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Fayllar köçürülür"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Fayllar silinir"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qalıb"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fayl kopyalanır.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bəzi fayllar konvertasiya edilib"</string>
<string name="allow" msgid="7225948811296386551">"İcazə verin"</string>
<string name="deny" msgid="2081879885755434506">"Rədd et"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Fayllar silinsin?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faylı silmək istədiyinizə əminsiniz?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> faylı silmək istədiyinizə əminsiniz?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/config.xml b/packages/DocumentsUI/res/values-b+sr+Latn/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-b+sr+Latn/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 40e4a0717249..81a4f9bdf98a 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Sakrij osnovne elemente"</string>
<string name="save_error" msgid="6167009778003223664">"Čuvanje dokumenta nije uspelo"</string>
<string name="create_error" msgid="3735649141335444215">"Direktorijum nije napravljen"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Učitavanje sadržaja trenutno nije moguće"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Slobodno je <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Usluge skladištenja"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Još aplikacija"</string>
<string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
<string name="no_results" msgid="6622510343880730446">"Nema podudaranja u %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Otvaranje datoteke nije uspelo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
<string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Datoteke se premeštaju"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -89,15 +89,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Priprema se kopiranje…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Priprema se premeštanje..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Priprema se brisanje…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku</item>
+ <item quantity="few">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
+ <item quantity="other">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="few">Premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="other">Premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije uspelo</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="few">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+ <item quantity="other">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije uspelo</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite da biste prikazali detalje"</string>
<string name="close" msgid="3043722427445528732">"Zatvori"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Sledeće datoteke nisu kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Sledeće datoteke nisu premeštene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ove datoteke su konvertovane u drugi format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku u privremenu memoriju.</item>
@@ -110,4 +120,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
<string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
<string name="deny" msgid="2081879885755434506">"Odbij"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-bg/config.xml b/packages/DocumentsUI/res/values-bg/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-bg/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 4a6d499627cc..7c096d965eeb 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Споделяне чрез"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файловете се копират"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файловете се преместват"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Оставащо време: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Копират се <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
<string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
<string name="deny" msgid="2081879885755434506">"Отказване"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/config.xml b/packages/DocumentsUI/res/values-bn-rBD/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-bn-rBD/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index e87a8240c633..6bbe95b924d9 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"রুটগুলি লুকান"</string>
<string name="save_error" msgid="6167009778003223664">"দস্তাবেজ সংরক্ষণ করতে ব্যর্থ হয়েছে"</string>
<string name="create_error" msgid="3735649141335444215">"ফোল্ডার তৈরি করতে ব্যর্থ হয়েছে"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"এই মুহূর্তে সামগ্রী লোড করা যাবে না"</string>
<string name="root_recent" msgid="4470053704320518133">"সাম্প্রতিক"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> খালি আছে"</string>
<string name="root_type_service" msgid="2178854894416775409">"সঞ্চয়স্থান পরিষেবাগুলি"</string>
@@ -63,12 +62,12 @@
<string name="root_type_apps" msgid="8838065367985945189">"আরো অ্যাপ্লিকেশান"</string>
<string name="empty" msgid="7858882803708117596">"কোনো আইটেম নেই"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s এ কোনো মিল নেই"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ফাইল খোলা যাবে না"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"কিছু দস্তাবেজ মুছতে অসমর্থ"</string>
<string name="share_via" msgid="8966594246261344259">"এর মাধ্যমে শেয়ার করুন"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ফাইলগুলি অনুলিপি করা হচ্ছে"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ফাইলগুলি সরানো হচ্ছে"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ফাইলগুলি মোছা হচ্ছে"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> বাকি"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল অনুলিপি করা হচ্ছে৷</item>
@@ -86,15 +85,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"অনুলিপি করার জন্য প্রস্তুত করা হচ্ছে..."</string>
<string name="move_preparing" msgid="2772219441375531410">"সরানোর জন্য প্রস্তুত হচ্ছে..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"মোছার জন্য প্রস্তুত করা হচ্ছে..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল প্রতিলিপি করা গেল না</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল প্রতিলিপি করা গেল না</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল সরানো গেল না</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল সরানো গেল না</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছা গেল না</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছা গেল না</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"বিশদ বিবরণ দেখতে আলতো চাপুন"</string>
<string name="close" msgid="3043722427445528732">"বন্ধ করুন"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"এই ফাইলগুলির প্রতিলিপি করা হয়নি: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"এই ফাইলগুলি সরানো হয়নি: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"এই ফাইলগুলি অন্য ফরম্যাটে রূপান্তর করা হয়েছে: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল ক্লিপবোর্ডে প্রতিলিপি করা হয়েছে।</item>
@@ -106,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"কিছু ফাইল রূপান্তরিত হয়েছে"</string>
<string name="allow" msgid="7225948811296386551">"অনুমতি দিন"</string>
<string name="deny" msgid="2081879885755434506">"আস্বীকার করুন"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ফাইলগুলি মুছবেন?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">আপনি কি <xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছার বিষয়ে নিশ্চিত?</item>
+ <item quantity="other">আপনি কি <xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মোছার বিষয়ে নিশ্চিত?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/config.xml b/packages/DocumentsUI/res/values-bs-rBA/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-bs-rBA/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 9c7b71aba4a4..68a2b422220f 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -16,136 +16,111 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (2783841764617238354) -->
- <skip />
- <!-- no translation found for files_label (6051402950202690279) -->
- <skip />
- <!-- no translation found for downloads_label (959113951084633612) -->
- <skip />
- <!-- no translation found for title_open (4353228937663917801) -->
- <skip />
- <!-- no translation found for title_save (2433679664882857999) -->
- <skip />
- <!-- no translation found for menu_create_dir (2547620241173881754) -->
- <skip />
- <!-- no translation found for menu_grid (6878021334497835259) -->
- <skip />
- <!-- no translation found for menu_list (7279285939892417279) -->
- <skip />
- <!-- no translation found for menu_sort (7677740407158414452) -->
- <skip />
- <!-- no translation found for menu_search (3816712084502856974) -->
- <skip />
+ <string name="app_label" msgid="2783841764617238354">"Dokumenti"</string>
+ <string name="files_label" msgid="6051402950202690279">"Fajlovi"</string>
+ <string name="downloads_label" msgid="959113951084633612">"Preuzimanja"</string>
+ <string name="title_open" msgid="4353228937663917801">"Otvori iz"</string>
+ <string name="title_save" msgid="2433679664882857999">"Sačuvaj u"</string>
+ <string name="menu_create_dir" msgid="2547620241173881754">"Nova fascikla"</string>
+ <string name="menu_grid" msgid="6878021334497835259">"Prikaz u vidu mreže"</string>
+ <string name="menu_list" msgid="7279285939892417279">"Prikaz u vidu liste"</string>
+ <string name="menu_sort" msgid="7677740407158414452">"Sortiraj po"</string>
+ <string name="menu_search" msgid="3816712084502856974">"Traži"</string>
<string name="menu_settings" msgid="8239065133341597825">"Postavke pohrane"</string>
- <!-- no translation found for menu_open (432922957274920903) -->
- <skip />
- <!-- no translation found for menu_save (2394743337684426338) -->
- <skip />
- <!-- no translation found for menu_share (3075149983979628146) -->
- <skip />
- <!-- no translation found for menu_delete (8138799623850614177) -->
- <skip />
- <!-- no translation found for menu_select_all (8323579667348729928) -->
- <skip />
- <!-- no translation found for menu_copy (3612326052677229148) -->
- <skip />
- <!-- no translation found for menu_move (1828090633118079817) -->
- <skip />
- <!-- no translation found for menu_new_window (1226032889278727538) -->
- <skip />
- <!-- no translation found for menu_copy_to_clipboard (489311381979634291) -->
- <skip />
- <!-- no translation found for menu_paste_from_clipboard (2071583031180257091) -->
- <skip />
- <!-- no translation found for menu_advanced_show (4693652895715631401) -->
- <skip />
- <!-- no translation found for menu_advanced_hide (4218809952721972589) -->
- <skip />
- <!-- no translation found for menu_file_size_show (3240323619260823076) -->
- <skip />
- <!-- no translation found for menu_file_size_hide (8881975928502581042) -->
- <skip />
- <!-- no translation found for button_select (527196987259139214) -->
- <skip />
- <!-- no translation found for button_copy (8706475544635021302) -->
- <skip />
- <!-- no translation found for button_move (2202666023104202232) -->
- <skip />
- <!-- no translation found for button_dismiss (3714065566893946085) -->
- <skip />
- <!-- no translation found for button_retry (4392027584153752797) -->
- <skip />
- <!-- no translation found for sort_name (9183560467917256779) -->
- <skip />
- <!-- no translation found for sort_date (586080032956151448) -->
- <skip />
- <!-- no translation found for sort_size (3350681319735474741) -->
- <skip />
- <!-- no translation found for drawer_open (4545466532430226949) -->
- <skip />
- <!-- no translation found for drawer_close (7602734368552123318) -->
- <skip />
- <!-- no translation found for save_error (6167009778003223664) -->
- <skip />
- <!-- no translation found for create_error (3735649141335444215) -->
- <skip />
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
- <!-- no translation found for root_recent (4470053704320518133) -->
- <skip />
- <!-- no translation found for root_available_bytes (8568452858617033281) -->
- <skip />
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
- <!-- no translation found for root_type_shortcut (3318760609471618093) -->
- <skip />
- <!-- no translation found for root_type_device (7121342474653483538) -->
- <skip />
- <!-- no translation found for root_type_apps (8838065367985945189) -->
- <skip />
- <!-- no translation found for empty (7858882803708117596) -->
- <skip />
+ <string name="menu_open" msgid="432922957274920903">"Otvori"</string>
+ <string name="menu_save" msgid="2394743337684426338">"Sačuvaj"</string>
+ <string name="menu_share" msgid="3075149983979628146">"Podijeli"</string>
+ <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
+ <string name="menu_select_all" msgid="8323579667348729928">"Odaberi sve"</string>
+ <string name="menu_copy" msgid="3612326052677229148">"Kopiraj na..."</string>
+ <string name="menu_move" msgid="1828090633118079817">"Premjesti u..."</string>
+ <string name="menu_new_window" msgid="1226032889278727538">"Novi prozor"</string>
+ <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiraj"</string>
+ <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Zalijepi"</string>
+ <string name="menu_advanced_show" msgid="4693652895715631401">"Pokaži internu pohranu"</string>
+ <string name="menu_advanced_hide" msgid="4218809952721972589">"Sakrij internu pohranu"</string>
+ <string name="menu_file_size_show" msgid="3240323619260823076">"Pokaži veličinu fajla"</string>
+ <string name="menu_file_size_hide" msgid="8881975928502581042">"Sakrij veličinu fajla"</string>
+ <string name="button_select" msgid="527196987259139214">"Odaberi"</string>
+ <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
+ <string name="button_move" msgid="2202666023104202232">"Premjesti"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Pokušajte ponovo"</string>
+ <string name="sort_name" msgid="9183560467917256779">"Po nazivu"</string>
+ <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
+ <string name="sort_size" msgid="3350681319735474741">"Po veličini"</string>
+ <string name="drawer_open" msgid="4545466532430226949">"Pokaži korijeni"</string>
+ <string name="drawer_close" msgid="7602734368552123318">"Sakrij korijenske foldere"</string>
+ <string name="save_error" msgid="6167009778003223664">"Pohranjivanje dokumenta nije uspjelo"</string>
+ <string name="create_error" msgid="3735649141335444215">"Kreiranje mape nije uspjelo"</string>
+ <string name="query_error" msgid="5999895349602476581">"Trenutno nije moguće učitati sadržaj"</string>
+ <string name="root_recent" msgid="4470053704320518133">"Nedavni"</string>
+ <string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> slobodno"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Usluge pohranjivanja"</string>
+ <string name="root_type_shortcut" msgid="3318760609471618093">"Prečice"</string>
+ <string name="root_type_device" msgid="7121342474653483538">"Uređaji"</string>
+ <string name="root_type_apps" msgid="8838065367985945189">"Više aplikacija"</string>
+ <string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
<string name="no_results" msgid="6622510343880730446">"Nema rezultata u %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
- <!-- no translation found for toast_failed_delete (2180678019407244069) -->
- <skip />
- <!-- no translation found for share_via (8966594246261344259) -->
- <skip />
- <!-- no translation found for copy_notification_title (6374299806748219777) -->
- <skip />
- <!-- no translation found for move_notification_title (6193835179777284805) -->
- <skip />
- <!-- no translation found for copy_remaining (6283790937387975095) -->
- <skip />
- <!-- no translation found for copy_begin (9071199452634086365) -->
- <!-- no translation found for move_begin (8430330882138871643) -->
- <!-- no translation found for deleting (5054338566802559411) -->
- <!-- no translation found for undo (7905788502491742328) -->
- <skip />
- <!-- no translation found for copy_preparing (3896202461003039386) -->
- <skip />
- <!-- no translation found for move_preparing (2772219441375531410) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Nije moguće otvoriti fajl"</string>
+ <string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće obrisati neke dokumente"</string>
+ <string name="share_via" msgid="8966594246261344259">"Podijeli preko"</string>
+ <string name="copy_notification_title" msgid="6374299806748219777">"Kopiraju se fajlovi"</string>
+ <string name="move_notification_title" msgid="6193835179777284805">"Premještanje fajlova"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
+ <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
+ <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+ <item quantity="one">Kopira se <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
+ <item quantity="few">Kopiraju se <xliff:g id="COUNT_1">%1$d</xliff:g> fajla.</item>
+ <item quantity="other">Kopira se <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova.</item>
+ </plurals>
+ <plurals name="move_begin" formatted="false" msgid="8430330882138871643">
+ <item quantity="one">Premješta se <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
+ <item quantity="few">Premještaju se <xliff:g id="COUNT_1">%1$d</xliff:g> fajla.</item>
+ <item quantity="other">Premješta se <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova.</item>
+ </plurals>
+ <plurals name="deleting" formatted="false" msgid="5054338566802559411">
+ <item quantity="one">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
+ <item quantity="few">Brišu se <xliff:g id="COUNT_1">%1$d</xliff:g> fajla.</item>
+ <item quantity="other">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova.</item>
+ </plurals>
+ <string name="undo" msgid="7905788502491742328">"Vrati"</string>
+ <string name="copy_preparing" msgid="3896202461003039386">"Priprema se kopiranje..."</string>
+ <string name="move_preparing" msgid="2772219441375531410">"Priprema za premještanje..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Pripremanje za brisanje…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Nije moguće kopirati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl</item>
+ <item quantity="few">Nije moguće kopirati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla</item>
+ <item quantity="other">Nije moguće kopirati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Nije moguće premjestiti <xliff:g id="COUNT_1">%1$d</xliff:g> fajl</item>
+ <item quantity="few">Nije moguće premjestiti <xliff:g id="COUNT_1">%1$d</xliff:g> fajla</item>
+ <item quantity="other">Nije moguće premjestiti <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Nije moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl</item>
+ <item quantity="few">Nije moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla</item>
+ <item quantity="other">Nije moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite za prikaz detalja"</string>
<string name="close" msgid="3043722427445528732">"Zatvori"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Nisu kopirani sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Nisu premješteni sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ove datoteke su pretvorene u drugi format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
- <!-- no translation found for clipboard_files_clipped (855459017537058539) -->
- <!-- no translation found for clipboard_files_cannot_paste (2878324825602325706) -->
- <skip />
+ <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fajl je kopiran u međuspremnik.</item>
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> fajla su kopirana u međuspremnik.</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fajlova je kopirano u međuspremnik.</item>
+ </plurals>
+ <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Odabrani fajlovi se ne mogu zalijepiti na ovu lokaciju."</string>
<string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
<string name="rename_error" msgid="4203041674883412606">"Nije uspjelo preimenovanje dokumenta"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
- <!-- no translation found for allow (7225948811296386551) -->
- <skip />
- <!-- no translation found for deny (2081879885755434506) -->
+ <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
+ <string name="deny" msgid="2081879885755434506">"Odbijte"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
<skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ca/config.xml b/packages/DocumentsUI/res/values-ca/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ca/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 2cb22c8820d3..e979b1181af6 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Amaga les arrels"</string>
<string name="save_error" msgid="6167009778003223664">"No s\'ha pogut desar el document."</string>
<string name="create_error" msgid="3735649141335444215">"No s\'ha pogut crear la carpeta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"En aquest moment no es pot carregar el contingut"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> lliures"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serveis d\'emmagatzematge"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Més aplicacions"</string>
<string name="empty" msgid="7858882803708117596">"Sense elements"</string>
<string name="no_results" msgid="6622510343880730446">"No hi ha cap coincidència a %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"No es pot obrir el fitxer"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es poden suprimir alguns documents."</string>
<string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"S\'estan copiant fitxers"</string>
<string name="move_notification_title" msgid="6193835179777284805">"S\'estan movent fitxers"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Temps restant: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">S\'estan copiant <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"S\'està preparant una còpia…"</string>
<string name="move_preparing" msgid="2772219441375531410">"S\'està preparant per moure\'ls..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"S\'està preparant per suprimir…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">No s\'han pogut copiar <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+ <item quantity="one">No s\'ha pogut copiar <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">No s\'han pogut moure <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+ <item quantity="one">No s\'ha pogut moure <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">No s\'han pogut suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+ <item quantity="one">No s\'ha pogut suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Toca per veure\'n els detalls"</string>
<string name="close" msgid="3043722427445528732">"Tanca"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Aquests fitxers no s\'han copiat: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Aquests fitxers no s\'han mogut: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Aquests fitxers s\'han convertit a un altre format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">S\'han copiat <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers al porta-retalls.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
<string name="allow" msgid="7225948811296386551">"Permet"</string>
<string name="deny" msgid="2081879885755434506">"Denega"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-cs/config.xml b/packages/DocumentsUI/res/values-cs/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-cs/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index c41b1b148738..0f3b4e023578 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skrýt kořeny"</string>
<string name="save_error" msgid="6167009778003223664">"Uložení dokumentu se nezdařilo"</string>
<string name="create_error" msgid="3735649141335444215">"Složku se nepodařilo vytvořit"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Obsah nyní nelze načíst"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedávné"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Volné místo: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Služby úložiště"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Další aplikace"</string>
<string name="empty" msgid="7858882803708117596">"Žádné položky"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s – žádné shody"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Soubor nelze otevřít"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Některé dokumenty nelze smazat"</string>
<string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopírování souborů"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Přesouvání souborů"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Zbývající čas: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souborů</item>
@@ -92,15 +92,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Příprava na kopírování…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Příprava na přesunutí…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Příprava na mazání…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory se zkopírovat nepodařilo</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru se zkopírovat nepodařilo</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů se zkopírovat nepodařilo</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor se zkopírovat nepodařilo</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory nelze přesunout</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru nelze přesunout</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů nelze přesunout</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor nelze přesunout</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory se smazat nepodařilo</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru se smazat nepodařilo</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů se smazat nepodařilo</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor se smazat nepodařilo</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Klepnutím zobrazíte podrobnosti"</string>
<string name="close" msgid="3043722427445528732">"Zavřít"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Následující soubory nebyly zkopírovány: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Následující soubory nebyly přesunuty: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Soubory byly převedeny do jiného formátu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory byly zkopírovány do schránky.</item>
@@ -114,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
<string name="allow" msgid="7225948811296386551">"Povolit"</string>
<string name="deny" msgid="2081879885755434506">"Odepřít"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-da/config.xml b/packages/DocumentsUI/res/values-da/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-da/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 78c59b928bc9..3854f0fa6fc2 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skjul rødder"</string>
<string name="save_error" msgid="6167009778003223664">"Dokumentet kunne ikke gemmes"</string>
<string name="create_error" msgid="3735649141335444215">"Mappen kunne ikke oprettes"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Der kan ikke indlæses indhold i øjeblikket"</string>
<string name="root_recent" msgid="4470053704320518133">"Seneste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledig plads"</string>
<string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Flere apps"</string>
<string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
<string name="no_results" msgid="6622510343880730446">"Ingen kampe i %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Filen kan ikke åbnes"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nogle dokumenter kan ikke slettes"</string>
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> tilbage"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Forbereder kopiering…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Forbereder flytning…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Forbereder til sletning…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke kopieres</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke kopieres</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke flyttes</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke flyttes</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke slettes</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke slettes</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tryk for at se oplysninger"</string>
<string name="close" msgid="3043722427445528732">"Luk"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Disse filer blev ikke kopieret: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Disse filer blev ikke flyttet: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Disse filer er konverteret til et andet format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev kopieret til udklipsholder.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
<string name="allow" msgid="7225948811296386551">"Tillad"</string>
<string name="deny" msgid="2081879885755434506">"Afvis"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-de/config.xml b/packages/DocumentsUI/res/values-de/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-de/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index fb25867c69e9..fd7f35c6db31 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Root-Verzeichnis ausblenden"</string>
<string name="save_error" msgid="6167009778003223664">"Dokument konnte nicht gespeichert werden."</string>
<string name="create_error" msgid="3735649141335444215">"Ordner konnte nicht erstellt werden."</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Inhalte können momentan nicht geladen werden"</string>
<string name="root_recent" msgid="4470053704320518133">"Letzte"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> verfügbar"</string>
<string name="root_type_service" msgid="2178854894416775409">"Speicherdienste"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Weitere Apps"</string>
<string name="empty" msgid="7858882803708117596">"Keine Dokumente"</string>
<string name="no_results" msgid="6622510343880730446">"Keine Übereinstimmungen in %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Datei kann nicht geöffnet werden"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
<string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Dateien werden kopiert"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Dateien werden verschoben"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Noch <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien werden kopiert.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Kopieren wird vorbereitet…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Verschieben wird vorbereitet…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Löschvorgang wird vorbereitet…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht kopiert werden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht kopiert werden</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht verschoben werden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht verschoben werden</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht gelöscht werden</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht gelöscht werden</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Zum Ansehen der Details tippen"</string>
<string name="close" msgid="3043722427445528732">"Schließen"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Diese Dateien wurden nicht kopiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Diese Dateien wurden nicht verschoben: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Folgende Dateien wurden in ein anderes Format konvertiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien wurden in die Zwischenablage kopiert.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
<string name="allow" msgid="7225948811296386551">"Zulassen"</string>
<string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-el/config.xml b/packages/DocumentsUI/res/values-el/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-el/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 5661e829c51b..6257e1712c87 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Απόκρυψη ρίζας"</string>
<string name="save_error" msgid="6167009778003223664">"Αποτυχία αποθήκευσης του εγγράφου"</string>
<string name="create_error" msgid="3735649141335444215">"Αποτυχία δημιουργίας φακέλου"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Δεν είναι δυνατή η φόρτωση περιεχομένου τώρα"</string>
<string name="root_recent" msgid="4470053704320518133">"Πρόσφατα"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ελεύθερα"</string>
<string name="root_type_service" msgid="2178854894416775409">"Υπηρεσίες αποθήκευσης"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Περισσότερες εφαρμογές"</string>
<string name="empty" msgid="7858882803708117596">"Δεν υπάρχουν στοιχεία"</string>
<string name="no_results" msgid="6622510343880730446">"Χωρίς αντιστοιχίσεις στο %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
<string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Αντιγραφή αρχείων"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Μετακίνηση αρχείων"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Απομένουν <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Προετοιμασία για αντιγραφή…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Προετοιμασία για μετακίνηση…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Προετοιμασία για διαγραφή…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Δεν ήταν δυνατή η αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων</item>
+ <item quantity="one">Δεν ήταν δυνατή η αντιγραφή <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Δεν ήταν δυνατή η μετακίνηση <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων</item>
+ <item quantity="one">Δεν ήταν δυνατή η μετακίνηση <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Δεν ήταν δυνατή η διαγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων</item>
+ <item quantity="one">Δεν ήταν δυνατή η διαγραφή <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Πατήστε για προβολή λεπτομερειών"</string>
<string name="close" msgid="3043722427445528732">"Κλείσιμο"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Αυτά τα αρχεία δεν αντιγράφηκαν: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Αυτά τα αρχεία δεν μετακινήθηκαν: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Αυτά τα αρχεία μετατράπηκαν σε άλλη μορφή: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία αντιγράφηκαν στο πρόχειρο.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
<string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
<string name="deny" msgid="2081879885755434506">"Άρνηση"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/config.xml b/packages/DocumentsUI/res/values-en-rAU/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-en-rAU/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 5bc4f5955a93..82c5557e6d79 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Share via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moving files"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Deleting files"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
<string name="deny" msgid="2081879885755434506">"Deny"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Delete files?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Are you sure you want to delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Are you sure you want to delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/config.xml b/packages/DocumentsUI/res/values-en-rGB/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-en-rGB/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 5bc4f5955a93..82c5557e6d79 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Share via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moving files"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Deleting files"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
<string name="deny" msgid="2081879885755434506">"Deny"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Delete files?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Are you sure you want to delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Are you sure you want to delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/config.xml b/packages/DocumentsUI/res/values-en-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-en-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 5bc4f5955a93..82c5557e6d79 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Share via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moving files"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Deleting files"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Some files were converted"</string>
<string name="allow" msgid="7225948811296386551">"Allow"</string>
<string name="deny" msgid="2081879885755434506">"Deny"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Delete files?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Are you sure you want to delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+ <item quantity="one">Are you sure you want to delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/config.xml b/packages/DocumentsUI/res/values-es-rUS/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-es-rUS/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index a72973261e96..29b91111121e 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raíces"</string>
<string name="save_error" msgid="6167009778003223664">"Error al guardar el documento"</string>
<string name="create_error" msgid="3735649141335444215">"Error al crear la carpeta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"No se puede cargar el contenido en este momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recientes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> de espacio libre"</string>
<string name="root_type_service" msgid="2178854894416775409">"Almacenamiento"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
<string name="empty" msgid="7858882803708117596">"Sin elementos"</string>
<string name="no_results" msgid="6622510343880730446">"No hay coincidencias en %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"No se puede abrir el archivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos."</string>
<string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Faltan <xliff:g id="DURATION">%s</xliff:g>."</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparación para mover archivos…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando para borrar…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+ <item quantity="one">No se pudo copiar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">No se pudieron trasladar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+ <item quantity="one">No se pudo trasladar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">No se pudieron borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+ <item quantity="one">No se pudo borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Presiona para ver los detalles"</string>
<string name="close" msgid="3043722427445528732">"Cerrar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Los siguientes archivos no se pudieron copiar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Los siguientes archivos no se trasladaron: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Estos archivos se convirtieron a otro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Se copiaron <xliff:g id="COUNT_1">%1$d</xliff:g> archivos al portapapeles.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Denegar"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-es/config.xml b/packages/DocumentsUI/res/values-es/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-es/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 28f3fd07f41f..02e6d744fb8d 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Tiempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Denegar"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/config.xml b/packages/DocumentsUI/res/values-et-rEE/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-et-rEE/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index d8d6bea66c71..13a4bfae1f7d 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Jagage teenusega"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Failide kopeerimine"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Failide teisaldamine"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Failide kustutamine"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Jäänud on <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili kopeerimine.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Mõned failid teisendati"</string>
<string name="allow" msgid="7225948811296386551">"Luba"</string>
<string name="deny" msgid="2081879885755434506">"Keela"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Kas kustutada failid?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Kas soovite kindlasti <xliff:g id="COUNT_1">%1$d</xliff:g> faili kustutada?</item>
+ <item quantity="one">Kas soovite kindlasti <xliff:g id="COUNT_0">%1$d</xliff:g> faili kustutada?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/config.xml b/packages/DocumentsUI/res/values-eu-rES/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-eu-rES/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 539774ffa5b2..125d899e44af 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ezkutatu erroko karpetak"</string>
<string name="save_error" msgid="6167009778003223664">"Ezin izan da dokumentua gorde"</string>
<string name="create_error" msgid="3735649141335444215">"Ezin izan da karpeta sortu"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Une honetan ezin da kargatu edukia"</string>
<string name="root_recent" msgid="4470053704320518133">"Azkenak"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> doan"</string>
<string name="root_type_service" msgid="2178854894416775409">"Biltegiratze-zerbitzuak"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Aplikazio gehiago"</string>
<string name="empty" msgid="7858882803708117596">"Ez dago elementurik"</string>
<string name="no_results" msgid="6622510343880730446">"Ez da aurkitu ezer %1$s atalean"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Ezin da ireki fitxategia"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ezin izan dira dokumentu batzuk ezabatu"</string>
<string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fitxategiak kopiatzen"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Fitxategiak mugitzea"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Falta den denbora: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatzen.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Kopiatzeko prestatzen…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Mugitzeko prestatzen…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Ezabatzeko prestatzen…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Ezin izan dira kopiatu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+ <item quantity="one">Ezin izan da kopiatu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Ezin izan dira mugitu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+ <item quantity="one">Ezin izan da mugitu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Ezin izan dira ezabatu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+ <item quantity="one">Ezin izan da ezabatu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Sakatu xehetasunak ikusteko"</string>
<string name="close" msgid="3043722427445528732">"Itxi"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Ez dira kopiatu fitxategi hauek: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Ez dira mugitu fitxategi hauek: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Fitxategi hauek beste formatu bateko fitxategi bihurtu dira: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatu dira arbelean.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
<string name="allow" msgid="7225948811296386551">"Onartu"</string>
<string name="deny" msgid="2081879885755434506">"Ukatu"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fa/config.xml b/packages/DocumentsUI/res/values-fa/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-fa/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 3b3d559bf01d..997eea8216af 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"اشتراک‌گذاری از طریق"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"در حال کپی کردن فایل‌ها"</string>
<string name="move_notification_title" msgid="6193835179777284805">"درحال انتقال فایل‌ها"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"در حال حذف فایل‌ها"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی‌مانده"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">در حال کپی کردن <xliff:g id="COUNT_1">%1$d</xliff:g> فایل.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"بعضی از فایل‌ها تبدیل شدند"</string>
<string name="allow" msgid="7225948811296386551">"ارزیابی‌شده"</string>
<string name="deny" msgid="2081879885755434506">"اجازه ندارد"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"فایل‌ها حذف شوند؟"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">مطمئنید می‌خواهید <xliff:g id="COUNT_1">%1$d</xliff:g> فایل را حذف کنید؟</item>
+ <item quantity="other">مطمئنید می‌خواهید <xliff:g id="COUNT_1">%1$d</xliff:g> فایل را حذف کنید؟</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-fi/config.xml b/packages/DocumentsUI/res/values-fi/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-fi/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index e349eefaaae8..0788598b5a75 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Piilota juuret"</string>
<string name="save_error" msgid="6167009778003223664">"Asiakirjan tallennus epäonnistui"</string>
<string name="create_error" msgid="3735649141335444215">"Kansion luominen epäonnistui"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Sisältöä ei juuri nyt voi ladata."</string>
<string name="root_recent" msgid="4470053704320518133">"Viimeisimmät"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> vapaana"</string>
<string name="root_type_service" msgid="2178854894416775409">"Tallennuspalvelut"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Lisää sovelluksia"</string>
<string name="empty" msgid="7858882803708117596">"Ei kohteita"</string>
<string name="no_results" msgid="6622510343880730446">"Ei osumia kohteessa %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Tiedoston avaaminen epäonnistui."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Joitakin asiakirjoja ei voi poistaa"</string>
<string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopioidaan tiedostoja"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Siirretään tiedostoja"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> jäljellä"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopioidaan <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Valmistellaan kopiointia…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Valmistellaan siirtämistä…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Valmistellaan poistamista…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston kopioiminen epäonnistui.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston kopioiminen epäonnistui.</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston siirtäminen epäonnistui.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston siirtäminen epäonnistui.</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston poistaminen epäonnistui.</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston poistaminen epäonnistui.</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tarkastele tietoja napauttamalla"</string>
<string name="close" msgid="3043722427445528732">"Sulje"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Näitä tiedostoja ei kopioitu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Näitä tiedostoja ei siirretty: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Seuraavat tiedostot muunnettiin toiseen muotoon: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa kopioitiin leikepöydälle.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
<string name="allow" msgid="7225948811296386551">"Salli"</string>
<string name="deny" msgid="2081879885755434506">"Kiellä"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/config.xml b/packages/DocumentsUI/res/values-fr-rCA/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-fr-rCA/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index fad48007bf2b..6b4c7fd12263 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Masquer les racines"</string>
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document"</string>
<string name="create_error" msgid="3735649141335444215">"Échec de la création du dossier"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Impossible de charger le contenu pour le moment"</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> disponible"</string>
<string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Plus d\'applications"</string>
<string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
<string name="no_results" msgid="6622510343880730446">"Aucune correspondance dans %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Impossible d\'ouvrir le fichier"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents"</string>
<string name="share_via" msgid="8966594246261344259">"Partager par"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers..."</string>
<string name="move_notification_title" msgid="6193835179777284805">"Déplacement des fichiers"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Durée restante : <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copier de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Préparation de la copie en cours"</string>
<string name="move_preparing" msgid="2772219441375531410">"Préparation du déplacement..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Préparation de la suppression..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier</item>
+ <item quantity="other">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Touchez pour afficher les détails"</string>
<string name="close" msgid="3043722427445528732">"Fermer"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Ces fichiers ne ont pas été copiés : <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Ces fichiers n\'ont pas été déplacés : <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ces fichiers ont été convertis dans un autre format : <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fichier a été copié dans le presse-papiers.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
<string name="deny" msgid="2081879885755434506">"Refuser"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fr/config.xml b/packages/DocumentsUI/res/values-fr/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-fr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 413416bac924..84021b0e7ae1 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Masquer les répertoires racines"</string>
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document."</string>
<string name="create_error" msgid="3735649141335444215">"Échec de la création du dossier."</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Impossible de charger le contenu pour le moment"</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Espace disponible : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Autres applications"</string>
<string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
<string name="no_results" msgid="6622510343880730446">"Aucune correspondance dans %1$s."</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Impossible d\'ouvrir le fichier"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents."</string>
<string name="share_via" msgid="8966594246261344259">"Partager via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers en cours"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Déplacement de fichiers"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Temps restant : <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours…</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Préparation de la copie en cours…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Préparation au déplacement…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Préparation à la suppression…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+ <item quantity="other">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Appuyez pour afficher plus d\'informations."</string>
<string name="close" msgid="3043722427445528732">"Fermer"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Les fichiers suivants n\'ont pas été copiés : <xliff:g id="LIST">%1$s</xliff:g>."</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Les fichiers suivants n\'ont pas été déplacés : <xliff:g id="LIST">%1$s</xliff:g>."</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ces fichiers ont été convertis dans un autre format : <xliff:g id="LIST">%1$s</xliff:g>."</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fichier a bien été copié dans le Presse-papiers.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
<string name="allow" msgid="7225948811296386551">"Autoriser"</string>
<string name="deny" msgid="2081879885755434506">"Refuser"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/config.xml b/packages/DocumentsUI/res/values-gl-rES/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-gl-rES/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 32745682c058..fd03af710962 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raíces"</string>
<string name="save_error" msgid="6167009778003223664">"Non se puido gardar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Non se puido crear o cartafol"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Non se pode cargar o contido neste momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> libres"</string>
<string name="root_type_service" msgid="2178854894416775409">"Servizos de almacenamento"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Máis aplicacións"</string>
<string name="empty" msgid="7858882803708117596">"Ningún elemento"</string>
<string name="no_results" msgid="6622510343880730446">"Non hai coincidencias en %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Non se pode abrir o ficheiro"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Non se poden eliminar algúns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando ficheiros"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Mover ficheiros"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Tempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparándose para mover..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando para eliminar…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Non se puideron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Non se puido copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Non se puideron mover <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Non se puido mover <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Non se puideron eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Non se puido eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Toca para ver detalles"</string>
<string name="close" msgid="3043722427445528732">"Pechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Non se copiaron estes ficheiros: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Non se moveron estes ficheiros: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Estes ficheiros convertéronse a outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Copiáronse <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros no portapapeis.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Rexeitar"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/config.xml b/packages/DocumentsUI/res/values-gu-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-gu-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 927906a5963e..11519a1a9762 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"આના દ્વારા શેર કરો"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ફાઇલો કૉપિ કરી રહ્યાં છે"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ફાઇલો ખસેડી રહ્યાં છે"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ફાઇલોને કાઢી નાખી રહ્યાં છે"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> બાકી"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલો કૉપિ કરી રહ્યાં છે.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"કેટલીક ફાઇલો રૂપાંતરિત કરી હતી"</string>
<string name="allow" msgid="7225948811296386551">"મંજૂરી આપો"</string>
<string name="deny" msgid="2081879885755434506">"નકારો"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ફાઇલોને કાઢી નાખીએ?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">શું તમે ખરેખર <xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલને કાઢી નાખવા માગો છો?</item>
+ <item quantity="other">શું તમે ખરેખર <xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલને કાઢી નાખવા માગો છો?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hi/config.xml b/packages/DocumentsUI/res/values-hi/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-hi/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index f947d3db6f86..dcb7805f181a 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"इसके द्वारा साझा करें"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"फ़ाइलें कॉपी हो रही हैं"</string>
<string name="move_notification_title" msgid="6193835179777284805">"फाइलें ले जाई जा रही हैं"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"फ़ाइलें हटाई जा रही हैं"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शेष"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें कॉपी की जा रही हैं.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"कुछ फ़ाइलें रूपांतरित हो गई थीं"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
<string name="deny" msgid="2081879885755434506">"अस्वीकारें"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"फ़ाइलें हटाएं?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">क्या आप वाकई <xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाना चाहते हैं?</item>
+ <item quantity="other">क्या आप वाकई <xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाना चाहते हैं?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hr/config.xml b/packages/DocumentsUI/res/values-hr/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-hr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index bfac527bd142..7d9b6f0f968f 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Dijeli putem"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Premještanje datoteka"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje datoteka"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -118,4 +119,10 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke su datoteke konvertirane"</string>
<string name="allow" msgid="7225948811296386551">"Dopusti"</string>
<string name="deny" msgid="2081879885755434506">"Odbij"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Izbrisati datoteke?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+ <item quantity="few">Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hu/config.xml b/packages/DocumentsUI/res/values-hu/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-hu/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 220d99c9dab1..ac40f87db7db 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Megosztás itt:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fájlok másolása"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Fájlok áthelyezése"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Fájlok törlése"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> van hátra"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fájl másolása.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Egyes fájlokat konvertált a rendszer"</string>
<string name="allow" msgid="7225948811296386551">"Engedélyezés"</string>
<string name="deny" msgid="2081879885755434506">"Elutasítás"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Törli a fájlokat?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Biztosan töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
+ <item quantity="one">Biztosan töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/config.xml b/packages/DocumentsUI/res/values-hy-rAM/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-hy-rAM/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 39344de20ba0..2ad2aa7c2ec8 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Թաքցնել արմատները"</string>
<string name="save_error" msgid="6167009778003223664">"Չհաջողվեց պահել փաստաթուղթը"</string>
<string name="create_error" msgid="3735649141335444215">"Չհաջողվեց ստեղծել պանակը"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Այս պահին հնարավոր չէ բեռնել բովանդակությունը"</string>
<string name="root_recent" msgid="4470053704320518133">"Վերջին"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ազատ է"</string>
<string name="root_type_service" msgid="2178854894416775409">"Պահուստի ծառայություններ"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Հավելյալ ծրագրեր"</string>
<string name="empty" msgid="7858882803708117596">"Տարրեր չկան"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s-ում համընկնումներ չկան"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Հնարավոր չէ բացել ֆայլը"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Անհնար է ջնջել որոշ փաստաթղթեր"</string>
<string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Ֆայլերի պատճենում"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Ֆայլերի տեղափոխում"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Մնացել է <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլի պատճենում:</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Պատճենման նախապատրաստում…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Տեղափոխման նախապատրաստում…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Պատրաստվում է ջնջել…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Չհաջողվեց պատճենել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ <item quantity="other">Չհաջողվեց պատճենել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Չհաջողվեց տեղափոխել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ <item quantity="other">Չհաջողվեց տեղափոխել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Չհաջողվեց ջնջել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ <item quantity="other">Չհաջողվեց ջնջել <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Հպեք՝ մանրամասները դիտելու համար"</string>
<string name="close" msgid="3043722427445528732">"Փակել"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Հետևյալ ֆայլերը չեն պատճենվել՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Հետևյալ ֆայլերը չեն տեղափոխվել՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Այս ֆայլերը փոխարկվել են մեկ այլ ձևաչափի՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ պատճենվեց սեղմատախտակին:</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
<string name="allow" msgid="7225948811296386551">"Թույլատրել"</string>
<string name="deny" msgid="2081879885755434506">"Մերժել"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-in/config.xml b/packages/DocumentsUI/res/values-in/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-in/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 4d4e81002840..66d40d21f9e7 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Menyalin file"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Memindahkan file"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
<string name="allow" msgid="7225948811296386551">"Izinkan"</string>
<string name="deny" msgid="2081879885755434506">"Tolak"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/config.xml b/packages/DocumentsUI/res/values-is-rIS/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-is-rIS/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 1d3d75f20ca3..290ec9268e05 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Fela rótarsöfn"</string>
<string name="save_error" msgid="6167009778003223664">"Mistókst að vista skjalið"</string>
<string name="create_error" msgid="3735649141335444215">"Mistókst að búa til möppu"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Ekki hægt að hlaða efni í augnablikinu"</string>
<string name="root_recent" msgid="4470053704320518133">"Nýlegt"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> laus"</string>
<string name="root_type_service" msgid="2178854894416775409">"Geymsluþjónusta"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Fleiri forrit"</string>
<string name="empty" msgid="7858882803708117596">"Engin atriði"</string>
<string name="no_results" msgid="6622510343880730446">"Engar samsvarandi niðurstöður í %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Ekki hægt að opna skrá"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ekki er hægt að eyða einhverjum skjölum"</string>
<string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Afritar skrár"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Skrár færðar"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> eftir"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Afritar <xliff:g id="COUNT_1">%1$d</xliff:g> skrá.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Undirbúningur fyrir afritun…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Flutningur undirbúinn…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Býr sig undir að eyða…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Ekki tókst að afrita <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+ <item quantity="other">Ekki tókst að afrita <xliff:g id="COUNT_1">%1$d</xliff:g> skrár</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Ekki tókst að færa <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+ <item quantity="other">Ekki tókst að færa <xliff:g id="COUNT_1">%1$d</xliff:g> skrár</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Ekki tókst að eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+ <item quantity="other">Ekki tókst að eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Ýttu til að skoða frekari upplýsingar"</string>
<string name="close" msgid="3043722427445528732">"Loka"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Þessar skrár voru ekki afritaðar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Þessar skrár voru ekki færðar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Þessum skrám var umbreytt yfir á annað snið: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> skrá afrituð á klippiborð.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
<string name="allow" msgid="7225948811296386551">"Leyfa"</string>
<string name="deny" msgid="2081879885755434506">"Hafna"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-it/config.xml b/packages/DocumentsUI/res/values-it/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-it/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 373f480007d9..43f5fcb5b859 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copia di file in corso"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Spostamento di file"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
<string name="allow" msgid="7225948811296386551">"Consenti"</string>
<string name="deny" msgid="2081879885755434506">"Nega"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-iw/config.xml b/packages/DocumentsUI/res/values-iw/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-iw/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index e0f750ace11c..622785c4b500 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"הסתר שורשים"</string>
<string name="save_error" msgid="6167009778003223664">"שמירת המסמך נכשלה"</string>
<string name="create_error" msgid="3735649141335444215">"יצירת התיקיה נכשלה"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"לא ניתן כרגע לטעון תוכן"</string>
<string name="root_recent" msgid="4470053704320518133">"מהזמן האחרון"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> של שטח פנוי"</string>
<string name="root_type_service" msgid="2178854894416775409">"שירותי אחסון"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"עוד אפליקציות"</string>
<string name="empty" msgid="7858882803708117596">"אין פריטים"</string>
<string name="no_results" msgid="6622510343880730446">"‏אין התאמות ב-%1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"לא ניתן לפתוח את הקובץ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"לא ניתן למחוק חלק מהמסמכים"</string>
<string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"מעתיק קבצים"</string>
<string name="move_notification_title" msgid="6193835179777284805">"מעביר קבצים"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"זמן נותר: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="two">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
@@ -92,15 +92,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"מתכונן להעתקה..."</string>
<string name="move_preparing" msgid="2772219441375531410">"מתכונן להעברה…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"מתכונן למחיקה…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="two">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="many">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="other">לא ניתן היה להעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="one">לא ניתן היה להעתיק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="two">לא ניתן היה להעביר <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="many">לא ניתן היה להעביר <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="other">לא ניתן היה להעביר <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="one">לא ניתן היה להעביר <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="two">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="many">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="other">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים</item>
+ <item quantity="one">לא ניתן היה למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"הקש כדי להציג פרטים"</string>
<string name="close" msgid="3043722427445528732">"סגור"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"הקבצים הבאים לא הועתקו: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"הקבצים הבאים לא הועברו: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"הקבצים האלה הומרו לפורמט אחר: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> קבצים הועתקו אל הלוח.</item>
@@ -114,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
<string name="allow" msgid="7225948811296386551">"אפשר"</string>
<string name="deny" msgid="2081879885755434506">"דחה"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ja/config.xml b/packages/DocumentsUI/res/values-ja/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ja/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index c56876dd5169..3319af070bd1 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ルートを非表示にする"</string>
<string name="save_error" msgid="6167009778003223664">"ドキュメントを保存できませんでした"</string>
<string name="create_error" msgid="3735649141335444215">"フォルダを作成できませんでした"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"現在、コンテンツを読み込むことができません"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"空き容量: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"ストレージサービス"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"その他のアプリ"</string>
<string name="empty" msgid="7858882803708117596">"アイテムがありません"</string>
<string name="no_results" msgid="6622510343880730446">"該当するものは %1$s にありません"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ファイルを開けません"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"一部のドキュメントを削除できません"</string>
<string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ファイルのコピー中"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ファイルを移動中"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"残り<xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>個のファイルをコピーしています。</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"コピーの準備をしています…"</string>
<string name="move_preparing" msgid="2772219441375531410">"移動の準備をしています…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"削除の準備をしています…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルをコピーできませんでした</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルをコピーできませんでした</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを移動できませんでした</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを移動できませんでした</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除できませんでした</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除できませんでした</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"タップすると詳細が表示されます"</string>
<string name="close" msgid="3043722427445528732">"閉じる"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"次のファイルをコピーできませんでした: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"次のファイルを移動できませんでした: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"次のファイルが別の形式に変換されました: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>件のファイルをクリップボードにコピーしました。</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
<string name="allow" msgid="7225948811296386551">"許可"</string>
<string name="deny" msgid="2081879885755434506">"拒否"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/config.xml b/packages/DocumentsUI/res/values-ka-rGE/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ka-rGE/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 69ffda20625d..30b78e5f7ef4 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ფესვების დამალვა"</string>
<string name="save_error" msgid="6167009778003223664">"დოკუმენტის შენახვა ვერ მოხერხდა"</string>
<string name="create_error" msgid="3735649141335444215">"საქაღალდის შექმნა ვერ მოხერხდა"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"კონტენტის ჩატვირთვა ამჟამად ვერ ხერხდება"</string>
<string name="root_recent" msgid="4470053704320518133">"ბოლო"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> თავისუფალია"</string>
<string name="root_type_service" msgid="2178854894416775409">"მეხსიერების სერვისები"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"მეტი აპები"</string>
<string name="empty" msgid="7858882803708117596">"ერთეულები არ არის"</string>
<string name="no_results" msgid="6622510343880730446">"„%1$s“-ში დამთხვევა ვერ მოიძებნა"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ფაილის გახსნა ვერ ხერხდება"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ზოგიერთი დოკუმენტის წაშლა ვერ ხერხდება"</string>
<string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"მიმდ. ფაილების კოპირება"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ფაილების გადაადგილება"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"დარჩა <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">მიმდინარეობს <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის კოპირება.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"მომზადება კოპირებისთვის…"</string>
<string name="move_preparing" msgid="2772219441375531410">"გადაადგილება მზადდება..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"მზადდება წასაშლელად…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ფაილი ვერ დაკოპირდა</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ფაილი ვერ დაკოპირდა</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ფაილი ვერ გადაადგილდა</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ფაილი ვერ გადაადგილდა</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ფაილი ვერ წაიშალა</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ფაილი ვერ წაიშალა</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"შეეხეთ დეტალების სანახავად"</string>
<string name="close" msgid="3043722427445528732">"დახურვა"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"შემდეგი ფაილები არ დაკოპირდა: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"შემდეგი ფაილები არ გადაადგილდა: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"შემდეგი ფაილები გარდაქმნილია სხვა ფორმატში: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">მოხდა <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის გაცვლის ბუფერში კოპირება.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
<string name="allow" msgid="7225948811296386551">"უფლების მიცემა"</string>
<string name="deny" msgid="2081879885755434506">"აკრძალვა"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/config.xml b/packages/DocumentsUI/res/values-kk-rKZ/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-kk-rKZ/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index a6a38765d7ed..ab045c66d915 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -53,7 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Тамырын жасыру"</string>
<string name="save_error" msgid="6167009778003223664">"Құжатты сақтау орындалмады"</string>
<string name="create_error" msgid="3735649141335444215">"Қалта жасақтау іске аспады"</string>
- <string name="query_error" msgid="5999895349602476581">"Қазіргі уақытта мазмұнды жүктеу мүмкін емес"</string>
+ <string name="query_error" msgid="5999895349602476581">"Қазір мазмұнды жүктеу мүмкін емес"</string>
<string name="root_recent" msgid="4470053704320518133">"Жуықта қолданылған"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> бос"</string>
<string name="root_type_service" msgid="2178854894416775409">"Жад қызметтері"</string>
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Бөлісу"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлдарды көшіру"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файлдар тасымалдануда"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> қалды"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды көшіру.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
<string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
<string name="deny" msgid="2081879885755434506">"Бас тарту"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/config.xml b/packages/DocumentsUI/res/values-km-rKH/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-km-rKH/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 4664bd435d63..a084f81adc73 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"ចែករំលែក​តាម"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"កំពុងថតចម្លងឯកសារ"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ផ្លាស់ទីឯកសារ"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"កំពុងលុបឯកសារ"</string>
<string name="copy_remaining" msgid="6283790937387975095">"នៅសល់ <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">កំពុងថតចម្លងឯកសារចំនួន <xliff:g id="COUNT_1">%1$d</xliff:g> ។</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ឯកសារមួយចំនួនត្រូវបានបម្លែង"</string>
<string name="allow" msgid="7225948811296386551">"អនុញ្ញាត​"</string>
<string name="deny" msgid="2081879885755434506">"បដិសេធ"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"លុបឯកសារឬទេ?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">តើអ្នកប្រាកដថាអ្នកចង់លុប <xliff:g id="COUNT_1">%1$d</xliff:g> ឯកសារឬទេ?</item>
+ <item quantity="one">តើអ្នកប្រាកដថាអ្នកចង់លុប <xliff:g id="COUNT_0">%1$d</xliff:g> ឯកសារឬទេ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/config.xml b/packages/DocumentsUI/res/values-kn-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-kn-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 9c956f58fe88..55c9697991ae 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ರೂಟ್‌ಗಳನ್ನು ಮರೆಮಾಡು"</string>
<string name="save_error" msgid="6167009778003223664">"ಡಾಕ್ಯುಮೆಂಟ್ ಉಳಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="create_error" msgid="3735649141335444215">"ಫೋಲ್ಡರ್ ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"ಈ ಕ್ಷಣದಲ್ಲಿ ವಿಷಯವನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="root_recent" msgid="4470053704320518133">"ಇತ್ತೀಚಿನದು"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ಮುಕ್ತವಾಗಿದೆ"</string>
<string name="root_type_service" msgid="2178854894416775409">"ಸಂಗ್ರಹಣೆ ಸೇವೆಗಳು"</string>
@@ -63,12 +62,12 @@
<string name="root_type_apps" msgid="8838065367985945189">"ಇನ್ನಷ್ಟು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
<string name="empty" msgid="7858882803708117596">"ಯಾವುದೇ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s ರಲ್ಲಿ ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಗಳಿಲ್ಲ"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ಫೈಲ್ ತೆರೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ಕೆಲವು ಡಾಕ್ಯುಮೆಂಟ್‌ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="share_via" msgid="8966594246261344259">"ಈ ಮೂಲಕ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ಫೈಲ್‌ಗಳನ್ನು ಸರಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ಫೈಲ್ ಅಳಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ಉಳಿದಿದೆ"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ.</item>
@@ -86,15 +85,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"ನಕಲಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
<string name="move_preparing" msgid="2772219441375531410">"ಸರಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"ಅಳಿಸಲು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಸರಿಸಲಾಗಲಿಲ್ಲ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಸರಿಸಲಾಗಲಿಲ್ಲ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="close" msgid="3043722427445528732">"ಮುಚ್ಚು"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ಈ ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗಿಲ್ಲ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"ಈ ಫೈಲ್‌ಗಳನ್ನು ಸರಿಸಲಾಗಿಲ್ಲ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ಈ ಫೈಲ್‌ಗಳನ್ನು ಮತ್ತೊಂದು ಫಾರ್ಮೆಟ್‌ಗೆ ಪರಿವರ್ತಿಸಲಾಗಿತ್ತು: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗಿದೆ.</item>
@@ -106,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ಕೆಲವು ಫೈಲ್‌ಗಳನ್ನು ಪರಿವರ್ತಿಸಲಾಗಿದೆ"</string>
<string name="allow" msgid="7225948811296386551">"ಅನುಮತಿಸು"</string>
<string name="deny" msgid="2081879885755434506">"ನಿರಾಕರಿಸು"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುವುದೇ?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ko/config.xml b/packages/DocumentsUI/res/values-ko/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ko/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 62336c786344..37642d1e0330 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"공유 방법"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"파일 복사 중"</string>
<string name="move_notification_title" msgid="6193835179777284805">"파일 이동"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"파일 삭제"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> 남음"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 복사합니다.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"일부 파일이 변환되었습니다."</string>
<string name="allow" msgid="7225948811296386551">"허용"</string>
<string name="deny" msgid="2081879885755434506">"거부"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"파일을 삭제하시겠습니까?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+ <item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/config.xml b/packages/DocumentsUI/res/values-ky-rKG/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ky-rKG/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index 1dc5e77373bd..ba3a6e32d8c4 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Папкаларды жашыруу"</string>
<string name="save_error" msgid="6167009778003223664">"Документтерди сактоо кыйрады"</string>
<string name="create_error" msgid="3735649141335444215">"Папка түзүү кыйрады"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Учурда мазмун жүктөлбөй жатат"</string>
<string name="root_recent" msgid="4470053704320518133">"Акыркы"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> бош"</string>
<string name="root_type_service" msgid="2178854894416775409">"Сактагыч кызматтар"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Көбүрөөк колдонмолор"</string>
<string name="empty" msgid="7858882803708117596">"Эч нерсе жок"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s ичинде дал келүүлөр жок"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Файл ачылбай жатат"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Кээ бир документтерди өчүрүү кыйрады"</string>
<string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлдар көчүрүлүүдө"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файлдар жылдырылууда…"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> калды"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлүүдө.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Көчүрүүгө даярдалууда…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Жылдырууга даярдалууда…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Жок кылууга даярдалууда…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлбөй койду</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл көчүрүлбөй койду</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жылдырылбай койду</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жылдырылбай койду</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынбай койду</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынбай койду</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Чоо-жайын көрүү үчүн таптаңыз"</string>
<string name="close" msgid="3043722427445528732">"Жабуу"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Төмөнкү файлдар көчүрүлгөн жок: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Төмөнкү файлдар жылдырылган жок: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Бул файлдар башка форматка айландырылды: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл буферге көчүрүлдү.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
<string name="allow" msgid="7225948811296386551">"Уруксат берүү"</string>
<string name="deny" msgid="2081879885755434506">"Жок"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ldrtl/dimens.xml b/packages/DocumentsUI/res/values-ldrtl/config.xml
index 22f8131474c4..22f8131474c4 100644
--- a/packages/DocumentsUI/res/values-ldrtl/dimens.xml
+++ b/packages/DocumentsUI/res/values-ldrtl/config.xml
diff --git a/packages/DocumentsUI/res/values-lo-rLA/config.xml b/packages/DocumentsUI/res/values-lo-rLA/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-lo-rLA/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 65276ba25aa3..edfca5ca4857 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"ແບ່ງປັນຜ່ານ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ​ໄຟ​ລ໌"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ກຳ​ລັງ​ຍ້າຍ​ໄຟ​ລ໌"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ກຳລັງລຶບໄຟລ໌"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ຍັງ​ເຫຼືອ​ຢູ່"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟ​ລ໌.</item>
@@ -85,8 +86,8 @@
<string name="move_preparing" msgid="2772219441375531410">"ກຳ​ລັງ​ກະ​ກຽມ​ຍ້າຍ…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"ກຳລັງກະກຽມລຶບ…"</string>
<plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
- <item quantity="other">ບໍ່ສາມາດອັດສຳເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
- <item quantity="one">ບໍ່ສາມາດອັດສຳເນົາ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
+ <item quantity="other">ບໍ່ສາມາດສຳເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
+ <item quantity="one">ບໍ່ສາມາດສຳເນົາ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
</plurals>
<plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
<item quantity="other">ບໍ່ສາມາດຍ້າຍ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ໄດ້</item>
@@ -98,7 +99,7 @@
</plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດ"</string>
<string name="close" msgid="3043722427445528732">"ປິດ"</string>
- <string name="copy_failure_alert_content" msgid="4563147454522476183">"ໄຟລ໌ເຫຼົ່ານີ້ບໍ່ໄດ້ຖືກອັດສຳເນົາ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ໄຟລ໌ເຫຼົ່ານີ້ບໍ່ໄດ້ຖືກສຳເນົາ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="move_failure_alert_content" msgid="2635075788682922861">"ໄຟລ໌ເຫຼົ່ານີ້ບໍ່ໄດ້ຖືກຍ້າຍ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ໄຟລ໌ເຫຼົ່ານີ້ໄດ້ຖືກປ່ຽນເປັນຮູບແບບອື່ນແລ້ວ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ປ່ຽນແປງບາງໄຟລ໌ແລ້ວ"</string>
<string name="allow" msgid="7225948811296386551">"ອະນຸຍາດ"</string>
<string name="deny" msgid="2081879885755434506">"ປະ​ຕິ​ເສດ"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ລຶບໄຟລ໌ອອກບໍ?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌?</item>
+ <item quantity="one">ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lt/config.xml b/packages/DocumentsUI/res/values-lt/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-lt/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 8de09ce40f5d..7e4292249652 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopijuojami failai"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Perkeliami failai"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Liko: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopijuojamas <xliff:g id="COUNT_1">%1$d</xliff:g> failas.</item>
@@ -125,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
<string name="allow" msgid="7225948811296386551">"Leisti"</string>
<string name="deny" msgid="2081879885755434506">"Atmesti"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-lv/config.xml b/packages/DocumentsUI/res/values-lv/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-lv/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 224e15b57a4c..14bd7a8b6c43 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Slēpt saknes"</string>
<string name="save_error" msgid="6167009778003223664">"Neizdevās saglabāt dokumentu."</string>
<string name="create_error" msgid="3735649141335444215">"Neizdevās izveidot mapi."</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Pašlaik nevar ielādēt saturu."</string>
<string name="root_recent" msgid="4470053704320518133">"Pēdējie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Brīva vieta: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Glabāšanas pakalpojumi"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Vairāk lietotņu"</string>
<string name="empty" msgid="7858882803708117596">"Nav vienumu"</string>
<string name="no_results" msgid="6622510343880730446">"Failā %1$s nav atbilstību"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Nevar atvērt failu."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nevar dzēst dažus dokumentus."</string>
<string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Notiek failu kopēšana"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Failu pārvietošana"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Atlikušais laiks: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="zero">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> failu kopēšana.</item>
@@ -89,15 +89,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Gatavošanās kopēšanai…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Sagatavošana pārvietošanai…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Notiek gatavošanās dzēšanai…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="zero">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ <item quantity="one">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
+ <item quantity="other">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="zero">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ <item quantity="one">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
+ <item quantity="other">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="zero">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ <item quantity="one">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
+ <item quantity="other">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Pieskarieties, lai skatītu informāciju"</string>
<string name="close" msgid="3043722427445528732">"Aizvērt"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Netika nokopēti šādi faili: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Netika pārvietoti šādi faili: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Šie faili tika pārveidoti citā formātā: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="zero"><xliff:g id="COUNT_1">%1$d</xliff:g> faili tika kopēti starpliktuvē.</item>
@@ -110,4 +120,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
<string name="allow" msgid="7225948811296386551">"Atļaut"</string>
<string name="deny" msgid="2081879885755434506">"Noraidīt"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/config.xml b/packages/DocumentsUI/res/values-mk-rMK/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-mk-rMK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 7798ea6d4720..129119bf7cf6 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Сподели преку"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Се копираат датотеки"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Датотеките се преместуваат"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Се бришат датотеки"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Уште <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Се копира <xliff:g id="COUNT_1">%1$d</xliff:g> датотека.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Некои датотеки беа конвертирани"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
<string name="deny" msgid="2081879885755434506">"Одбиј"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Избриши датотеки?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">Дали сте сигурни дека сакате да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+ <item quantity="other">Дали сте сигурни дека сакате да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/config.xml b/packages/DocumentsUI/res/values-ml-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ml-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index a9f9a46a553c..966ddbbd0c88 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"ഇതുവഴി പങ്കിടുക"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ഫയലുകൾ പകർത്തുന്നു"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ഫയലുകൾ നീക്കുന്നു"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ഫയലുകൾ ഇല്ലാതാക്കുന്നു"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ശേഷിക്കുന്നു"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ പകർത്തുന്നു.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ചില ഫയലുകൾ പരിവർത്തനം ചെയ്യപ്പെട്ടു"</string>
<string name="allow" msgid="7225948811296386551">"അനുവദിക്കുക"</string>
<string name="deny" msgid="2081879885755434506">"നിരസിക്കുക"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ഫയലുകൾ ഇല്ലാതാക്കണോ?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണമെന്ന് നിങ്ങൾക്ക് തീർച്ചയാണോ?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണമെന്ന് നിങ്ങൾക്ക് തീർച്ചയാണോ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/config.xml b/packages/DocumentsUI/res/values-mn-rMN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-mn-rMN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 0663588e6d13..85312952e7cd 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Дараахаар дамжуулан хуваалцах"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Файлуудыг хуулж байна"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Файлыг зөөвөрлөж байна"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> үлдсэн"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлуудыг хуулж байна.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
<string name="allow" msgid="7225948811296386551">"Зөвшөөрөх"</string>
<string name="deny" msgid="2081879885755434506">"Татгалзах"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/config.xml b/packages/DocumentsUI/res/values-mr-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-mr-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index 82bb882fa444..f747d1a62dde 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"द्वारे सामायिक करा"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"फायली कॉपी करीत आहे"</string>
<string name="move_notification_title" msgid="6193835179777284805">"फायली हलविणे"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शिल्लक"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल कॉपी करीत आहे.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
<string name="allow" msgid="7225948811296386551">"अनुमती द्या"</string>
<string name="deny" msgid="2081879885755434506">"नकार द्या"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/config.xml b/packages/DocumentsUI/res/values-ms-rMY/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ms-rMY/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index f24dc9671773..d481125a12e9 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Sembunyikan akar"</string>
<string name="save_error" msgid="6167009778003223664">"Gagal menyimpan dokumen"</string>
<string name="create_error" msgid="3735649141335444215">"Gagal membuat folder"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Tidak dapat memuatkan kandungan pada masa ini"</string>
<string name="root_recent" msgid="4470053704320518133">"Terbaharu"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> kosong"</string>
<string name="root_type_service" msgid="2178854894416775409">"Perkhidmatan storan"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Lebih banyak apl"</string>
<string name="empty" msgid="7858882803708117596">"Tiada item"</string>
<string name="no_results" msgid="6622510343880730446">"Tiada padanan dalam %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Tidak dapat membuka fail"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat memadam beberapa dokumen"</string>
<string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Menyalin fail"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Mengalihkan fail"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Bersedia untuk salin..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Bersedia untuk mengalih…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Bersedia untuk memadam…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Tidak dapat menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+ <item quantity="one">Tidak dapat menyalin <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Tidak dapat mengalihkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+ <item quantity="one">Tidak dapat mengalihkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Tidak dapat memadamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+ <item quantity="one">Tidak dapat memadamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Ketik untuk melihat butiran"</string>
<string name="close" msgid="3043722427445528732">"Tutup"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Fail ini tidak disalin: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Fail ini tidak dialihkan: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Fail ini telah ditukarkan kepada format lain: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fail disalin ke papan keratan.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
<string name="allow" msgid="7225948811296386551">"Benarkan"</string>
<string name="deny" msgid="2081879885755434506">"Nafi"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/config.xml b/packages/DocumentsUI/res/values-my-rMM/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-my-rMM/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 74d0ae40c428..13392fc8b3fd 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -53,7 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ဖိုဒါကို ပိတ်လိုက်ပါ"</string>
<string name="save_error" msgid="6167009778003223664">"စာရွက်စာတန်း သိမ်းဆည်းမှု မအောင်​မြင်ပါ"</string>
<string name="create_error" msgid="3735649141335444215">"အကန့်အသစ် ဖန်တီးခြင်း မအောင်မြင်ပါ"</string>
- <string name="query_error" msgid="5999895349602476581">"အကြောင်းအရာများကို လောလောဆယ်တွင် ဖွင့်၍မရသေးပါ"</string>
+ <string name="query_error" msgid="5999895349602476581">"အကြောင်းအရာများကို လောလောဆယ်တွင် တင်၍မရသေးပါ"</string>
<string name="root_recent" msgid="4470053704320518133">"လတ်တလော"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> အသုံးချနိုင်ပါသည်"</string>
<string name="root_type_service" msgid="2178854894416775409">"သိုလှောင်ရန်ဆားဗစ်များ"</string>
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"မှ ဝေမျှပါ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ဖိုင်များကူယူနေသည်"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ဖိုင်များ ရွှေ့နေသည်"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ဖိုင်များကို ဖျက်နေသည်"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ကျန်ရှိသည်"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ဖိုင်များကို ကူးယူနေသည်။</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"အချို့ဖိုင်များကို ပြောင်းလဲထားသည်"</string>
<string name="allow" msgid="7225948811296386551">"ခွင့်ပြုသည်"</string>
<string name="deny" msgid="2081879885755434506">"ငြင်းပယ်သည်"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ဖိုင်များကို ဖျက်မလား။"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ဖိုင်များကိုဖျက်ရန် သေချာပါသလား။</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ဖိုင်ကိုဖျက်ရန် သေချာပါသလား။</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-nb/config.xml b/packages/DocumentsUI/res/values-nb/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-nb/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index aa74b9818c14..8271428c9037 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skjul røtter"</string>
<string name="save_error" msgid="6167009778003223664">"Kunne ikke lagre dokumentet"</string>
<string name="create_error" msgid="3735649141335444215">"Kunne ikke opprette mappen"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Kan ikke laste inn innholdet for øyeblikket"</string>
<string name="root_recent" msgid="4470053704320518133">"Siste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledig"</string>
<string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Flere apper"</string>
<string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
<string name="no_results" msgid="6622510343880730446">"Ingen treff i %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Kan ikke åpne filen"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Enkelte dokumenter kunne ikke slettes"</string>
<string name="share_via" msgid="8966594246261344259">"Del via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> gjenstår"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Forbereder kopiering …"</string>
<string name="move_preparing" msgid="2772219441375531410">"Forbereder flytting …"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Gjøres klar for sletting …"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Kunne ikke kopiere <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+ <item quantity="one">Kunne ikke kopiere <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Kunne ikke flytte <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+ <item quantity="one">Kunne ikke flytte <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Kunne ikke slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+ <item quantity="one">Kunne ikke slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Trykk for å se detaljer"</string>
<string name="close" msgid="3043722427445528732">"Lukk"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Disse filene er ikke kopiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Disse filene er ikke flyttet: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Disse filene er konvertert til et annet format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Kopierte <xliff:g id="COUNT_1">%1$d</xliff:g> filer til utklippstavlen.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
<string name="allow" msgid="7225948811296386551">"Tillat"</string>
<string name="deny" msgid="2081879885755434506">"Avslå"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/config.xml b/packages/DocumentsUI/res/values-ne-rNP/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ne-rNP/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index ccc54c7f1615..d0bc737b7103 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -53,7 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"मूलहरू लुकाउनुहोस्"</string>
<string name="save_error" msgid="6167009778003223664">"कागजात सुरक्षित गर्न विफल भयो"</string>
<string name="create_error" msgid="3735649141335444215">"फोल्डर सिर्जना गर्न असफल भयो"</string>
- <string name="query_error" msgid="5999895349602476581">"यो समय सामग्री लोड गर्न सक्दैन"</string>
+ <string name="query_error" msgid="5999895349602476581">"अहिले सामग्री लोड गर्न सक्दैन"</string>
<string name="root_recent" msgid="4470053704320518133">"हालैको"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> खाली"</string>
<string name="root_type_service" msgid="2178854894416775409">"भण्डारण सेवाहरू"</string>
@@ -62,11 +62,12 @@
<string name="root_type_apps" msgid="8838065367985945189">"थप अनुप्रयोगहरू"</string>
<string name="empty" msgid="7858882803708117596">"कुनै वस्तु छैन।"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s मा कुनै पनि मेल खानेहरू छैन"</string>
- <string name="toast_no_application" msgid="4632640357724698144">"फाइल खोल्न सकिदैन"</string>
+ <string name="toast_no_application" msgid="4632640357724698144">"फाइल खोल्न सक्दैन"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"केही कागजातहरू मेट्न असमर्थ छ"</string>
<string name="share_via" msgid="8966594246261344259">"माध्यमबाट साझेदारी गर्नुहोस्"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"फाइलहरू प्रतिलिपि गर्दै:"</string>
<string name="move_notification_title" msgid="6193835179777284805">"फाइलहरू सार्दै"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"फाइलहरूलाई मेट्दै"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g>बाँकी"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g>फाइलहरू प्रतिलिप गर्दै।</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"केही फाइलहरू परिवर्तन गरिएका थिए"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दिनुहोस्"</string>
<string name="deny" msgid="2081879885755434506">"अस्वीकार गर्नुहोस्"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"फाइलहरूलाई मेट्ने हो?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">तपाईँ निश्चित रूपमा <xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्न चाहनुहुन्छ?</item>
+ <item quantity="one">तपाईँ निश्चित रूपमा <xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्न चाहनुहुन्छ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-nl/config.xml b/packages/DocumentsUI/res/values-nl/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-nl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 99a9f91751db..257e7e421b0c 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Delen via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Bestanden kopiëren"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Bestanden verplaatsen"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Bestanden verwijderen"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> resterend"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden kopiëren.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige bestanden zijn geconverteerd"</string>
<string name="allow" msgid="7225948811296386551">"Toestaan"</string>
<string name="deny" msgid="2081879885755434506">"Weigeren"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Bestanden verwijderen?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Weet je zeker dat je <xliff:g id="COUNT_1">%1$d</xliff:g> bestanden wilt verwijderen?</item>
+ <item quantity="one">Weet je zeker dat je <xliff:g id="COUNT_0">%1$d</xliff:g> bestand wilt verwijderen?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/config.xml b/packages/DocumentsUI/res/values-pa-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-pa-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 0fb35fada75c..7dca3cf238f0 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ਰੂਟਸ ਲੁਕਾਓ"</string>
<string name="save_error" msgid="6167009778003223664">"ਦਸਾਤਵੇਜ਼ ਸੁਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ"</string>
<string name="create_error" msgid="3735649141335444215">"ਫੋਲਡਰ ਬਣਾਉਣ ਲਈ ਅਸਫਲ"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"ਇਸ ਵੇਲੇ ਸਮੱਗਰੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="root_recent" msgid="4470053704320518133">"ਹਾਲੀਆ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ਖਾਲੀ"</string>
<string name="root_type_service" msgid="2178854894416775409">"ਸਟੋਰੇਜ ਸੇਵਾਵਾਂ"</string>
@@ -63,12 +62,12 @@
<string name="root_type_apps" msgid="8838065367985945189">"ਹੋਰ ਐਪਸ"</string>
<string name="empty" msgid="7858882803708117596">"ਕੋਈ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s ਵਿੱਚ ਕੋਈ ਮੇਲ ਨਹੀਂ"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"ਫ਼ਾਈਲ ਨੂੰ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ਕੁਝ ਦਸਤਾਵੇਜ਼ ਮਿਟਾਉਣ ਵਿੱਚ ਅਸਮਰੱਥ"</string>
<string name="share_via" msgid="8966594246261344259">"ਇਸ ਰਾਹੀਂ ਸ਼ੇਅਰ ਕਰੋ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ਫਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ਫ਼ਾਈਲਾਂ ਨੂੰ ਮੂਵ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ਬਾਕੀ"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ਫਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ।</item>
@@ -86,15 +85,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"ਕਾਪੀ ਲਈ ਤਿਆਰ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="move_preparing" msgid="2772219441375531410">"ਮੂਵ ਲਈ ਤਿਆਰ ਕਰ ਰਿਹਾ ਹੈ..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"ਮਿਟਾਉਣ ਦੀ ਤਿਆਰੀ ਹੋ ਰਹੀ ਹੈ…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਤਬਦੀਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਤਬਦੀਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"ਵੇਰਵਿਆਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="close" msgid="3043722427445528732">"ਬੰਦ ਕਰੋ"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ਇਹ ਫ਼ਾਈਲਾਂ ਕਾਪੀ ਨਹੀਂ ਹੋਈਆਂ ਸਨ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"ਇਹ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਨਹੀਂ ਹੋਈਆਂ ਸਨ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ਇਹ ਫ਼ਾਈਲਾਂ ਕਿਸੇ ਹੋਰ ਫੌਰਮੈਟ ਵਿੱਚ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਦੀ ਪ੍ਰਤੀਲਿਪੀ ਬਣਾਈ ਗਈ।</item>
@@ -106,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ਕੁਝ ਫ਼ਾਈਲਾਂ ਤਬਦੀਲ ਕੀਤੀਆਂ ਗਈਆਂ ਸਨ"</string>
<string name="allow" msgid="7225948811296386551">"ਆਗਿਆ ਦਿਓ"</string>
<string name="deny" msgid="2081879885755434506">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ਕੀ ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ \'ਤੇ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?</item>
+ <item quantity="other">ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ \'ਤੇ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pl/config.xml b/packages/DocumentsUI/res/values-pl/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-pl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 790c7b7aed56..7330e1e89224 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ukryj elementy główne"</string>
<string name="save_error" msgid="6167009778003223664">"Nie udało się zapisać dokumentu"</string>
<string name="create_error" msgid="3735649141335444215">"Nie udało się utworzyć folderu"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Teraz nie można załadować zawartości"</string>
<string name="root_recent" msgid="4470053704320518133">"Ostatnie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> wolne"</string>
<string name="root_type_service" msgid="2178854894416775409">"Usługi pamięci masowej"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
<string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
<string name="no_results" msgid="6622510343880730446">"Brak wyników w %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Nie można otworzyć pliku"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Nie można usunąć niektórych dokumentów"</string>
<string name="share_via" msgid="8966594246261344259">"Udostępnij przez:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiowanie plików"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Przenoszenie plików"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Pozostało: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> plików.</item>
@@ -92,15 +92,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Przygotowuję do kopiowania…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Przygotowuję przenoszenie…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Przygotowuję do usunięcia…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="many">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="other">Nie udało się skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+ <item quantity="one">Nie udało się skopiować <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="many">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="other">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+ <item quantity="one">Nie udało się przenieść <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="many">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+ <item quantity="other">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+ <item quantity="one">Nie udało się usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Kliknij, by zobaczyć szczegóły"</string>
<string name="close" msgid="3043722427445528732">"Zamknij"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Te pliki nie zostały skopiowane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Te pliki nie zostały przeniesione: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Te pliki zostały przekonwertowane na inny format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few">Skopiowano <xliff:g id="COUNT_1">%1$d</xliff:g> pliki do schowka.</item>
@@ -114,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
<string name="allow" msgid="7225948811296386551">"Zezwól"</string>
<string name="deny" msgid="2081879885755434506">"Odmów"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/config.xml b/packages/DocumentsUI/res/values-pt-rBR/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-pt-rBR/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 8e62483d6ed1..44f2ab84830a 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raízes"</string>
<string name="save_error" msgid="6167009778003223664">"Falha ao salvar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Falha ao criar a pasta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Não é possível carregar o conteúdo no momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> livres"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serviços de armazenamento"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Mais apps"</string>
<string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
<string name="no_results" msgid="6622510343880730446">"Nenhum resultado em %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Não é possível abrir o arquivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparando para mover..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando-se para excluir..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tocar para ver detalhes"</string>
<string name="close" msgid="3043722427445528732">"Fechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Estes arquivos não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Estes arquivos não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Esses arquivos foram convertidos em outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> arquivos copiados para a área de transferência.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Negar"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/config.xml b/packages/DocumentsUI/res/values-pt-rPT/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-pt-rPT/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 02467fed8d0a..3d999c7258bb 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raízes"</string>
<string name="save_error" msgid="6167009778003223664">"Falha ao guardar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Falha ao criar a pasta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Não é possível carregar o conteúdo neste momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> espaço livre"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serv. de armazenamento"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
<string name="empty" msgid="7858882803708117596">"Sem itens"</string>
<string name="no_results" msgid="6622510343880730446">"Sem correspondências para %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Não é possível abrir o ficheiro"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não é possível eliminar alguns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"A copiar ficheiros"</string>
<string name="move_notification_title" msgid="6193835179777284805">"A mover ficheiros"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">A copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"A preparar para copiar…"</string>
<string name="move_preparing" msgid="2772219441375531410">"A preparar para mover…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"A preparar para eliminar…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Não foi possível mover <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">Não foi possível eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+ <item quantity="one">Não foi possível eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Toque para ver detalhes"</string>
<string name="close" msgid="3043722427445528732">"Fechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Os seguintes ficheiros não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Os seguintes ficheiros não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Estes ficheiros foram convertidos para outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">Copiou <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros para a área de transferência.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Recusar"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-pt/config.xml b/packages/DocumentsUI/res/values-pt/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-pt/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 8e62483d6ed1..44f2ab84830a 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ocultar raízes"</string>
<string name="save_error" msgid="6167009778003223664">"Falha ao salvar o documento"</string>
<string name="create_error" msgid="3735649141335444215">"Falha ao criar a pasta"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Não é possível carregar o conteúdo no momento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> livres"</string>
<string name="root_type_service" msgid="2178854894416775409">"Serviços de armazenamento"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Mais apps"</string>
<string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
<string name="no_results" msgid="6622510343880730446">"Nenhum resultado em %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Não é possível abrir o arquivo"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
<string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Preparando para mover..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Preparando-se para excluir..."</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ <item quantity="other">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Tocar para ver detalhes"</string>
<string name="close" msgid="3043722427445528732">"Fechar"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Estes arquivos não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Estes arquivos não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Esses arquivos foram convertidos em outro formato: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> arquivos copiados para a área de transferência.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
<string name="allow" msgid="7225948811296386551">"Permitir"</string>
<string name="deny" msgid="2081879885755434506">"Negar"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ro/config.xml b/packages/DocumentsUI/res/values-ro/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ro/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index a598fe46fca8..d256a268ccb4 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Ascundeți directoarele rădăcină"</string>
<string name="save_error" msgid="6167009778003223664">"Salvarea documentului nu a reușit"</string>
<string name="create_error" msgid="3735649141335444215">"Eroare la crearea dosarului"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Momentan, conținutul nu poate fi încărcat"</string>
<string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> spațiu liber"</string>
<string name="root_type_service" msgid="2178854894416775409">"Servicii de stocare"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Alte aplicații"</string>
<string name="empty" msgid="7858882803708117596">"Nu există elemente"</string>
<string name="no_results" msgid="6622510343880730446">"Niciun rezultat în %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Fișierul nu poate fi deschis"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Unele documente nu au putut fi șterse"</string>
<string name="share_via" msgid="8966594246261344259">"Trimiteți prin"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Se copiază fișierele"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Se mută fișierele"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Timp rămas: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Se copiază <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere.</item>
@@ -89,15 +89,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Se pregătește copierea..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Se pregătește mutarea…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Se pregătește ștergerea…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
+ <item quantity="other">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
+ <item quantity="one">Nu s-a putut copia <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few">Nu s-au putut muta <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
+ <item quantity="other">Nu s-au putut muta <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
+ <item quantity="one">Nu s-a putut muta <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few">Nu s-au putut șterge <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
+ <item quantity="other">Nu s-au putut șterge <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
+ <item quantity="one">Nu s-a putut șterge <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Atingeți pentru a vedea detaliile"</string>
<string name="close" msgid="3043722427445528732">"Închideți"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Aceste fișiere nu au fost copiate: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Aceste fișiere nu au fost mutate: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Aceste fișiere au fost convertite în alt format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few">Au fost copiate <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere în clipboard.</item>
@@ -109,5 +119,8 @@
<string name="rename_error" msgid="4203041674883412606">"Documentul nu a putut fi redenumit"</string>
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
<string name="allow" msgid="7225948811296386551">"Permiteți"</string>
- <string name="deny" msgid="2081879885755434506">"Refuzaţi"</string>
+ <string name="deny" msgid="2081879885755434506">"Refuzați"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ru/config.xml b/packages/DocumentsUI/res/values-ru/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ru/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 934037ec4b4d..161bb195ebd9 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Скрыть"</string>
<string name="save_error" msgid="6167009778003223664">"Не удалось сохранить документ"</string>
<string name="create_error" msgid="3735649141335444215">"Не удалось создать папку"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Не удалось загрузить контент"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавние"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Свободно <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Службы хранения"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Другие приложения"</string>
<string name="empty" msgid="7858882803708117596">"Ничего нет"</string>
<string name="no_results" msgid="6622510343880730446">"В \"%1$s\" ничего не найдено"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Не удалось открыть файл"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Не удалось удалить некоторые документы"</string>
<string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копирование файлов"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Перемещение файлов"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Осталось <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файл...</item>
@@ -92,15 +92,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Подготовка к копированию…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Подготовка…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Подготовка к удалению…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+ <item quantity="few">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ <item quantity="many">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файлов</item>
+ <item quantity="other">Не удалось скопировать <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+ <item quantity="few">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ <item quantity="many">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов</item>
+ <item quantity="other">Не удалось переместить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
+ <item quantity="few">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ <item quantity="many">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов</item>
+ <item quantity="other">Не удалось удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Нажмите, чтобы узнать подробности."</string>
<string name="close" msgid="3043722427445528732">"Закрыть"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Не удалось скопировать следующие файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Не удалось переместить следующие файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Формат этих файлов изменен: <xliff:g id="LIST">%1$s</xliff:g>."</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Скопирован <xliff:g id="COUNT_1">%1$d</xliff:g> файл</item>
@@ -114,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
<string name="allow" msgid="7225948811296386551">"Разрешить"</string>
<string name="deny" msgid="2081879885755434506">"Отклонить"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/config.xml b/packages/DocumentsUI/res/values-si-rLK/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-si-rLK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index fdfabe2484ac..ae85f329cd9b 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"හරහා බෙදාගන්න"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ගොනු පිටපත් කරමින්"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ගොනු ගෙන යාම"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ගොනු මකමින්"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ඉතිරියි"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් පිටපත් කරමින්.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"සමහර ගොනු පරිවර්තනය කරන ලදී"</string>
<string name="allow" msgid="7225948811296386551">"අවසර දෙන්න"</string>
<string name="deny" msgid="2081879885755434506">"ප්‍රතික්ෂේප කරන්න"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ගොනු මකන්නද?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">ඔබට ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මැකීමට අවශ්‍ය බව විශ්වාසද?</item>
+ <item quantity="other">ඔබට ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මැකීමට අවශ්‍ය බව විශ්වාසද?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sk/config.xml b/packages/DocumentsUI/res/values-sk/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-sk/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index f83a173f091f..7919533b7b6f 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Skryť korene"</string>
<string name="save_error" msgid="6167009778003223664">"Dokument sa nepodarilo uložiť"</string>
<string name="create_error" msgid="3735649141335444215">"Priečinok sa nepodarilo vytvoriť"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Obsah momentálne nie je možné načítať"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedávne"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Voľné <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Služby úložiska"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
<string name="empty" msgid="7858882803708117596">"Žiadne položky"</string>
<string name="no_results" msgid="6622510343880730446">"Žiadne zhody – %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Súbor nie je možné otvoriť"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Niektoré dokumenty sa nepodarilo odstrániť"</string>
<string name="share_via" msgid="8966594246261344259">"Zdieľať"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopírovanie súborov"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Presúvajú sa súbory"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Zostáva: <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="few">Kopírujú sa <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
@@ -92,15 +92,28 @@
<string name="copy_preparing" msgid="3896202461003039386">"Pripravuje sa na kopírovanie..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Prebieha príprava na presunutie…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Príprava na odstránenie…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="few">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> súbory</item>
+ <item quantity="many">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> súboru</item>
+ <item quantity="other">Nepodarilo sa skopírovať <xliff:g id="COUNT_1">%1$d</xliff:g> súborov</item>
+ <item quantity="one">Nepodarilo sa skopírovať <xliff:g id="COUNT_0">%1$d</xliff:g> súbor</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> súbory nie je možné presunúť</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> súboru nie je možné presunúť</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> súborov nie je možné presunúť</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> súbor nie je možné presunúť</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="few">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory</item>
+ <item quantity="many">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru</item>
+ <item quantity="other">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov</item>
+ <item quantity="one">Nepodarilo sa odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Klepnutím zobrazíte podrobnosti"</string>
<string name="close" msgid="3043722427445528732">"Zavrieť"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Tieto súbory neboli skopírované: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Tieto súbory neboli presunuté: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Tieto súbory boli konvertované do iného formátu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="few">Do schránky boli skopírované <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
@@ -114,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
<string name="allow" msgid="7225948811296386551">"Povoliť"</string>
<string name="deny" msgid="2081879885755434506">"Zamietnuť"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sl/config.xml b/packages/DocumentsUI/res/values-sl/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-sl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index dc17a081bcdf..afcdb6ab199a 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Deli z drugimi prek"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datotek"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Premikanje datotek"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje datotek"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Še <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
@@ -125,4 +126,11 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nekatere datoteke so bile pretvorjene"</string>
<string name="allow" msgid="7225948811296386551">"Dovoli"</string>
<string name="deny" msgid="2081879885755434506">"Zavrni"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Ali želite izbrisati datoteke?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="one">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteko?</item>
+ <item quantity="two">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteki?</item>
+ <item quantity="few">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+ <item quantity="other">Ali res želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/config.xml b/packages/DocumentsUI/res/values-sq-rAL/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-sq-rAL/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 5ae1f2ab1e5d..7934b16b55d7 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Shpërnda publikisht përmes"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Po kopjon skedarët"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Po zhvendos skedarët"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Po fshin skedarët"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> të mbetura"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Po kopjon <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Disa skedarë u konvertuan"</string>
<string name="allow" msgid="7225948811296386551">"Lejo"</string>
<string name="deny" msgid="2081879885755434506">"Moho"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Të fshihen skedarët?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Je i sigurt se dëshiron të fshish <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
+ <item quantity="one">Je i sigurt se dëshiron të fshish <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sr/config.xml b/packages/DocumentsUI/res/values-sr/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-sr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 0152b3a3149f..ffa6944b70e3 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Сакриј основне елементе"</string>
<string name="save_error" msgid="6167009778003223664">"Чување документа није успело"</string>
<string name="create_error" msgid="3735649141335444215">"Директоријум није направљен"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Учитавање садржаја тренутно није могуће"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавно"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Слободно је <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"Услуге складиштења"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Још апликација"</string>
<string name="empty" msgid="7858882803708117596">"Нема ставки"</string>
<string name="no_results" msgid="6622510343880730446">"Нема подударања у %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Отварање датотеке није успело"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Није могуће избрисати неке документе"</string>
<string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копирање датотека"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Датотеке се премештају"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Још <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке.</item>
@@ -89,15 +89,25 @@
<string name="copy_preparing" msgid="3896202461003039386">"Припрема се копирање…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Припрема се премештање..."</string>
<string name="delete_preparing" msgid="5655813182533491992">"Припрема се брисање…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Нисмо успели да копирамо <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку</item>
+ <item quantity="few">Нисмо успели да копирамо <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке</item>
+ <item quantity="other">Нисмо успели да копирамо <xliff:g id="COUNT_1">%1$d</xliff:g> датотека</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="few">Премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="other">Премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотека није успело</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Брисање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="few">Брисање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке није успело</item>
+ <item quantity="other">Брисање <xliff:g id="COUNT_1">%1$d</xliff:g> датотека није успело</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Додирните да бисте приказали детаље"</string>
<string name="close" msgid="3043722427445528732">"Затвори"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Следеће датотеке нису копиране: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Следеће датотеке нису премештене: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ове датотеке су конвертоване у други формат: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Копирали сте <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку у привремену меморију.</item>
@@ -110,4 +120,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
<string name="allow" msgid="7225948811296386551">"Дозволи"</string>
<string name="deny" msgid="2081879885755434506">"Одбиј"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sv/config.xml b/packages/DocumentsUI/res/values-sv/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-sv/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index dfc42a36c970..656ef8f04db0 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Dela via"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kopierar filer"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Filer flyttas"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> återstår"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Kopierar <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
<string name="allow" msgid="7225948811296386551">"Tillåt"</string>
<string name="deny" msgid="2081879885755434506">"Neka"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sw/config.xml b/packages/DocumentsUI/res/values-sw/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-sw/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index cbdb44ccb868..c50920b87b2a 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Shiriki kupitia"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Inanakili faili"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Inahamisha faili"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Inafuta faili"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Zimesalia <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Inanakili faili <xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Baadhi ya faili zimebadilishwa muundo"</string>
<string name="allow" msgid="7225948811296386551">"Ruhusu"</string>
<string name="deny" msgid="2081879885755434506">"Kataza"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Ungependa kufuta faili?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Una uhakika kuwa ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+ <item quantity="one">Una uhakika kuwa ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/config.xml b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
index 843a8aad4051..8d9526d62dff 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/config.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,9 +12,8 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+<resources>
+ <bool name="always_show_summary">true</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
index c9dee8d2c174..fa11244141f7 100644
--- a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
@@ -15,8 +15,6 @@
-->
<resources>
- <bool name="always_show_summary">true</bool>
-
<dimen name="list_item_height">64dp</dimen>
<dimen name="list_item_padding">24dp</dimen>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/config.xml b/packages/DocumentsUI/res/values-ta-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ta-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 5aaf2b71ca5e..08dc5ba81e42 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"வழிகளை மறை"</string>
<string name="save_error" msgid="6167009778003223664">"ஆவணத்தைச் சேமிப்பதில் தோல்வி"</string>
<string name="create_error" msgid="3735649141335444215">"கோப்புறையை உருவாக்குவதில் தோல்வி"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"தற்போது உள்ளடக்கத்தை ஏற்ற முடியாது"</string>
<string name="root_recent" msgid="4470053704320518133">"சமீபத்தியவை"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> இலவசம்"</string>
<string name="root_type_service" msgid="2178854894416775409">"சேமிப்பிட சாதனங்கள்"</string>
@@ -63,12 +62,12 @@
<string name="root_type_apps" msgid="8838065367985945189">"மேலும் பயன்பாடுகள்"</string>
<string name="empty" msgid="7858882803708117596">"எதுவும் இல்லை"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s இல் பொருந்தும் முடிவு இல்லை"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"கோப்பைத் திறக்க முடியாது"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"சில ஆவணங்களை நீக்க முடியவில்லை"</string>
<string name="share_via" msgid="8966594246261344259">"இதன் வழியாகப் பகிர்"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"கோப்புகளை நகலெடுத்தல்"</string>
<string name="move_notification_title" msgid="6193835179777284805">"கோப்புகளை நகர்த்துதல்"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"கோப்புகளை நீக்குகிறது"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> மீதமுள்ளது"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகலெடுக்கிறது.</item>
@@ -86,15 +85,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"நகல் தயாராகிறது…"</string>
<string name="move_preparing" msgid="2772219441375531410">"நகர்த்துவதற்குத் தயார்படுத்துகிறது…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"நீக்கத் தயாராகிறது…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகலெடுக்க முடியவில்லை</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நகலெடுக்க முடியவில்லை</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகர்த்த முடியவில்லை</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நகர்த்த முடியவில்லை</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்க முடியவில்லை</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்க முடியவில்லை</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"விவரங்களைப் பார்க்க, தட்டவும்"</string>
<string name="close" msgid="3043722427445528732">"மூடு"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"பின்வரும் கோப்புகள் நகலெடுக்கப்படவில்லை: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"பின்வரும் கோப்புகள் நகர்த்தப்படவில்லை: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"இந்தக் கோப்புகள் வேறொரு வடிவத்திற்கு மாற்றப்பட்டன: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">கிளிப்போர்டிற்கு <xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகள் நகலெடுக்கப்பட்டன.</item>
@@ -106,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"சில கோப்புகள் மாற்றப்பட்டன"</string>
<string name="allow" msgid="7225948811296386551">"அனுமதி"</string>
<string name="deny" msgid="2081879885755434506">"நிராகரி"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"கோப்புகளை நீக்கவா?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நிச்சயமாக நீக்கவா?</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நிச்சயமாக நீக்கவா?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/config.xml b/packages/DocumentsUI/res/values-te-rIN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-te-rIN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 07a7e6df973f..ad8c840ce6e5 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"దీని ద్వారా భాగస్వామ్యం చేయండి"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"ఫైల్‌లు కాపీ అవుతున్నాయి"</string>
<string name="move_notification_title" msgid="6193835179777284805">"ఫైల్‌లను తరలిస్తోంది"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"ఫైల్‌లను తొలగిస్తోంది"</string>
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> మిగిలి ఉంది"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్‌లను కాపీ చేస్తోంది.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"కొన్ని పైల్‌లు మార్చబడ్డాయి"</string>
<string name="allow" msgid="7225948811296386551">"అనుమతించండి"</string>
<string name="deny" msgid="2081879885755434506">"తిరస్కరించండి"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"ఫైల్‌లను తొలగించాలా?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">మీరు ఖచ్చితంగా <xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్‌లను తొలగించాలనుకుంటున్నారా?</item>
+ <item quantity="one">మీరు ఖచ్చితంగా <xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్‌ను తొలగించాలనుకుంటున్నారా?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-th/config.xml b/packages/DocumentsUI/res/values-th/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-th/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index f24757110bfa..ad4c5b9008c8 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"ซ่อนราก"</string>
<string name="save_error" msgid="6167009778003223664">"การบันทึกเอกสารล้มเหลว"</string>
<string name="create_error" msgid="3735649141335444215">"การสร้างโฟลเดอร์ล้มเหลว"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"โหลดเนื้อหาไม่ได้ในขณะนี้"</string>
<string name="root_recent" msgid="4470053704320518133">"ล่าสุด"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ว่าง <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"บริการที่เก็บข้อมูล"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"แอปเพิ่มเติม"</string>
<string name="empty" msgid="7858882803708117596">"ไม่มีรายการ"</string>
<string name="no_results" msgid="6622510343880730446">"ไม่พบข้อมูลที่ตรงกันใน %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"เปิดไฟล์ไม่ได้"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"ไม่สามารถลบเอกสารบางรายการ"</string>
<string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"กำลังคัดลอกไฟล์"</string>
<string name="move_notification_title" msgid="6193835179777284805">"กำลังย้ายไฟล์"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"เหลือ <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">กำลังคัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"กำลังเตรียมการคัดลอก…"</string>
<string name="move_preparing" msgid="2772219441375531410">"กำลังเตรียมการย้าย…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"กำลังเตรียมลบ…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">คัดลอกไม่ได้ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+ <item quantity="one">คัดลอกไม่ได้ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">ย้ายไม่ได้ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+ <item quantity="one">ย้ายไม่ได้ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">ลบไม่ได้ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+ <item quantity="one">ลบไม่ได้ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"แตะเพื่อดูรายละเอียด"</string>
<string name="close" msgid="3043722427445528732">"ปิด"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"ไม่ได้คัดลอกไฟล์เหล่านี้: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"ไม่ได้ย้ายไฟล์เหล่านี้: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ไฟล์ต่อไปนี้แปลงเป็นอีกรูปแบบหนึ่งแล้ว: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">คัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ไปยังคลิปบอร์ดแล้ว</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
<string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
<string name="deny" msgid="2081879885755434506">"ปฏิเสธ"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-tl/config.xml b/packages/DocumentsUI/res/values-tl/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-tl/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index bca1f84d0217..8c8b018b1bd2 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Itago ang mga root"</string>
<string name="save_error" msgid="6167009778003223664">"Hindi na-save ang dokumento"</string>
<string name="create_error" msgid="3735649141335444215">"Hindi nagawa ang folder"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Hindi ma-load ang content sa ngayon"</string>
<string name="root_recent" msgid="4470053704320518133">"Kamakailan"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ang libre"</string>
<string name="root_type_service" msgid="2178854894416775409">"Mga serbisyo ng storage"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Higit pang apps"</string>
<string name="empty" msgid="7858882803708117596">"Walang mga item"</string>
<string name="no_results" msgid="6622510343880730446">"Walang mga katugma sa %1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Hindi mabuksan ang file"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Hindi matanggal ang ilang dokumento"</string>
<string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Kinokopya ang mga file"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Inililipat ang mga file"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> na lang ang natitira"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Kumokopya ng <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Naghahanda para sa pagkopya…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Naghahanda para sa paglilipat…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Naghahanda para sa pag-delete…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+ <item quantity="other">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Hindi mailipat ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+ <item quantity="other">Hindi mailipat ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Hindi ma-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+ <item quantity="other">Hindi ma-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"I-tap upang tingnan ang mga detalye"</string>
<string name="close" msgid="3043722427445528732">"Isara"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Hindi nakopya ang mga file na ito: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Hindi nailipat ang mga file na ito: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Na-convert ang mga file na ito sa ibang format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Nakopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> file sa clipboard.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
<string name="allow" msgid="7225948811296386551">"Payagan"</string>
<string name="deny" msgid="2081879885755434506">"Tanggihan"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-tr/config.xml b/packages/DocumentsUI/res/values-tr/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-tr/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 7ee02180b2da..602f8d7978ea 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Kökleri sakla"</string>
<string name="save_error" msgid="6167009778003223664">"Doküman kaydedilemedi"</string>
<string name="create_error" msgid="3735649141335444215">"Klasör oluşturulamadı"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"İçerik şu anda yüklenemiyor"</string>
<string name="root_recent" msgid="4470053704320518133">"En son"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> boş"</string>
<string name="root_type_service" msgid="2178854894416775409">"Depolama hizmetleri"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Diğer uygulamalar"</string>
<string name="empty" msgid="7858882803708117596">"Öğe yok"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s içinde eşleşme bulunamadı"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Dosya açılamıyor"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Bazı dokümanlar silinemiyor"</string>
<string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Dosyalar kopyalanıyor"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Dosyalar taşınıyor"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> kaldı"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanıyor.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Kopyalanmak için hazırlanıyor…"</string>
<string name="move_preparing" msgid="2772219441375531410">"Taşıma için hazırlanıyor…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Silmek için hazırlanıyor…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanamadı</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya kopyalanamadı</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya taşınamadı</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya taşınamadı</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinemedi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinemedi</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Ayrıntıları görmek için hafifçe dokunun"</string>
<string name="close" msgid="3043722427445528732">"Kapat"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Şu dosyalar kopyalanamadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Şu dosyalar taşınamadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Bu dosyalar başka bir biçime dönüştürüldü: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya panoya kopyalandı.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
<string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
<string name="deny" msgid="2081879885755434506">"Reddet"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-uk/config.xml b/packages/DocumentsUI/res/values-uk/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-uk/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 5f2b99c8420b..15ae4249e780 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"Надіслати через"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Копіювання файлів"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Переміщення файлів"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"Залишилося <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
@@ -125,4 +127,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
<string name="allow" msgid="7225948811296386551">"Дозвол."</string>
<string name="deny" msgid="2081879885755434506">"Забор."</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/config.xml b/packages/DocumentsUI/res/values-ur-rPK/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-ur-rPK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 1ef29267d88d..272677f036d7 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"روٹس کو چھپائیں"</string>
<string name="save_error" msgid="6167009778003223664">"دستاویز کو محفوظ کرنے میں ناکام ہو گیا۔"</string>
<string name="create_error" msgid="3735649141335444215">"فولڈر بنانے میں ناکام ہو گیا"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"اس وقت مواد لوڈ نہیں ہو سکتا"</string>
<string name="root_recent" msgid="4470053704320518133">"حالیہ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> خالی"</string>
<string name="root_type_service" msgid="2178854894416775409">"اسٹوریج سروسز"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"مزید ایپس"</string>
<string name="empty" msgid="7858882803708117596">"کوئی آئٹمز نہيں ہیں"</string>
<string name="no_results" msgid="6622510343880730446">"‏%1$s میں کوئی مماثل نہیں"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"فائل نہیں کھل سکتی"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"کچھ دستاویزات کو حذف کرنے سے قاصر"</string>
<string name="share_via" msgid="8966594246261344259">"اشتراک کریں بذریعہ"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"فائلیں کاپی ہو رہی ہیں"</string>
<string name="move_notification_title" msgid="6193835179777284805">"فائلیں منتقل ہو رہی ہیں"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی ہے"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی کی جا رہی ہیں۔</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"کاپی کیلئے تیار ہو رہا ہے…"</string>
<string name="move_preparing" msgid="2772219441375531410">"منتقلی کیلئے تیار ہو رہی ہیں…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"حذف کرنے کیلئے تیاری ہو رہی ہے…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی نہیں ہو سکیں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل کاپی نہیں ہو سکی</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں منتقل نہیں ہو سکیں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل منتقل نہیں ہو سکی</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف نہیں ہو سکیں</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف نہیں ہو سکی</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"تفصیلات دیکھنے کیلئے تھپتھپائیں"</string>
<string name="close" msgid="3043722427445528732">"بند کریں"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"یہ فائلیں کاپی نہیں ہوئیں: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"یہ فائلیں منتقل نہیں ہوئیں: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"ان فائلوں کو ایک دوسرے فارمیٹ میں تبدیل کیا گیا تھا: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلز کلپ بورڈ پر کاپی کی گئیں۔</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
<string name="allow" msgid="7225948811296386551">"اجازت دیں"</string>
<string name="deny" msgid="2081879885755434506">"مسترد کریں"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/config.xml b/packages/DocumentsUI/res/values-uz-rUZ/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-uz-rUZ/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index b8111252a908..0a599c5dd455 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -31,7 +31,7 @@
<string name="menu_save" msgid="2394743337684426338">"Saqlash"</string>
<string name="menu_share" msgid="3075149983979628146">"Ulashish"</string>
<string name="menu_delete" msgid="8138799623850614177">"O‘chirish"</string>
- <string name="menu_select_all" msgid="8323579667348729928">"Barchasini belgilash"</string>
+ <string name="menu_select_all" msgid="8323579667348729928">"Hammasini belgilash"</string>
<string name="menu_copy" msgid="3612326052677229148">"Nusxalash…"</string>
<string name="menu_move" msgid="1828090633118079817">"Ko‘chirib o‘tkazish…"</string>
<string name="menu_new_window" msgid="1226032889278727538">"Yangi oyna"</string>
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Asosiy jildlarni yashirish"</string>
<string name="save_error" msgid="6167009778003223664">"Hujjat saqlanmadi"</string>
<string name="create_error" msgid="3735649141335444215">"Jild yaratilmadi"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Ayni paytda kontentni yuklab bo‘lmayapti"</string>
<string name="root_recent" msgid="4470053704320518133">"Yaqinda"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> bo‘sh"</string>
<string name="root_type_service" msgid="2178854894416775409">"Xotira xizmatlari"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Ko‘proq dasturlar"</string>
<string name="empty" msgid="7858882803708117596">"Hech narsa yo‘q"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s jildidan topilmadi"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Fayl ochilmadi"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ba’zi hujjatlar o‘chirilmadi"</string>
<string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Fayllar nusxalanmoqda"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Ko‘chirib o‘tkazilmoqda"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qoldi"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl nusxalanmoqda</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Nuxsa olishga tayyorgarlik..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Ko‘chirishga tayyorgarlik…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"O‘chirishga tayyorlanmoqda…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan nusxa olib bo‘lmadi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayldan nusxa olib bo‘lmadi</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta faylni ko‘chirib bo‘lmadi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta faylni ko‘chirib bo‘lmadi</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta faylni o‘chirib bo‘lmadi</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta faylni o‘chirib bo‘lmadi</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Batafsil ma’lumot olish uchun bosing"</string>
<string name="close" msgid="3043722427445528732">"Yopish"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Quyidagi fayllardan nusxa olinmadi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Quyidagi fayllar ko‘chirilmadi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Ushbu fayllar boshqa formatga o‘girildi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan vaqtinchalik xotiraga nusxa olindi.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
<string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
<string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-vi/config.xml b/packages/DocumentsUI/res/values-vi/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-vi/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 66a5b7310270..0abb3890b19a 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -67,6 +67,7 @@
<string name="share_via" msgid="8966594246261344259">"Chia sẻ qua"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Đang sao chép tệp"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Đang di chuyển tệp"</string>
+ <string name="delete_notification_title" msgid="3329403967712437496">"Đang xóa tệp"</string>
<string name="copy_remaining" msgid="6283790937387975095">"Còn <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">Đang sao chép <xliff:g id="COUNT_1">%1$d</xliff:g> tệp.</item>
@@ -111,4 +112,9 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Đã chuyển đổi một số tệp"</string>
<string name="allow" msgid="7225948811296386551">"Cho phép"</string>
<string name="deny" msgid="2081879885755434506">"Từ chối"</string>
+ <string name="delete_confirmation_title" msgid="1958369150786342998">"Xóa tệp?"</string>
+ <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+ <item quantity="other">Bạn có chắc chắn muốn xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp không?</item>
+ <item quantity="one">Bạn có chắc chắn muốn xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp không?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/config.xml b/packages/DocumentsUI/res/values-zh-rCN/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-zh-rCN/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 0ad4e3bd67cc..83a9204256e0 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"隐藏根目录"</string>
<string name="save_error" msgid="6167009778003223664">"无法保存文档"</string>
<string name="create_error" msgid="3735649141335444215">"无法创建文件夹"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"暂时无法加载内容"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空间:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"存储服务"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"更多应用"</string>
<string name="empty" msgid="7858882803708117596">"无任何文件"</string>
<string name="no_results" msgid="6622510343880730446">"%1$s中没有任何相符项"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"无法打开文件"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"无法删除部分文档"</string>
<string name="share_via" msgid="8966594246261344259">"分享方式"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"正在复制文件"</string>
<string name="move_notification_title" msgid="6193835179777284805">"正在移动文件"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"剩余时间:<xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"正在准备复制…"</string>
<string name="move_preparing" msgid="2772219441375531410">"正在准备移动…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"正在准备删除…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="other">无法复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+ <item quantity="one">无法复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="other">无法移动 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+ <item quantity="one">无法移动 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="other">无法删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件</item>
+ <item quantity="one">无法删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件</item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"点按即可查看详情"</string>
<string name="close" msgid="3043722427445528732">"关闭"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"无法复制以下文件:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"无法移动以下文件:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"下列文件已转换成其他格式:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">已将 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件复制到剪贴板。</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
<string name="allow" msgid="7225948811296386551">"允许"</string>
<string name="deny" msgid="2081879885755434506">"拒绝"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/config.xml b/packages/DocumentsUI/res/values-zh-rHK/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-zh-rHK/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 44ac652f6a21..532f976f0766 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"正在複製檔案"</string>
<string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
@@ -98,8 +100,8 @@
</plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"輕按即可查看詳細資訊"</string>
<string name="close" msgid="3043722427445528732">"關閉"</string>
- <string name="copy_failure_alert_content" msgid="4563147454522476183">"未複製下列檔案:<xliff:g id="LIST">%1$s</xliff:g>"</string>
- <string name="move_failure_alert_content" msgid="2635075788682922861">"未移動下列檔案:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"以下檔案未能複製:<xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"以下檔案未能移動:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"這些檔案已轉換成其他格式:<xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="other">已複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案到剪貼簿。</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
<string name="deny" msgid="2081879885755434506">"拒絕"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/config.xml b/packages/DocumentsUI/res/values-zh-rTW/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-zh-rTW/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index ad77ad453078..e8b48ccc594e 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -67,6 +67,8 @@
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"複製檔案"</string>
<string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
@@ -111,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
<string name="allow" msgid="7225948811296386551">"允許"</string>
<string name="deny" msgid="2081879885755434506">"拒絕"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zu/config.xml b/packages/DocumentsUI/res/values-zu/config.xml
deleted file mode 100644
index 843a8aad4051..000000000000
--- a/packages/DocumentsUI/res/values-zu/config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index f450209b1e0e..b22f99455897 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -53,8 +53,7 @@
<string name="drawer_close" msgid="7602734368552123318">"Fihla izimpande"</string>
<string name="save_error" msgid="6167009778003223664">"Yehlulekile ukulondoloza idokhumenti"</string>
<string name="create_error" msgid="3735649141335444215">"Yehlulekile ukudala ifolda"</string>
- <!-- no translation found for query_error (5999895349602476581) -->
- <skip />
+ <string name="query_error" msgid="5999895349602476581">"Ayikwazanga ukulayisha okuqukethwe okwamanje"</string>
<string name="root_recent" msgid="4470053704320518133">"Okwakamuva"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> okhululekile"</string>
<string name="root_type_service" msgid="2178854894416775409">"Amasevisi wesitoreji"</string>
@@ -63,12 +62,13 @@
<string name="root_type_apps" msgid="8838065367985945189">"Izinhlelo zokusebenza eziningi"</string>
<string name="empty" msgid="7858882803708117596">"Azikho izinto"</string>
<string name="no_results" msgid="6622510343880730446">"Akukho okufanayo ku-%1$s"</string>
- <!-- no translation found for toast_no_application (4632640357724698144) -->
- <skip />
+ <string name="toast_no_application" msgid="4632640357724698144">"Ayikwazanga ukuvula ifayela"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Ayikwazi ukususa amanye amadokhumenti"</string>
<string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
<string name="copy_notification_title" msgid="6374299806748219777">"Ikopisha amafayela"</string>
<string name="move_notification_title" msgid="6193835179777284805">"Ihambisa amafayela"</string>
+ <!-- no translation found for delete_notification_title (3329403967712437496) -->
+ <skip />
<string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> okusele"</string>
<plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
<item quantity="one">Ikopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
@@ -86,15 +86,22 @@
<string name="copy_preparing" msgid="3896202461003039386">"Ilungiselela ukukopisha..."</string>
<string name="move_preparing" msgid="2772219441375531410">"Ilungiselela ukuhambisa…"</string>
<string name="delete_preparing" msgid="5655813182533491992">"Ilungiselela ukususa…"</string>
- <!-- no translation found for copy_error_notification_title (7160447124922897689) -->
- <!-- no translation found for move_error_notification_title (2710901971014783012) -->
- <!-- no translation found for delete_error_notification_title (7228393157786591199) -->
+ <plurals name="copy_error_notification_title" formatted="false" msgid="7160447124922897689">
+ <item quantity="one">Ayikwazanga ukukopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Ayikwazanga ukukopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2710901971014783012">
+ <item quantity="one">Ayikwazanga ukuhambisa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Ayikwazanga ukuhambisa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
+ <plurals name="delete_error_notification_title" formatted="false" msgid="7228393157786591199">
+ <item quantity="one">Ayikwazanga ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Ayikwazanga ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
<string name="notification_touch_for_details" msgid="6268189413228855582">"Thepha ukuze ubuke imininingwane"</string>
<string name="close" msgid="3043722427445528732">"Vala"</string>
- <!-- no translation found for copy_failure_alert_content (4563147454522476183) -->
- <skip />
- <!-- no translation found for move_failure_alert_content (2635075788682922861) -->
- <skip />
+ <string name="copy_failure_alert_content" msgid="4563147454522476183">"Lawo mafayela awakopishwanga: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="2635075788682922861">"Lawa mafayela awazange ahanjiswe: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="copy_converted_warning_content" msgid="5753861488218674361">"Lawo mafayela aguqulelwe kwenye ifomethi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
<item quantity="one">Kukopishwe amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g> kubhodi lokunamathisela.</item>
@@ -106,4 +113,7 @@
<string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
<string name="allow" msgid="7225948811296386551">"Vumela"</string>
<string name="deny" msgid="2081879885755434506">"Yala"</string>
+ <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
+ <skip />
+ <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index c868d340e901..3785adf7f878 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -21,18 +21,18 @@
else that needs to manually declare a background matching the "default"
app background (e.g. the drawer overlay). -->
<color name="window_background">#fff1f1f1</color>
+ <color name="drawer_background">#fff1f1f1</color>
+ <color name="directory_background">#fff7f7f7</color>
+ <color name="item_doc_background">#fffafafa</color>
+ <color name="item_doc_background_selected">#ffe0f2f1</color>
+ <color name="menu_search_background">#ff676f74</color>
<color name="primary_dark">@*android:color/primary_dark_material_dark</color>
<color name="primary">@*android:color/material_blue_grey_900</color>
<color name="accent">@*android:color/accent_material_light</color>
+ <color name="accent_dark">@*android:color/accent_material_dark</color>
<color name="action_mode">@color/material_grey_400</color>
<color name="band_select_background">#88ffffff</color>
<color name="band_select_border">#44000000</color>
-
- <color name="item_doc_background">#fffafafa</color>
- <color name="item_doc_background_selected">#ffe0f2f1</color>
-
- <color name="menu_search_background">#ff676f74</color>
-
</resources>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index e8d8c8ebfda1..8a7654071a3e 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -19,5 +19,7 @@
<bool name="config_defaultAdvancedDevices">false</bool>
<!-- Intentionally unset. Vendors should set this in an overlay. -->
- <string name="trusted_quick_viewer_package"></string>
+ <string name="trusted_quick_viewer_package" translatable="false"></string>
+ <bool name="list_divider_inset_left">true</bool>
+ <bool name="always_show_summary">false</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index 5adb165667c4..9fc8a73874da 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -17,37 +17,24 @@
<resources>
<dimen name="grid_container_padding">10dp</dimen>
<dimen name="list_container_padding">0dp</dimen>
-
<dimen name="icon_size">40dp</dimen>
<dimen name="root_icon_size">24dp</dimen>
<dimen name="root_icon_margin">0dp</dimen>
<dimen name="check_icon_size">30dp</dimen>
-
<dimen name="list_item_thumbnail_size">40dp</dimen>
<dimen name="grid_item_icon_size">30dp</dimen>
-
<dimen name="progress_bar_height">4dp</dimen>
-
<dimen name="grid_width">152dp</dimen>
<dimen name="grid_height">176dp</dimen>
-
<dimen name="grid_item_width">152dp</dimen>
<dimen name="grid_item_height">176dp</dimen>
<dimen name="grid_item_margin">4dp</dimen>
-
<dimen name="grid_padding_horiz">4dp</dimen>
<dimen name="grid_padding_vert">4dp</dimen>
-
<dimen name="list_item_height">72dp</dimen>
<dimen name="list_item_padding">16dp</dimen>
-
<dimen name="list_divider_inset">72dp</dimen>
- <bool name="list_divider_inset_left">true</bool>
-
- <bool name="always_show_summary">false</bool>
-
<dimen name="dir_elevation">8dp</dimen>
-
<dimen name="drag_shadow_size">120dp</dimen>
-
+ <dimen name="grid_item_elevation">2dp</dimen>
</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index b97918e7b9d1..3dc111aa9703 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -134,6 +134,8 @@
<string name="copy_notification_title">Copying files</string>
<!-- Title of the move notification [CHAR LIMIT=24] -->
<string name="move_notification_title">Moving files</string>
+ <!-- Title of the move notification [CHAR LIMIT=24] -->
+ <string name="delete_notification_title">Deleting files</string>
<!-- Text shown on the copy notification to indicate remaining time, in minutes [CHAR LIMIT=24] -->
<string name="copy_remaining"><xliff:g id="duration" example="3 minutes">%s</xliff:g> left</string>
<!-- Toast shown when a file copy is kicked off -->
@@ -206,4 +208,11 @@
<string name="allow">Allow</string>
<!-- Text in the button asking user to deny access to a given directory. -->
<string name="deny">Deny</string>
+ <!-- Dialog title shown to users when asking if they want to delete files (a confirmation). -->
+ <string name="delete_confirmation_title">Delete files?</string>
+ <!-- Dialog text shown to users when asking if they want to delete files (a confirmation). -->
+ <plurals name="delete_confirmation_message">
+ <item quantity="one">Are you sure you want to delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
+ <item quantity="other">Are you sure you want to delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index f4dfd73690ca..21bdfd9ec53c 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -29,6 +29,7 @@
<item name="android:colorPrimary">@color/primary</item>
<item name="android:colorAccent">@color/accent</item>
<item name="colorActionMode">@color/action_mode</item>
+ <item name="android:queryBackground">@color/menu_search_background</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 3c21a214b19b..46cbbdf81c4e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -22,17 +22,15 @@ import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_ENTER;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_LEAVE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkState;
import android.app.Activity;
import android.app.Fragment;
+import android.app.FragmentManager;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
-import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -42,17 +40,18 @@ import android.support.annotation.CallSuper;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Spinner;
-import com.android.documentsui.SearchManager.SearchManagerListener;
+import com.android.documentsui.SearchViewManager.SearchManagerListener;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.DirectoryFragment;
+import com.android.documentsui.dirlist.Model;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
import java.io.FileNotFoundException;
import java.util.ArrayList;
@@ -63,14 +62,9 @@ import java.util.concurrent.Executor;
public abstract class BaseActivity extends Activity
implements SearchManagerListener, NavigationView.Environment {
- static final String EXTRA_STATE = "state";
-
- // See comments where this const is referenced for details.
- private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
-
State mState;
RootsCache mRoots;
- SearchManager mSearchManager;
+ SearchViewManager mSearchManager;
DrawerController mDrawer;
NavigationView mNavigator;
@@ -79,11 +73,9 @@ public abstract class BaseActivity extends Activity
@LayoutRes
private int mLayoutId;
- // Track the time we opened the drawer in response to back being pressed.
- // We use the time gap to figure out whether to close app or reopen the drawer.
- private long mDrawerLastFiddled;
+ private boolean mNavDrawerHasFocus;
- public abstract void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings);
+ public abstract void onDocumentPicked(DocumentInfo doc, Model model);
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
abstract void onTaskFinished(Uri... uris);
@@ -118,7 +110,7 @@ public abstract class BaseActivity extends Activity
}
});
- mSearchManager = new SearchManager(this);
+ mSearchManager = new SearchViewManager(this, icicle);
DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
setActionBar(toolbar);
@@ -138,6 +130,7 @@ public abstract class BaseActivity extends Activity
boolean showMenu = super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.activity, menu);
+ mNavigator.update();
mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar));
return showMenu;
@@ -185,7 +178,7 @@ public abstract class BaseActivity extends Activity
private State getState(@Nullable Bundle icicle) {
if (icicle != null) {
- State state = icicle.<State>getParcelable(EXTRA_STATE);
+ State state = icicle.<State>getParcelable(Shared.EXTRA_STATE);
if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state);
return state;
}
@@ -216,11 +209,16 @@ public abstract class BaseActivity extends Activity
return state;
}
- void onStackRestored(boolean restored, boolean external) {}
+ public void setRootsDrawerOpen(boolean open) {
+ mNavigator.revealRootsDrawer(open);
+ }
void onRootPicked(RootInfo root) {
- // Skip refreshing if root didn't change
- if(root.equals(getCurrentRoot())) {
+ // Clicking on the current root removes search
+ mSearchManager.cancelSearch();
+
+ // Skip refreshing if root nor directory didn't change
+ if (root.equals(getCurrentRoot()) && mState.stack.size() == 1) {
return;
}
@@ -228,7 +226,6 @@ public abstract class BaseActivity extends Activity
// Clear entire backstack and start in new root
mState.onRootChanged(root);
- mSearchManager.update(root);
// Recents is always in memory, so we just load it directly.
// Otherwise we delegate loading data from disk to a task
@@ -279,7 +276,7 @@ public abstract class BaseActivity extends Activity
if (dir != null) {
dir.pasteFromClipboard();
}
- return true;
+ return true;
case R.id.menu_advanced:
setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
@@ -309,6 +306,12 @@ public abstract class BaseActivity extends Activity
CreateDirectoryFragment.show(getFragmentManager());
}
+ void onDirectoryCreated(DocumentInfo doc) {
+ // By default we do nothing, just let the new directory appear.
+ // DocumentsActivity auto-opens directories after creating them
+ // As that is more attuned to the "picker" use cases it supports.
+ }
+
/**
* Returns true if a directory can be created in the current location.
* @return
@@ -323,13 +326,9 @@ public abstract class BaseActivity extends Activity
&& !root.isDownloads();
}
- void onDirectoryCreated(DocumentInfo doc) {
- checkArgument(doc.isDirectory());
- openContainerDocument(doc);
- }
-
void openContainerDocument(DocumentInfo doc) {
- checkArgument(doc.isContainer());
+ assert(doc.isContainer());
+
mState.pushDocument(doc);
// Show an opening animation only if pressing "back" would get us back to the
// previous directory. Especially after opening a root document, pressing
@@ -359,24 +358,30 @@ public abstract class BaseActivity extends Activity
invalidateOptionsMenu();
}
+ final void loadRoot(final Uri uri) {
+ new LoadRootTask(this, uri).executeOnExecutor(
+ ProviderExecutor.forAuthority(uri.getAuthority()));
+ }
+
/**
* Called when search results changed.
* Refreshes the content of the directory. It doesn't refresh elements on the action bar.
* e.g. The current directory name displayed on the action bar won't get updated.
*/
@Override
- public void onSearchChanged() {
- refreshDirectory(ANIM_NONE);
+ public void onSearchChanged(@Nullable String query) {
+ // We should not get here if root is not searchable
+ assert(canSearchRoot());
+
+ reloadSearch(query);
}
- /**
- * Called when search query changed.
- * Updates the state object.
- * @param query - New query
- */
- @Override
- public void onSearchQueryChanged(String query) {
- mState.currentSearch = query;
+ private void reloadSearch(String query) {
+ FragmentManager fm = getFragmentManager();
+ RootInfo root = getCurrentRoot();
+ DocumentInfo cwd = getCurrentDirectory();
+
+ DirectoryFragment.reloadSearch(fm, root, cwd, query);
}
final List<String> getExcludedAuthorities() {
@@ -451,15 +456,14 @@ public abstract class BaseActivity extends Activity
DirectoryFragment dir = getDirectoryFragment();
if (dir != null) {
dir.onSortOrderChanged();
- };
+ }
}
/**
* Set mode based on explicit user action.
*/
void setViewMode(@ViewMode int mode) {
- checkState(mState.stack.root != null);
- LocalPreferences.setViewMode(this, mState.stack.root, mode);
+ LocalPreferences.setViewMode(this, getCurrentRoot(), mode);
mState.derivedMode = mode;
// view icon needs to be updated, but we *could* do it
@@ -469,7 +473,7 @@ public abstract class BaseActivity extends Activity
DirectoryFragment dir = getDirectoryFragment();
if (dir != null) {
dir.onViewModeChanged();
- };
+ }
}
public void setPending(boolean pending) {
@@ -482,7 +486,8 @@ public abstract class BaseActivity extends Activity
@Override
protected void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
- state.putParcelable(EXTRA_STATE, mState);
+ state.putParcelable(Shared.EXTRA_STATE, mState);
+ mSearchManager.onSaveInstanceState(state);
}
@Override
@@ -534,37 +539,18 @@ public abstract class BaseActivity extends Activity
return;
}
- int size = mState.stack.size();
-
- // Do some "do what a I want" drawer fiddling, but don't
- // do it if user already hit back recently and we recently
- // did some fiddling.
- if ((System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
- // Close drawer if it is open.
- if (mDrawer.isOpen()) {
- mDrawer.setOpen(false);
- mDrawerLastFiddled = System.currentTimeMillis();
- return;
- }
-
- // Open the Close drawer if it is closed and we're at the top of a root.
- if (size == 1) {
- mDrawer.setOpen(true);
- // Remember so we don't just close it again if back is pressed again.
- mDrawerLastFiddled = System.currentTimeMillis();
- return;
- }
- }
-
- if (size > 1) {
- mState.stack.pop();
- refreshCurrentRootAndDirectory(ANIM_LEAVE);
+ if (onBeforePopDir() || popDir()) {
return;
}
super.onBackPressed();
}
+ boolean onBeforePopDir() {
+ // Files app overrides this with some fancy logic.
+ return false;
+ }
+
public void onStackPicked(DocumentStack stack) {
try {
// Update the restored stack to ensure we have freshest data
@@ -577,6 +563,58 @@ public abstract class BaseActivity extends Activity
}
}
+ /**
+ * Declare a global key handler to route key events when there isn't a specific focus view. This
+ * covers the scenario where a user opens DocumentsUI and just starts typing.
+ *
+ * @param keyCode
+ * @param event
+ * @return
+ */
+ @CallSuper
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (Events.isNavigationKeyCode(keyCode)) {
+ // Forward all unclaimed navigation keystrokes to the DirectoryFragment. This causes any
+ // stray navigation keystrokes focus the content pane, which is probably what the user
+ // is trying to do.
+ DirectoryFragment df = DirectoryFragment.get(getFragmentManager());
+ if (df != null) {
+ df.requestFocus();
+ return true;
+ }
+ } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ // Tab toggles focus on the navigation drawer.
+ toggleNavDrawerFocus();
+ return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DEL) {
+ popDir();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Toggles focus between the navigation drawer and the directory listing. If the drawer isn't
+ * locked, open/close it as appropriate.
+ */
+ void toggleNavDrawerFocus() {
+ if (mNavDrawerHasFocus) {
+ mDrawer.setOpen(false);
+ DirectoryFragment df = DirectoryFragment.get(getFragmentManager());
+ if (df != null) {
+ df.requestFocus();
+ }
+ } else {
+ mDrawer.setOpen(true);
+ RootsFragment rf = RootsFragment.get(getFragmentManager());
+ if (rf != null) {
+ rf.requestFocus();
+ }
+ }
+ mNavDrawerHasFocus = !mNavDrawerHasFocus;
+ }
+
DocumentInfo getRootDocumentBlocking(RootInfo root) {
try {
final Uri uri = DocumentsContract.buildDocumentUri(
@@ -588,6 +626,21 @@ public abstract class BaseActivity extends Activity
}
}
+ /**
+ * Pops the top entry off the directory stack, and returns the user to the previous directory.
+ * If the directory stack only contains one item, this method does nothing.
+ *
+ * @return Whether the stack was popped.
+ */
+ private boolean popDir() {
+ if (mState.stack.size() > 1) {
+ mState.stack.pop();
+ refreshCurrentRootAndDirectory(ANIM_LEAVE);
+ return true;
+ }
+ return false;
+ }
+
private static final class PickRootTask extends PairedTask<BaseActivity, Void, DocumentInfo> {
private RootInfo mRoot;
@@ -619,7 +672,8 @@ public abstract class BaseActivity extends Activity
@Override
protected RootInfo run(RootInfo... roots) {
- checkArgument(roots.length == 1);
+ assert(roots.length == 1);
+
final RootInfo currentRoot = roots[0];
final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking();
RootInfo homeRoot = null;
@@ -632,7 +686,7 @@ public abstract class BaseActivity extends Activity
return null;
}
}
- Preconditions.checkNotNull(homeRoot);
+ assert(homeRoot != null);
mHome = mOwner.getRootDocumentBlocking(homeRoot);
return homeRoot;
}
@@ -647,17 +701,4 @@ public abstract class BaseActivity extends Activity
}
}
}
-
- /**
- * Interface providing access to current view of documents
- * even when all documents are not homed to the same parent.
- */
- public interface SiblingProvider {
- /**
- * Returns the cursor for the selected document. The cursor can be used to retrieve
- * details about a document and its siblings.
- * @return
- */
- Cursor getCursor();
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index df036b93651c..40bd754b35b0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -36,6 +36,7 @@ import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
@@ -86,9 +87,9 @@ public class CreateDirectoryFragment extends DialogFragment {
@Override
public boolean onEditorAction(
TextView view, int actionId, @Nullable KeyEvent event) {
- if (event != null
+ if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER
- && event.hasNoModifiers()) {
+ && event.hasNoModifiers())) {
createDirectory(editText.getText().toString());
dialog.dismiss();
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index b0542b9eb5be..13b7b14600eb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -53,19 +53,22 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
private final RootInfo mRoot;
private final Uri mUri;
private final int mUserSortOrder;
+ private final boolean mSearchMode;
private DocumentInfo mDoc;
private CancellationSignal mSignal;
private DirectoryResult mResult;
+
public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
- int userSortOrder) {
+ int userSortOrder, boolean inSearchMode) {
super(context, ProviderExecutor.forAuthority(root.authority));
mType = type;
mRoot = root;
mUri = uri;
mUserSortOrder = userSortOrder;
mDoc = doc;
+ mSearchMode = inSearchMode;
}
@Override
@@ -83,7 +86,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
final DirectoryResult result = new DirectoryResult();
// Use default document when searching
- if (mType == DirectoryFragment.TYPE_SEARCH) {
+ if (mSearchMode) {
final Uri docUri = DocumentsContract.buildDocumentUri(
mRoot.authority, mRoot.documentId);
try {
@@ -106,7 +109,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
}
// Search always uses ranking from provider
- if (mType == DirectoryFragment.TYPE_SEARCH) {
+ if (mSearchMode) {
result.sortOrder = State.SORT_ORDER_UNKNOWN;
}
@@ -127,7 +130,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
- if (mType == DirectoryFragment.TYPE_SEARCH) {
+ if (mSearchMode) {
// Filter directories out of search results, for now
cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index b3c28469e71d..15bfc3b93087 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -28,7 +28,6 @@ import android.support.annotation.Nullable;
import android.util.Log;
import com.android.documentsui.model.DocumentInfo;
-import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
@@ -85,7 +84,7 @@ public final class DocumentClipper {
* This should be run from inside an AsyncTask.
*/
public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
- Preconditions.checkNotNull(clipData);
+ assert(clipData != null);
final List<DocumentInfo> srcDocs = new ArrayList<>();
int count = clipData.getItemCount();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 3485fe4446f5..12a41862e436 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -32,10 +32,8 @@ import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -49,6 +47,7 @@ import android.view.MenuItem;
import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.RecentsProvider.ResumeColumns;
import com.android.documentsui.dirlist.DirectoryFragment;
+import com.android.documentsui.dirlist.Model;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
@@ -74,8 +73,6 @@ public class DocumentsActivity extends BaseActivity {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- final Resources res = getResources();
-
if (mState.action == ACTION_CREATE) {
final String mimeType = getIntent().getType();
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
@@ -97,13 +94,27 @@ public class DocumentsActivity extends BaseActivity {
RootsFragment.show(getFragmentManager(), null);
}
- if (!mState.restored) {
- // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
- // talkback from reading aloud the default title, we clear it here.
- setTitle("");
- new RestoreStackTask(this).execute();
- } else {
+ if (mState.restored) {
refreshCurrentRootAndDirectory(ANIM_NONE);
+ } else {
+ // We set the activity title in AsyncTask.onPostExecute().
+ // To prevent talkback from reading aloud the default title, we clear it here.
+ setTitle("");
+
+ // As a matter of policy we don't load the last used stack for the copy
+ // destination picker (user is already in Files app).
+ // Concensus was that the experice was too confusing.
+ // In all other cases, where the user is visiting us from another app
+ // we restore the stack as last used from that app.
+ if (mState.action == ACTION_PICK_COPY_DESTINATION) {
+ if (DEBUG) Log.d(TAG, "Launching directly into Home directory.");
+ Uri homeUri = DocumentsContract.buildHomeUri();
+ new LoadRootTask(this, homeUri).executeOnExecutor(
+ ProviderExecutor.forAuthority(homeUri.getAuthority()));
+ } else {
+ if (DEBUG) Log.d(TAG, "Attempting to load last used stack for calling package.");
+ new LoadLastUsedStackTask(this).execute();
+ }
}
}
@@ -134,15 +145,18 @@ public class DocumentsActivity extends BaseActivity {
}
if (state.action == ACTION_PICK_COPY_DESTINATION) {
+ // Indicates that a copy operation (or move) includes a directory.
+ // Why? Directory creation isn't supported by some roots (like Downloads).
+ // This allows us to restrict available roots to just those with support.
state.directoryCopy = intent.getBooleanExtra(
Shared.EXTRA_DIRECTORY_COPY, false);
- state.transferMode = intent.getIntExtra(FileOperationService.EXTRA_OPERATION,
+ state.copyOperationSubType = intent.getIntExtra(
+ FileOperationService.EXTRA_OPERATION,
FileOperationService.OPERATION_COPY);
}
}
- @Override
- void onStackRestored(boolean restored, boolean external) {
+ private void onStackRestored(boolean restored, boolean external) {
// Show drawer when no stack restored, but only when requesting
// non-visual content. However, if we last used an external app,
// drawer is always shown.
@@ -157,6 +171,9 @@ public class DocumentsActivity extends BaseActivity {
if (external && mState.action == ACTION_GET_CONTENT) {
showDrawer = true;
}
+ if (mState.action == ACTION_PICK_COPY_DESTINATION) {
+ showDrawer = true;
+ }
if (showDrawer) {
mNavigator.revealRootsDrawer(true);
@@ -287,13 +304,8 @@ public class DocumentsActivity extends BaseActivity {
mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
}
} else {
- if (mSearchManager.isSearching()) {
- // Ongoing search
- DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
- } else {
// Normal boring directory
DirectoryFragment.showDirectory(fm, root, cwd, anim);
- }
}
// Forget any replacement target
@@ -308,7 +320,7 @@ public class DocumentsActivity extends BaseActivity {
mState.action == ACTION_PICK_COPY_DESTINATION) {
final PickFragment pick = PickFragment.get(fm);
if (pick != null) {
- pick.setPickTarget(mState.action, mState.transferMode, cwd);
+ pick.setPickTarget(mState.action, mState.copyOperationSubType, cwd);
}
}
}
@@ -318,6 +330,12 @@ public class DocumentsActivity extends BaseActivity {
.executeOnExecutor(getExecutorForCurrentDirectory());
}
+ @Override
+ void onDirectoryCreated(DocumentInfo doc) {
+ assert(doc.isDirectory());
+ openContainerDocument(doc);
+ }
+
void onSaveRequested(String mimeType, String displayName) {
new CreateFinishTask(this, mimeType, displayName)
.executeOnExecutor(getExecutorForCurrentDirectory());
@@ -329,12 +347,8 @@ public class DocumentsActivity extends BaseActivity {
mNavigator.revealRootsDrawer(false);
}
- public void setRootsDrawerOpen(boolean open) {
- mNavigator.revealRootsDrawer(open);
- }
-
@Override
- public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
+ public void onDocumentPicked(DocumentInfo doc, Model model) {
final FragmentManager fm = getFragmentManager();
if (doc.isContainer()) {
openContainerDocument(doc);
@@ -425,7 +439,7 @@ public class DocumentsActivity extends BaseActivity {
// Picking a copy destination is only used internally by us, so we
// don't need to extend permissions to the caller.
intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
- intent.putExtra(FileOperationService.EXTRA_OPERATION, mState.transferMode);
+ intent.putExtra(FileOperationService.EXTRA_OPERATION, mState.copyOperationSubType);
} else {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
@@ -442,16 +456,19 @@ public class DocumentsActivity extends BaseActivity {
}
/**
- * Restores the stack from Recents for the specified package.
+ * Loads the last used path (stack) from Recents (history).
+ * The path selected is based on the calling package name. So the last
+ * path for an app like Gmail can be different than the last path
+ * for an app like DropBox.
*/
- private static final class RestoreStackTask
+ private static final class LoadLastUsedStackTask
extends PairedTask<DocumentsActivity, Void, Void> {
private volatile boolean mRestoredStack;
private volatile boolean mExternal;
private State mState;
- public RestoreStackTask(DocumentsActivity activity) {
+ public LoadLastUsedStackTask(DocumentsActivity activity) {
super(activity);
mState = activity.mState;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index d589d5e0e237..b5d3ea082d50 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -36,9 +36,9 @@ import android.view.MenuItem;
import android.widget.Toolbar;
import com.android.documentsui.dirlist.DirectoryFragment;
+import com.android.documentsui.dirlist.Model;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
import java.util.Arrays;
import java.util.List;
@@ -68,7 +68,7 @@ public class DownloadsActivity extends BaseActivity {
// talkback from reading aloud the default title, we clear it here.
setTitle("");
final Uri rootUri = getIntent().getData();
- new RestoreRootTask(this, rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
+ new LoadRootTask(this, rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
} else {
refreshCurrentRootAndDirectory(ANIM_NONE);
}
@@ -118,22 +118,20 @@ public class DownloadsActivity extends BaseActivity {
final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
+ assert(!mSearchManager.isSearching());
+
// If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
// root).
- Preconditions.checkNotNull(cwd);
+ assert(cwd != null);
- if (mState.currentSearch != null) {
- // Ongoing search
- DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
- } else {
- // Normal boring directory
- DirectoryFragment.showDirectory(fm, root, cwd, anim);
- }
+ // Normal boring directory
+ DirectoryFragment.showDirectory(fm, root, cwd, anim);
}
@Override
- public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
- Preconditions.checkArgument(!doc.isDirectory());
+ public void onDocumentPicked(DocumentInfo doc, Model model) {
+ assert(!doc.isDirectory());
+
// First try managing the document; we expect manager to filter
// based on authority, so we don't grant.
final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
index bcf69c44070a..9fceff569d76 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.app.Activity;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
@@ -83,7 +81,7 @@ abstract class DrawerController implements DrawerListener {
DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
Toolbar drawerToolbar) {
mToolbar = drawerToolbar;
- checkArgument(layout != null);
+ assert(layout != null);
mLayout = layout;
mDrawer = drawer;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index 99b425e9fac2..14d4e2d942d9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -91,6 +91,8 @@ public final class Events {
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_MOVE_HOME:
case KeyEvent.KEYCODE_MOVE_END:
+ case KeyEvent.KEYCODE_PAGE_UP:
+ case KeyEvent.KEYCODE_PAGE_DOWN:
return true;
default:
return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c81f342822f6..c17be067d55d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -19,8 +19,6 @@ package com.android.documentsui;
import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkState;
import android.app.Activity;
import android.app.FragmentManager;
@@ -33,7 +31,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
-import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;
@@ -43,6 +40,7 @@ import android.view.MenuItem;
import com.android.documentsui.OperationDialogFragment.DialogType;
import com.android.documentsui.RecentsProvider.ResumeColumns;
import com.android.documentsui.dirlist.DirectoryFragment;
+import com.android.documentsui.dirlist.Model;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -62,6 +60,12 @@ public class FilesActivity extends BaseActivity {
public static final String TAG = "FilesActivity";
+ // See comments where this const is referenced for details.
+ private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
+
+ // Track the time we opened the drawer in response to back being pressed.
+ // We use the time gap to figure out whether to close app or reopen the drawer.
+ private long mDrawerLastFiddled;
private DocumentClipper mClipper;
public FilesActivity() {
@@ -81,7 +85,6 @@ public class FilesActivity extends BaseActivity {
if (mState.restored) {
if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
- refreshCurrentRootAndDirectory(ANIM_NONE);
} else if (!mState.stack.isEmpty()) {
// If a non-empty stack is present in our state it was read (presumably)
// from EXTRA_STACK intent extra. In this case, we'll skip other means of
@@ -92,25 +95,23 @@ public class FilesActivity extends BaseActivity {
// Launch URIs support sensible activity management, but don't specify a real
// content target.
if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
- checkState(uri == null || uri.getAuthority() == null ||
+ assert(uri == null || uri.getAuthority() == null ||
LauncherActivity.isLaunchUri(uri));
refreshCurrentRootAndDirectory(ANIM_NONE);
} else if (intent.getAction() == Intent.ACTION_VIEW) {
- checkArgument(uri != null);
+ assert(uri != null);
new OpenUriForViewTask(this).executeOnExecutor(
ProviderExecutor.forAuthority(uri.getAuthority()), uri);
} else if (DocumentsContract.isRootUri(this, uri)) {
if (DEBUG) Log.d(TAG, "Launching with root URI.");
// If we've got a specific root to display, restore that root using a dedicated
// authority. That way a misbehaving provider won't result in an ANR.
- new RestoreRootTask(this, uri).executeOnExecutor(
- ProviderExecutor.forAuthority(uri.getAuthority()));
+ loadRoot(uri);
} else {
if (DEBUG) Log.d(TAG, "Launching into Home directory.");
// If all else fails, try to load "Home" directory.
final Uri homeUri = DocumentsContract.buildHomeUri();
- new RestoreRootTask(this, homeUri).executeOnExecutor(
- ProviderExecutor.forAuthority(homeUri.getAuthority()));
+ loadRoot(homeUri);
}
final @DialogType int dialogType = intent.getIntExtra(
@@ -140,7 +141,7 @@ public class FilesActivity extends BaseActivity {
state.allowMultiple = true;
// Options specific to the DocumentsActivity.
- checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
+ assert(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
if (stack != null) {
@@ -209,7 +210,7 @@ public class FilesActivity extends BaseActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_create_dir:
- checkState(canCreateDirectory());
+ assert(canCreateDirectory());
showCreateDirectoryDialog();
return true;
case R.id.menu_new_window:
@@ -247,16 +248,13 @@ public class FilesActivity extends BaseActivity {
final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
+ assert(!mSearchManager.isSearching());
+
if (cwd == null) {
DirectoryFragment.showRecentsOpen(fm, anim);
} else {
- if (mState.currentSearch != null) {
- // Ongoing search
- DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
- } else {
- // Normal boring directory
- DirectoryFragment.showDirectory(fm, root, cwd, anim);
- }
+ // Normal boring directory
+ DirectoryFragment.showDirectory(fm, root, cwd, anim);
}
}
@@ -272,24 +270,20 @@ public class FilesActivity extends BaseActivity {
}
@Override
- public void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings) {
+ public void onDocumentPicked(DocumentInfo doc, Model model) {
if (doc.isContainer()) {
openContainerDocument(doc);
} else {
- openDocument(doc, siblings);
+ openDocument(doc, model);
}
}
/**
* Launches an intent to view the specified document.
*/
- private void openDocument(DocumentInfo doc, @Nullable SiblingProvider siblings) {
- Intent intent = null;
- if (siblings != null) {
- QuickViewIntentBuilder builder = new QuickViewIntentBuilder(
- getPackageManager(), getResources(), doc, siblings);
- intent = builder.build();
- }
+ private void openDocument(DocumentInfo doc, Model model) {
+ Intent intent = new QuickViewIntentBuilder(
+ getPackageManager(), getResources(), doc, model).build();
if (intent != null) {
// TODO: un-work around issue b/24963914. Should be fixed soon.
@@ -348,6 +342,34 @@ public class FilesActivity extends BaseActivity {
}
}
+ // Do some "do what a I want" drawer fiddling, but don't
+ // do it if user already hit back recently and we recently
+ // did some fiddling.
+ @Override
+ boolean onBeforePopDir() {
+ int size = mState.stack.size();
+
+ if (mDrawer.isPresent()
+ && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
+ // Close drawer if it is open.
+ if (mDrawer.isOpen()) {
+ mDrawer.setOpen(false);
+ mDrawerLastFiddled = System.currentTimeMillis();
+ return true;
+ }
+
+ // Open the Close drawer if it is closed and we're at the top of a root.
+ if (size == 1) {
+ mDrawer.setOpen(true);
+ // Remember so we don't just close it again if back is pressed again.
+ mDrawerLastFiddled = System.currentTimeMillis();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
// Turns out only DocumentsActivity was ever calling saveStackBlocking.
// There may be a case where we want to contribute entries from
// Behavior here in FilesActivity, but it isn't yet obvious.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/LoadRootTask.java
index 9048b9d45ee7..c5d359b1246b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LoadRootTask.java
@@ -22,12 +22,12 @@ import android.util.Log;
import com.android.documentsui.model.RootInfo;
-final class RestoreRootTask extends PairedTask<BaseActivity, Void, RootInfo> {
+final class LoadRootTask extends PairedTask<BaseActivity, Void, RootInfo> {
private static final String TAG = "RestoreRootTask";
private final Uri mRootUri;
- public RestoreRootTask(BaseActivity activity, Uri rootUri) {
+ public LoadRootTask(BaseActivity activity, Uri rootUri) {
super(activity);
mRootUri = rootUri;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 4bffc49e5ac0..170fb891f97d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -17,7 +17,6 @@
package com.android.documentsui;
import static com.android.documentsui.State.MODE_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
import android.content.Context;
import android.preference.PreferenceManager;
@@ -59,7 +58,8 @@ public class LocalPreferences {
}
public static void setViewMode(Context context, RootInfo root, @ViewMode int viewMode) {
- checkArgument(viewMode != MODE_UNKNOWN);
+ assert(viewMode != MODE_UNKNOWN);
+
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putInt(createKey(root), viewMode).apply();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index 172282a9b3f9..bff65d5b5caf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -17,7 +17,6 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
-import static com.android.internal.util.Preconditions.checkArgument;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -64,23 +63,23 @@ public final class Metrics {
// Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
// root that is not explicitly recognized by the Metrics code (see {@link
- // #getSanitizedRootIndex}). Apps are also bucketed in this histogram using negative indices
- // (see below).
+ // #getSanitizedRootIndex}). Apps are also bucketed in this histogram.
// Do not change or rearrange these values, that will break historical data. Only add to the end
// of the list.
- private static final int ROOT_NONE = 0;
- private static final int ROOT_OTHER = 1;
- private static final int ROOT_AUDIO = 2;
- private static final int ROOT_DEVICE_STORAGE = 3;
- private static final int ROOT_DOWNLOADS = 4;
- private static final int ROOT_HOME = 5;
- private static final int ROOT_IMAGES = 6;
- private static final int ROOT_RECENTS = 7;
- private static final int ROOT_VIDEOS = 8;
- private static final int ROOT_MTP = 9;
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int ROOT_NONE = 1;
+ private static final int ROOT_OTHER = 2;
+ private static final int ROOT_AUDIO = 3;
+ private static final int ROOT_DEVICE_STORAGE = 4;
+ private static final int ROOT_DOWNLOADS = 5;
+ private static final int ROOT_HOME = 6;
+ private static final int ROOT_IMAGES = 7;
+ private static final int ROOT_RECENTS = 8;
+ private static final int ROOT_VIDEOS = 9;
+ private static final int ROOT_MTP = 10;
// Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
- // are logged analogously to roots. Use negative numbers to identify apps.
- private static final int ROOT_THIRD_PARTY_APP = -1;
+ // are logged analogously to roots.
+ private static final int ROOT_THIRD_PARTY_APP = 100;
@IntDef(flag = true, value = {
ROOT_NONE,
@@ -99,19 +98,21 @@ public final class Metrics {
public @interface Root {}
// Indices for bucketing mime types.
- private static final int MIME_OTHER = -2; // anything not enumerated below
- private static final int MIME_NONE = -1; // null mime
- private static final int MIME_ANY = 0; // */*
- private static final int MIME_APPLICATION = 1; // application/*
- private static final int MIME_AUDIO = 2; // audio/*
- private static final int MIME_IMAGE = 3; // image/*
- private static final int MIME_MESSAGE = 4; // message/*
- private static final int MIME_MULTIPART = 5; // multipart/*
- private static final int MIME_TEXT = 6; // text/*
- private static final int MIME_VIDEO = 7; // video/*
+ // Do not change or rearrange these values, that will break historical data. Only add to the end
+ // of the list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int MIME_NONE = 1; // null mime
+ private static final int MIME_ANY = 2; // */*
+ private static final int MIME_APPLICATION = 3; // application/*
+ private static final int MIME_AUDIO = 4; // audio/*
+ private static final int MIME_IMAGE = 5; // image/*
+ private static final int MIME_MESSAGE = 6; // message/*
+ private static final int MIME_MULTIPART = 7; // multipart/*
+ private static final int MIME_TEXT = 8; // text/*
+ private static final int MIME_VIDEO = 9; // video/*
+ private static final int MIME_OTHER = 10; // anything not enumerated below
@IntDef(flag = true, value = {
- MIME_OTHER,
MIME_NONE,
MIME_ANY,
MIME_APPLICATION,
@@ -120,25 +121,29 @@ public final class Metrics {
MIME_MESSAGE,
MIME_MULTIPART,
MIME_TEXT,
- MIME_VIDEO
+ MIME_VIDEO,
+ MIME_OTHER
})
@Retention(RetentionPolicy.SOURCE)
public @interface Mime {}
// Codes representing different kinds of file operations. These are used for bucketing
// operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms.
- private static final int FILEOP_OTHER = 0; // any file operation not listed below
- private static final int FILEOP_COPY_INTRA_PROVIDER = 1; // Copy within a provider
- private static final int FILEOP_COPY_SYSTEM_PROVIDER = 2; // Copy to a system provider.
- private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 3; // Copy to a 3rd-party provider.
- private static final int FILEOP_MOVE_INTRA_PROVIDER = 4; // Move within a provider.
- private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 5; // Move to a system provider.
- private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 6; // Move to a 3rd-party provider.
- private static final int FILEOP_DELETE = 7;
- private static final int FILEOP_OTHER_ERROR = -1;
- private static final int FILEOP_COPY_ERROR = -2;
- private static final int FILEOP_MOVE_ERROR = -3;
- private static final int FILEOP_DELETE_ERROR = -4;
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int FILEOP_OTHER = 1; // any file operation not listed below
+ private static final int FILEOP_COPY_INTRA_PROVIDER = 2; // Copy within a provider
+ private static final int FILEOP_COPY_SYSTEM_PROVIDER = 3; // Copy to a system provider.
+ private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 4; // Copy to a 3rd-party provider.
+ private static final int FILEOP_MOVE_INTRA_PROVIDER = 5; // Move within a provider.
+ private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 6; // Move to a system provider.
+ private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 7; // Move to a 3rd-party provider.
+ private static final int FILEOP_DELETE = 8;
+ private static final int FILEOP_OTHER_ERROR = 100;
+ private static final int FILEOP_DELETE_ERROR = 101;
+ private static final int FILEOP_MOVE_ERROR = 102;
+ private static final int FILEOP_COPY_ERROR = 103;
@IntDef(flag = true, value = {
FILEOP_OTHER,
@@ -157,6 +162,52 @@ public final class Metrics {
@Retention(RetentionPolicy.SOURCE)
public @interface FileOp {}
+ // Codes representing different kinds of file operations. These are used for bucketing
+ // operations in the COUNT_FILEOP_CANCELED histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int OPERATION_UNKNOWN = 1;
+ private static final int OPERATION_COPY = 2;
+ private static final int OPERATION_MOVE = 3;
+ private static final int OPERATION_DELETE= 4;
+
+ @IntDef(flag = true, value = {
+ OPERATION_UNKNOWN,
+ OPERATION_COPY,
+ OPERATION_MOVE,
+ OPERATION_DELETE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MetricsOpType {}
+
+ // Codes representing different launch actions. These are used for bucketing stats in the
+ // COUNT_LAUNCH_ACTION histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int ACTION_OTHER = 1;
+ private static final int ACTION_OPEN = 2;
+ private static final int ACTION_CREATE = 3;
+ private static final int ACTION_GET_CONTENT = 4;
+ private static final int ACTION_OPEN_TREE = 5;
+ private static final int ACTION_MANAGE = 6;
+ private static final int ACTION_BROWSE = 7;
+ private static final int ACTION_PICK_COPY_DESTINATION = 8;
+
+ @IntDef(flag = true, value = {
+ ACTION_OTHER,
+ ACTION_OPEN,
+ ACTION_CREATE,
+ ACTION_GET_CONTENT,
+ ACTION_OPEN_TREE,
+ ACTION_MANAGE,
+ ACTION_BROWSE,
+ ACTION_PICK_COPY_DESTINATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MetricsAction {}
+
// Codes representing different provider types. Used for sorting file operations when logging.
private static final int PROVIDER_INTRA = 0;
private static final int PROVIDER_SYSTEM = 1;
@@ -179,7 +230,7 @@ public final class Metrics {
*/
public static void logActivityLaunch(Context context, State state, Intent intent) {
// Log the launch action.
- logHistogram(context, COUNT_LAUNCH_ACTION, state.action);
+ logHistogram(context, COUNT_LAUNCH_ACTION, toMetricsAction(state.action));
// Then log auxiliary data (roots/mime types) associated with some actions.
Uri uri = intent.getData();
switch (state.action) {
@@ -300,7 +351,7 @@ public final class Metrics {
* @param operationType
*/
public static void logFileOperationCancelled(Context context, @OpType int operationType) {
- logHistogram(context, COUNT_FILEOP_CANCELED, operationType);
+ logHistogram(context, COUNT_FILEOP_CANCELED, toMetricsOpType(operationType));
}
private static void logInterProviderFileOps(
@@ -311,7 +362,7 @@ public final class Metrics {
if (operationType == FileOperationService.OPERATION_DELETE) {
logHistogram(context, histogram, FILEOP_DELETE);
} else {
- checkArgument(dst != null);
+ assert(dst != null);
@Provider int providerType =
isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL;
logHistogram(context, histogram, getOpCode(operationType, providerType));
@@ -483,6 +534,44 @@ public final class Metrics {
}
/**
+ * Maps FileOperationService OpType values, to MetricsOpType values.
+ */
+ private static @MetricsOpType int toMetricsOpType(@OpType int operation) {
+ switch (operation) {
+ case FileOperationService.OPERATION_COPY:
+ return OPERATION_COPY;
+ case FileOperationService.OPERATION_MOVE:
+ return OPERATION_MOVE;
+ case FileOperationService.OPERATION_DELETE:
+ return OPERATION_DELETE;
+ case FileOperationService.OPERATION_UNKNOWN:
+ default:
+ return OPERATION_UNKNOWN;
+ }
+ }
+
+ private static @MetricsAction int toMetricsAction(int action) {
+ switch(action) {
+ case State.ACTION_OPEN:
+ return ACTION_OPEN;
+ case State.ACTION_CREATE:
+ return ACTION_CREATE;
+ case State.ACTION_GET_CONTENT:
+ return ACTION_GET_CONTENT;
+ case State.ACTION_OPEN_TREE:
+ return ACTION_OPEN_TREE;
+ case State.ACTION_MANAGE:
+ return ACTION_MANAGE;
+ case State.ACTION_BROWSE:
+ return ACTION_BROWSE;
+ case State.ACTION_PICK_COPY_DESTINATION:
+ return ACTION_PICK_COPY_DESTINATION;
+ default:
+ return ACTION_OTHER;
+ }
+ }
+
+ /**
* Count the given src documents and provide a tally of how many come from the same provider as
* the dst document (if a dst is provided), how many come from system providers, and how many
* come from external 3rd-party providers.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index ff1940aea94d..4cba1354d853 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -132,7 +132,7 @@ class NavigationView {
showBreadcrumb(true);
mToolbar.setTitle(null);
mIgnoreNextNavigation = true;
- mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1);
+ mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1, false);
}
if (DEBUG) Log.d(TAG, "Final toolbar title is: " + mToolbar.getTitle());
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index d6015501b003..27d6797fdce6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -17,9 +17,12 @@
package com.android.documentsui;
import static android.os.Environment.isStandardDirectory;
+import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
+import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
import static com.android.documentsui.Shared.DEBUG;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
@@ -31,13 +34,16 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
+import android.content.UriPermission;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.provider.DocumentsContract;
import android.text.TextUtils;
@@ -58,42 +64,67 @@ public class OpenExternalDirectoryActivity extends Activity {
private static final String EXTRA_APP_LABEL = "com.android.documentsui.APP_LABEL";
private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL";
+ private ContentProviderClient mExternalStorageClient;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
- if (intent == null || intent.getData() == null) {
- Log.d(TAG, "missing intent or intent data: " + intent);
+ if (intent == null) {
+ if (DEBUG) Log.d(TAG, "missing intent");
+ setResult(RESULT_CANCELED);
+ finish();
+ return;
+ }
+ final Parcelable storageVolume = intent.getParcelableExtra(EXTRA_STORAGE_VOLUME);
+ if (!(storageVolume instanceof StorageVolume)) {
+ if (DEBUG)
+ Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
+ + storageVolume);
+ setResult(RESULT_CANCELED);
+ finish();
+ return;
+ }
+ final String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME);
+ if (directoryName == null) {
+ if (DEBUG) Log.d(TAG, "missing extra " + EXTRA_DIRECTORY_NAME + " on " + intent);
setResult(RESULT_CANCELED);
finish();
return;
}
- final String path = intent.getData().getPath();
final int userId = UserHandle.myUserId();
- if (!showFragment(this, userId, path)) {
+ if (!showFragment(this, userId, (StorageVolume) storageVolume, directoryName)) {
setResult(RESULT_CANCELED);
finish();
return;
}
}
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mExternalStorageClient != null) {
+ mExternalStorageClient.close();
+ }
+ }
+
/**
- * Validates the given {@code path} and display the appropriate dialog asking the user to grant
- * access to it.
+ * Validates the given path (volume + directory) and display the appropriate dialog asking the
+ * user to grant access to it.
*/
- static boolean showFragment(Activity activity, int userId, String path) {
- Log.d(TAG, "showFragment() for path " + path + " and user " + userId);
- if (path == null) {
- Log.e(TAG, "INTERNAL ERROR: showFragment() with null path");
- return false;
- }
+ private static boolean showFragment(OpenExternalDirectoryActivity activity, int userId,
+ StorageVolume storageVolume, String directoryName) {
+ if (DEBUG)
+ Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory "
+ + directoryName + ", and user " + userId);
File file;
try {
- file = new File(new File(path).getCanonicalPath());
+ file = new File(storageVolume.getPathFile(), directoryName).getCanonicalFile();
} catch (IOException e) {
- Log.e(TAG, "Could not get canonical file from " + path);
+ Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
+ + " and directory " + directoryName);
return false;
}
final StorageManager sm =
@@ -104,11 +135,13 @@ public class OpenExternalDirectoryActivity extends Activity {
// Verify directory is valid.
if (TextUtils.isEmpty(directory) || !isStandardDirectory(directory)) {
- Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '" + path + "')");
+ if (DEBUG)
+ Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
+ + file.getAbsolutePath() + "')");
return false;
}
- // Gets volume label and converted path
+ // Gets volume label and converted path.
String volumeLabel = null;
final List<VolumeInfo> volumes = sm.getVolumes();
if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
@@ -122,8 +155,17 @@ public class OpenExternalDirectoryActivity extends Activity {
break;
}
}
+
+ // Checks if the user has granted the permission already.
+ final Intent intent = getIntentForExistingPermission(activity, file);
+ if (intent != null) {
+ activity.setResult(RESULT_OK, intent);
+ activity.finish();
+ return true;
+ }
+
if (volumeLabel == null) {
- Log.e(TAG, "Could not get volume for " + path);
+ Log.e(TAG, "Could not get volume for " + file);
return false;
}
@@ -165,18 +207,17 @@ public class OpenExternalDirectoryActivity extends Activity {
final File userPath = volume.getPathForUser(userId);
final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
final boolean isVisible = volume.isVisibleForWrite(userId);
- if (DEBUG) {
+ if (DEBUG)
Log.d(TAG, "Volume: " + volume + " userId: " + userId + " root: " + root
+ " volumePath: " + volume.getPath().getPath()
+ " pathForUser: " + path
+ " internalPathForUser: " + volume.getInternalPath()
+ " isVisible: " + isVisible);
- }
+
return volume.isVisibleForWrite(userId) && root.equals(path);
}
- private static Intent createGrantedUriPermissionsIntent(ContentProviderClient provider,
- File file) {
+ private static Uri getGrantedUriPermission(ContentProviderClient provider, File file) {
// Calls ExternalStorageProvider to get the doc id for the file
final Bundle bundle;
try {
@@ -197,8 +238,17 @@ public class OpenExternalDirectoryActivity extends Activity {
Log.e(TAG, "Could not get URI for doc id " + docId);
return null;
}
-
if (DEBUG) Log.d(TAG, "URI for " + file + ": " + uri);
+ return uri;
+ }
+
+ private static Intent createGrantedUriPermissionsIntent(ContentProviderClient provider,
+ File file) {
+ final Uri uri = getGrantedUriPermission(provider, file);
+ return createGrantedUriPermissionsIntent(uri);
+ }
+
+ private static Intent createGrantedUriPermissionsIntent(Uri uri) {
final Intent intent = new Intent();
intent.setData(uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
@@ -208,13 +258,31 @@ public class OpenExternalDirectoryActivity extends Activity {
return intent;
}
+ private static Intent getIntentForExistingPermission(OpenExternalDirectoryActivity activity,
+ File file) {
+ final String packageName = activity.getCallingPackage();
+ final Uri grantedUri = getGrantedUriPermission(activity.getExternalStorageClient(), file);
+ if (DEBUG)
+ Log.d(TAG, "checking if " + packageName + " already has permission for " + grantedUri);
+ final ActivityManager am =
+ (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
+ for (UriPermission uriPermission : am.getGrantedUriPermissions(packageName).getList()) {
+ final Uri uri = uriPermission.getUri();
+ if (uri.equals(grantedUri)) {
+ if (DEBUG) Log.d(TAG, packageName + " already has permission: " + uriPermission);
+ return createGrantedUriPermissionsIntent(uri);
+ }
+ }
+ if (DEBUG) Log.d(TAG, packageName + " does not have permission for " + grantedUri);
+ return null;
+ }
+
public static class OpenExternalDirectoryDialogFragment extends DialogFragment {
private File mFile;
private String mVolumeLabel;
private String mAppLabel;
- private ContentProviderClient mExternalStorageClient;
- private ContentResolver mResolver;
+ private OpenExternalDirectoryActivity mActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -224,16 +292,8 @@ public class OpenExternalDirectoryActivity extends Activity {
mFile = new File(args.getString(EXTRA_FILE));
mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
mAppLabel = args.getString(EXTRA_APP_LABEL);
- mResolver = getContext().getContentResolver();
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (mExternalStorageClient != null) {
- mExternalStorageClient.close();
}
+ mActivity = (OpenExternalDirectoryActivity) getActivity();
}
@Override
@@ -246,8 +306,8 @@ public class OpenExternalDirectoryActivity extends Activity {
public void onClick(DialogInterface dialog, int which) {
Intent intent = null;
if (which == DialogInterface.BUTTON_POSITIVE) {
- intent = createGrantedUriPermissionsIntent(getExternalStorageClient(),
- mFile);
+ intent = createGrantedUriPermissionsIntent(
+ mActivity.getExternalStorageClient(), mFile);
}
if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
activity.setResult(RESULT_CANCELED);
@@ -276,13 +336,13 @@ public class OpenExternalDirectoryActivity extends Activity {
activity.setResult(RESULT_CANCELED);
activity.finish();
}
+ }
- private synchronized ContentProviderClient getExternalStorageClient() {
- if (mExternalStorageClient == null) {
- mExternalStorageClient =
- mResolver.acquireContentProviderClient(EXTERNAL_STORAGE_AUTH);
- }
- return mExternalStorageClient;
+ private synchronized ContentProviderClient getExternalStorageClient() {
+ if (mExternalStorageClient == null) {
+ mExternalStorageClient =
+ getContentResolver().acquireContentProviderClient(EXTERNAL_STORAGE_AUTH);
}
+ return mExternalStorageClient;
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
index 85cc12b8a97a..2cef8d31ad1a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
@@ -16,9 +16,6 @@
package com.android.documentsui;
-import static com.android.documentsui.services.FileOperationService.OpType;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.annotation.IntDef;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -32,13 +29,11 @@ import android.text.Html;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.services.FileOperationService;
-import com.android.documentsui.services.FileOperations;
-import com.android.documentsui.services.Job;
+import com.android.documentsui.services.FileOperationService.OpType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.List;
/**
* Alert dialog for operation dialogs.
@@ -114,7 +109,7 @@ public class OperationDialogFragment extends DialogFragment {
final StringBuilder list = new StringBuilder("<p>");
for (DocumentInfo documentInfo : srcList) {
- list.append(String.format("&#8226; %s<br>", documentInfo.displayName));
+ list.append(String.format("&#8226; %s<br>", Html.escapeHtml(documentInfo.displayName)));
}
list.append("</p>");
builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString())));
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index bbf4682a1466..933506c258f2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -16,6 +16,10 @@
package com.android.documentsui;
+import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
+import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
+import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
+
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -27,6 +31,7 @@ import android.view.ViewGroup;
import android.widget.Button;
import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.services.FileOperationService.OpType;
/**
* Display pick confirmation bar, usually for selecting a directory.
@@ -35,7 +40,8 @@ public class PickFragment extends Fragment {
public static final String TAG = "PickFragment";
private int mAction;
- private int mTransferMode;
+ // Only legal values are OPERATION_COPY, OPERATION_MOVE, and unset (OPERATION_UNKNOWN).
+ private @OpType int mCopyOperationSubType = OPERATION_UNKNOWN;
private DocumentInfo mPickTarget;
private View mContainer;
private Button mPick;
@@ -92,9 +98,12 @@ public class PickFragment extends Fragment {
/**
* @param action Which action defined in State is the picker shown for.
*/
- public void setPickTarget(int action, int transferMode, DocumentInfo pickTarget) {
+ public void setPickTarget(
+ int action, @OpType int copyOperationSubType, DocumentInfo pickTarget) {
+ assert(copyOperationSubType != OPERATION_DELETE);
+
mAction = action;
- mTransferMode = transferMode;
+ mCopyOperationSubType = copyOperationSubType;
mPickTarget = pickTarget;
if (mContainer != null) {
updateView();
@@ -111,7 +120,8 @@ public class PickFragment extends Fragment {
mCancel.setVisibility(View.GONE);
break;
case State.ACTION_PICK_COPY_DESTINATION:
- mPick.setText(R.string.button_copy);
+ mPick.setText(mCopyOperationSubType == OPERATION_MOVE
+ ? R.string.button_move : R.string.button_copy);
mCancel.setVisibility(View.VISIBLE);
break;
default:
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
index b0e332faa3fc..8145edc4d7db 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
@@ -19,7 +19,6 @@ package com.android.documentsui;
import android.os.AsyncTask;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -85,7 +84,7 @@ public class ProviderExecutor extends Thread implements Executor {
private Executor mNonPreemptingExecutor = new Executor() {
@Override
public void execute(Runnable command) {
- Preconditions.checkNotNull(command);
+ assert(command != null);
mQueue.add(command);
}
};
@@ -93,7 +92,7 @@ public class ProviderExecutor extends Thread implements Executor {
@Override
public void execute(Runnable command) {
preempt();
- Preconditions.checkNotNull(command);
+ assert(command != null);
mQueue.add(command);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 454316214573..a77a9b3559dc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -33,34 +33,36 @@ import android.provider.DocumentsContract.Document;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Range;
-import com.android.documentsui.BaseActivity.SiblingProvider;
+import com.android.documentsui.dirlist.Model;
import com.android.documentsui.model.DocumentInfo;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Provides support for gather a list of quick-viewable files into a quick view intent.
*/
final class QuickViewIntentBuilder {
+ private static final int MAX_CLIP_ITEMS = 1000;
private final DocumentInfo mDocument;
- private final SiblingProvider mSiblings;
+ private final Model mModel;
private final PackageManager mPkgManager;
private final Resources mResources;
- private ClipData mClipData;
- private int mDocumentLocation;
-
public QuickViewIntentBuilder(
PackageManager pkgManager,
Resources resources,
DocumentInfo doc,
- SiblingProvider siblings) {
+ Model model) {
mPkgManager = pkgManager;
mResources = resources;
mDocument = doc;
- mSiblings = siblings;
+ mModel = model;
}
/**
@@ -78,12 +80,28 @@ final class QuickViewIntentBuilder {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setPackage(trustedPkg);
if (hasRegisteredHandler(intent)) {
- Cursor cursor = mSiblings.getCursor();
- for (int i = 0; i < cursor.getCount(); i++) {
- onNextItem(i, cursor);
+ final ArrayList<Uri> uris = new ArrayList<Uri>();
+ final int documentLocation = collectViewableUris(uris);
+ final Range<Integer> range = computeSiblingsRange(uris, documentLocation);
+
+ ClipData clipData = null;
+ ClipData.Item item;
+ Uri uri;
+ for (int i = range.getLower(); i <= range.getUpper(); i++) {
+ uri = uris.get(i);
+ item = new ClipData.Item(uri);
+ if (DEBUG) Log.d(TAG, "Including file: " + uri);
+ if (clipData == null) {
+ clipData = new ClipData(
+ "URIs", new String[] { ClipDescription.MIMETYPE_TEXT_URILIST },
+ item);
+ } else {
+ clipData.addItem(item);
+ }
}
- intent.putExtra(Intent.EXTRA_INDEX, mDocumentLocation);
- intent.setClipData(mClipData);
+
+ intent.putExtra(Intent.EXTRA_INDEX, documentLocation);
+ intent.setClipData(clipData);
return intent;
} else {
@@ -94,35 +112,63 @@ final class QuickViewIntentBuilder {
return null;
}
- private boolean hasRegisteredHandler(Intent intent) {
- // Try to resolve the intent. If a matching app isn't installed, it won't resolve.
- return intent.resolveActivity(mPkgManager) != null;
- }
+ private int collectViewableUris(ArrayList<Uri> uris) {
+ final List<String> siblingIds = mModel.getModelIds();
+ uris.ensureCapacity(siblingIds.size());
- private void onNextItem(int index, Cursor cursor) {
- cursor.moveToPosition(index);
+ int documentLocation = 0;
+ Cursor cursor;
+ String mimeType;
+ String id;
+ String authority;
+ Uri uri;
- String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- if (Document.MIME_TYPE_DIR.equals(mimeType)) {
- return;
- }
+ // Cursor's are not guaranteed to be immutable. Hence, traverse it only once.
+ for (int i = 0; i < siblingIds.size(); i++) {
+ cursor = mModel.getItem(siblingIds.get(i));
- String id = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
- String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
- Uri uri = DocumentsContract.buildDocumentUri(authority, id);
- if (DEBUG) Log.d(TAG, "Including file[" + id + "] @ " + uri);
+ mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ continue;
+ }
- if (id.equals(mDocument.documentId)) {
- if (DEBUG) Log.d(TAG, "Found starting point for QV. " + index);
- mDocumentLocation = index;
+ id = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+ uri = DocumentsContract.buildDocumentUri(authority, id);
+
+ if (id.equals(mDocument.documentId)) {
+ if (DEBUG) Log.d(TAG, "Found starting point for QV. " + i);
+ documentLocation = i;
+ }
+
+ uris.add(uri);
}
- ClipData.Item item = new ClipData.Item(uri);
- if (mClipData == null) {
- mClipData = new ClipData(
- "URIs", new String[]{ClipDescription.MIMETYPE_TEXT_URILIST}, item);
+ return documentLocation;
+ }
+
+ private static Range<Integer> computeSiblingsRange(List<Uri> uris, int documentLocation) {
+ // Restrict number of siblings to avoid hitting the IPC limit.
+ // TODO: Remove this restriction once ClipData can hold an arbitrary number of
+ // items.
+ int firstSibling;
+ int lastSibling;
+ if (documentLocation < uris.size() / 2) {
+ firstSibling = Math.max(0, documentLocation - MAX_CLIP_ITEMS / 2);
+ lastSibling = Math.min(uris.size() - 1, firstSibling + MAX_CLIP_ITEMS - 1);
} else {
- mClipData.addItem(item);
+ lastSibling = Math.min(uris.size() - 1, documentLocation + MAX_CLIP_ITEMS / 2);
+ firstSibling = Math.max(0, lastSibling - MAX_CLIP_ITEMS + 1);
}
+
+ if (DEBUG) Log.d(TAG, "Copmuted siblings from index: " + firstSibling
+ + " to: " + lastSibling);
+
+ return new Range(firstSibling, lastSibling);
+ }
+
+ private boolean hasRegisteredHandler(Intent intent) {
+ // Try to resolve the intent. If a matching app isn't installed, it won't resolve.
+ return intent.resolveActivity(mPkgManager) != null;
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 7dac0c10e077..0e2762291b09 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -83,7 +83,7 @@ public class RecentsCreateFragment extends Fragment {
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
- mRecView = (RecyclerView) view.findViewById(R.id.list);
+ mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
mRecView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecView.addOnItemTouchListener(mItemListener);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
index 0ee54e650db9..cebc9b05679e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
@@ -31,12 +31,12 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
+
import com.google.common.util.concurrent.AbstractFuture;
import libcore.io.IoUtils;
@@ -52,7 +52,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
+public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
// TODO: clean up cursor ownership so background thread doesn't traverse
// previously returned cursors for filtering/sorting; this currently races
// with the UI thread.
@@ -80,7 +80,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
private final State mState;
@GuardedBy("mTasks")
- private final HashMap<RootInfo, RecentTask> mTasks = new HashMap<>();
+ private final HashMap<RootInfo, RecentsTask> mTasks = new HashMap<>();
private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
@@ -89,69 +89,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
private DirectoryResult mResult;
- // TODO: create better transfer of ownership around cursor to ensure its
- // closed in all edge cases.
-
- public class RecentTask extends AbstractFuture<Cursor> implements Runnable, Closeable {
- public final String authority;
- public final String rootId;
-
- private Cursor mWithRoot;
-
- public RecentTask(String authority, String rootId) {
- this.authority = authority;
- this.rootId = rootId;
- }
-
- @Override
- public void run() {
- if (isCancelled()) return;
-
- try {
- mQueryPermits.acquire();
- } catch (InterruptedException e) {
- return;
- }
-
- try {
- runInternal();
- } finally {
- mQueryPermits.release();
- }
- }
-
- public void runInternal() {
- ContentProviderClient client = null;
- try {
- client = DocumentsApplication.acquireUnstableProviderOrThrow(
- getContext().getContentResolver(), authority);
-
- final Uri uri = DocumentsContract.buildRecentDocumentsUri(authority, rootId);
- final Cursor cursor = client.query(
- uri, null, null, null, DirectoryLoader.getQuerySortOrder(mSortOrder));
- mWithRoot = new RootCursorWrapper(authority, rootId, cursor, MAX_DOCS_FROM_ROOT);
-
- } catch (Exception e) {
- Log.w(TAG, "Failed to load " + authority + ", " + rootId, e);
- } finally {
- ContentProviderClient.releaseQuietly(client);
- }
-
- set(mWithRoot);
-
- mFirstPassLatch.countDown();
- if (mFirstPassDone) {
- onContentChanged();
- }
- }
-
- @Override
- public void close() throws IOException {
- IoUtils.closeQuietly(mWithRoot);
- }
- }
-
- public RecentLoader(Context context, RootsCache roots, State state) {
+ public RecentsLoader(Context context, RootsCache roots, State state) {
super(context);
mRoots = roots;
mState = state;
@@ -178,14 +116,13 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
final Collection<RootInfo> roots = mRoots.getMatchingRootsBlocking(mState);
for (RootInfo root : roots) {
- if ((root.flags & Root.FLAG_SUPPORTS_RECENTS) != 0) {
- final RecentTask task = new RecentTask(root.authority, root.rootId);
- mTasks.put(root, task);
+ if (root.supportsRecents()) {
+ mTasks.put(root, new RecentsTask(root.authority, root.rootId));
}
}
mFirstPassLatch = new CountDownLatch(mTasks.size());
- for (RecentTask task : mTasks.values()) {
+ for (RecentsTask task : mTasks.values()) {
ProviderExecutor.forAuthority(task.authority).execute(task);
}
@@ -202,7 +139,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
// Collect all finished tasks
boolean allDone = true;
List<Cursor> cursors = new ArrayList<>();
- for (RecentTask task : mTasks.values()) {
+ for (RecentsTask task : mTasks.values()) {
if (task.isDone()) {
try {
final Cursor cursor = task.get();
@@ -303,7 +240,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
onStopLoading();
synchronized (mTasks) {
- for (RecentTask task : mTasks.values()) {
+ for (RecentsTask task : mTasks.values()) {
IoUtils.closeQuietly(task);
}
}
@@ -311,4 +248,66 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
IoUtils.closeQuietly(mResult);
mResult = null;
}
+
+ // TODO: create better transfer of ownership around cursor to ensure its
+ // closed in all edge cases.
+
+ public class RecentsTask extends AbstractFuture<Cursor> implements Runnable, Closeable {
+ public final String authority;
+ public final String rootId;
+
+ private Cursor mWithRoot;
+
+ public RecentsTask(String authority, String rootId) {
+ this.authority = authority;
+ this.rootId = rootId;
+ }
+
+ @Override
+ public void run() {
+ if (isCancelled()) return;
+
+ try {
+ mQueryPermits.acquire();
+ } catch (InterruptedException e) {
+ return;
+ }
+
+ try {
+ runInternal();
+ } finally {
+ mQueryPermits.release();
+ }
+ }
+
+ public void runInternal() {
+ ContentProviderClient client = null;
+ try {
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ getContext().getContentResolver(), authority);
+
+ final Uri uri = DocumentsContract.buildRecentDocumentsUri(authority, rootId);
+ final Cursor cursor = client.query(
+ uri, null, null, null, DirectoryLoader.getQuerySortOrder(mSortOrder));
+ mWithRoot = new RootCursorWrapper(authority, rootId, cursor, MAX_DOCS_FROM_ROOT);
+
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to load " + authority + ", " + rootId, e);
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+
+ set(mWithRoot);
+
+ mFirstPassLatch.countDown();
+ if (mFirstPassDone) {
+ onContentChanged();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ IoUtils.closeQuietly(mWithRoot);
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 92ffb93365d2..e1b1c09be364 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -95,6 +95,7 @@ public class RecentsProvider extends ContentProvider {
public static final String PACKAGE_NAME = "package_name";
public static final String STACK = "stack";
public static final String TIMESTAMP = "timestamp";
+ // Indicates handler was an external app, like photos.
public static final String EXTERNAL = "external";
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 29a72b86ea7e..ab67a51265e9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -66,7 +66,7 @@ public class RootsCache {
private final ContentObserver mObserver;
private OnCacheUpdateListener mCacheUpdateListener;
- private final RootInfo mRecentsRoot = new RootInfo();
+ private final RootInfo mRecentsRoot;
private final Object mLock = new Object();
private final CountDownLatch mFirstLoad = new CountDownLatch(1);
@@ -82,6 +82,17 @@ public class RootsCache {
public RootsCache(Context context) {
mContext = context;
mObserver = new RootsChangedObserver();
+
+ // Create a new anonymous "Recents" RootInfo. It's a faker.
+ mRecentsRoot = new RootInfo() {{
+ // Special root for recents
+ derivedIcon = R.drawable.ic_root_recent;
+ derivedType = RootInfo.TYPE_RECENTS;
+ flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD
+ | Root.FLAG_SUPPORTS_CREATE;
+ title = mContext.getString(R.string.root_recent);
+ availableBytes = -1;
+ }};
}
private class RootsChangedObserver extends ContentObserver {
@@ -104,15 +115,16 @@ public class RootsCache {
* Gather roots from all known storage providers.
*/
public void updateAsync() {
- // Special root for recents
- mRecentsRoot.authority = null;
- mRecentsRoot.rootId = null;
- mRecentsRoot.derivedIcon = R.drawable.ic_root_recent;
- mRecentsRoot.derivedType = RootInfo.TYPE_RECENTS;
- mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
- | Root.FLAG_SUPPORTS_IS_CHILD;
- mRecentsRoot.title = mContext.getString(R.string.root_recent);
- mRecentsRoot.availableBytes = -1;
+ // Verifying an assumption about the recents root being immutable.
+ assert(mRecentsRoot.authority == null);
+ assert(mRecentsRoot.rootId == null);
+ assert(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
+ assert(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
+ assert(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY
+ | Root.FLAG_SUPPORTS_IS_CHILD
+ | Root.FLAG_SUPPORTS_CREATE));
+ assert(mRecentsRoot.title == mContext.getString(R.string.root_recent));
+ assert(mRecentsRoot.availableBytes == -1);
new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@@ -360,7 +372,7 @@ public class RootsCache {
}
public boolean isRecentsRoot(RootInfo root) {
- return mRecentsRoot == root;
+ return mRecentsRoot.equals(root);
}
public Collection<RootInfo> getRootsBlocking() {
@@ -400,27 +412,23 @@ public class RootsCache {
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
final List<RootInfo> matching = new ArrayList<>();
for (RootInfo root : roots) {
- final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
- final boolean supportsIsChild = (root.flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
- final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
- final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
- final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
-
// Exclude read-only devices when creating
- if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
- if (state.action == State.ACTION_PICK_COPY_DESTINATION && !supportsCreate) continue;
+ if (state.action == State.ACTION_CREATE && !root.supportsCreate()) continue;
+ if (state.action == State.ACTION_PICK_COPY_DESTINATION
+ && !root.supportsCreate()) continue;
// Exclude roots that don't support directory picking
- if (state.action == State.ACTION_OPEN_TREE && !supportsIsChild) continue;
+ if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) continue;
// Exclude advanced devices when not requested
- if (!state.showAdvanced && advanced) continue;
+ if (!state.showAdvanced && root.isAdvanced()) continue;
// Exclude non-local devices when local only
- if (state.localOnly && !localOnly) continue;
- // Exclude downloads roots that don't support directory creation
- // TODO: Add flag to check the root supports directory creation or not.
- if (state.directoryCopy && root.isDownloads()) continue;
+ if (state.localOnly && !root.isLocalOnly()) continue;
+ // Exclude downloads roots as it doesn't support directory creation (actually
+ // we just don't show them).
+ // TODO: Add flag to check the root supports directory creation.
+ if (state.directoryCopy && !root.isDownloads()) continue;
// Only show empty roots when creating, or in browse mode.
- if (empty && (state.action == State.ACTION_OPEN
+ if (root.isEmpty() && (state.action == State.ACTION_OPEN
|| state.action == State.ACTION_GET_CONTENT)) {
if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
continue;
@@ -436,10 +444,13 @@ public class RootsCache {
// Exclude roots from the calling package.
if (state.excludedAuthorities.contains(root.authority)) {
- if (DEBUG) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
+ if (DEBUG) Log.d(
+ TAG, "Excluding root " + root.authority + " from calling package.");
continue;
}
+ if (DEBUG) Log.d(
+ TAG, "Including root " + root + " in roots list.");
matching.add(root);
}
return matching;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 26bda31261ef..9f83c042b111 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -30,6 +30,7 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
+import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.Log;
@@ -44,7 +45,6 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import java.util.ArrayList;
@@ -86,10 +86,9 @@ public class RootsFragment extends Fragment {
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final Context context = inflater.getContext();
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
- mList = (ListView) view.findViewById(android.R.id.list);
+ mList = (ListView) view.findViewById(R.id.roots_list);
mList.setOnItemClickListener(mItemListener);
mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
return view;
@@ -112,11 +111,13 @@ public class RootsFragment extends Fragment {
@Override
public void onLoadFinished(
Loader<Collection<RootInfo>> loader, Collection<RootInfo> result) {
- if (!isAdded()) return;
+ if (!isAdded()) {
+ return;
+ }
- final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
+ Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
- mAdapter = new RootsAdapter(context, result, includeApps);
+ mAdapter = new RootsAdapter(context, result, handlerAppIntent);
mList.setAdapter(mAdapter);
onCurrentRootChanged();
@@ -151,7 +152,9 @@ public class RootsFragment extends Fragment {
}
public void onCurrentRootChanged() {
- if (mAdapter == null) return;
+ if (mAdapter == null) {
+ return;
+ }
final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot();
for (int i = 0; i < mAdapter.getCount(); i++) {
@@ -167,6 +170,13 @@ public class RootsFragment extends Fragment {
}
}
+ /**
+ * Attempts to shift focus back to the navigation drawer.
+ */
+ public void requestFocus() {
+ mList.requestFocus();
+ }
+
private void showAppDetails(ResolveInfo ri) {
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
@@ -293,7 +303,13 @@ public class RootsFragment extends Fragment {
}
private static class RootsAdapter extends ArrayAdapter<Item> {
- public RootsAdapter(Context context, Collection<RootInfo> roots, Intent includeApps) {
+
+ /**
+ * @param handlerAppIntent When not null, apps capable of handling the original
+ * intent will be included in list of roots (in special section at bottom).
+ */
+ public RootsAdapter(
+ Context context, Collection<RootInfo> roots, @Nullable Intent handlerAppIntent) {
super(context, 0);
final List<RootItem> libraries = new ArrayList<>();
@@ -315,27 +331,39 @@ public class RootsFragment extends Fragment {
Collections.sort(others, comp);
addAll(libraries);
- add(new SpacerItem());
+ // Only add the spacer if it is actually separating something.
+ if (!libraries.isEmpty() && !others.isEmpty()) {
+ add(new SpacerItem());
+ }
addAll(others);
- if (includeApps != null) {
- final PackageManager pm = context.getPackageManager();
- final List<ResolveInfo> infos = pm.queryIntentActivities(
- includeApps, PackageManager.MATCH_DEFAULT_ONLY);
-
- final List<AppItem> apps = new ArrayList<>();
+ // Include apps that can handle this intent too.
+ if (handlerAppIntent != null) {
+ includeHandlerApps(context, handlerAppIntent);
+ }
+ }
- // Omit ourselves from the list
- for (ResolveInfo info : infos) {
- if (!context.getPackageName().equals(info.activityInfo.packageName)) {
- apps.add(new AppItem(info));
- }
+ /**
+ * Adds apps capable of handling the original intent will be included
+ * in list of roots (in special section at bottom).
+ */
+ private void includeHandlerApps(Context context, Intent handlerAppIntent) {
+ final PackageManager pm = context.getPackageManager();
+ final List<ResolveInfo> infos = pm.queryIntentActivities(
+ handlerAppIntent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ final List<AppItem> apps = new ArrayList<>();
+
+ // Omit ourselves from the list
+ for (ResolveInfo info : infos) {
+ if (!context.getPackageName().equals(info.activityInfo.packageName)) {
+ apps.add(new AppItem(info));
}
+ }
- if (apps.size() > 0) {
- add(new SpacerItem());
- addAll(apps);
- }
+ if (apps.size() > 0) {
+ add(new SpacerItem());
+ addAll(apps);
}
}
@@ -374,17 +402,7 @@ public class RootsFragment extends Fragment {
public static class RootComparator implements Comparator<RootItem> {
@Override
public int compare(RootItem lhs, RootItem rhs) {
- // Sort by root type, then title, then summary.
- int score = lhs.root.derivedType - rhs.root.derivedType;
- if (score != 0) {
- return score;
- }
- score = DocumentInfo.compareToIgnoreCaseNullable(lhs.root.title, rhs.root.title);
- if (score != 0) {
- return score;
- }
-
- return DocumentInfo.compareToIgnoreCaseNullable(lhs.root.summary, rhs.root.summary);
+ return lhs.root.compareTo(rhs.root);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsList.java b/packages/DocumentsUI/src/com/android/documentsui/RootsList.java
new file mode 100644
index 000000000000..bf03ffd1e6d6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsList.java
@@ -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.
+ */
+package com.android.documentsui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+/**
+ * The list in the navigation drawer. This class exists for the purpose of overriding the key
+ * handler on ListView. Ignoring keystrokes (e.g. the tab key) cannot be properly done using
+ * View.OnKeyListener.
+ */
+public class RootsList extends ListView {
+
+ // Multiple constructors are needed to handle all the different ways this View could be
+ // constructed by the framework. Don't remove them!
+ public RootsList(Context context) {
+ super(context);
+ }
+
+ public RootsList(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public RootsList(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public RootsList(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ // Ignore tab key events - this causes them to bubble up to the global key handler where
+ // they are appropriately handled. See BaseActivity.onKeyDown.
+ case KeyEvent.KEYCODE_TAB:
+ return false;
+ // Prevent left/right arrow keystrokes from shifting focus away from the roots list.
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ return true;
+ default:
+ return super.onKeyDown(keyCode, event);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index c81377a19aa2..5c4ccdddc39d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -50,7 +50,7 @@ public class RootsLoader extends AsyncTaskLoader<Collection<RootInfo>> {
if (isReset()) {
return;
}
- Collection<RootInfo> oldResult = mResult;
+
mResult = result;
if (isStarted()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
index 69f54c77fe8b..63dc2ee3796e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import android.annotation.Nullable;
+import android.os.Bundle;
import android.provider.DocumentsContract.Root;
import android.text.TextUtils;
import android.util.Log;
@@ -31,28 +33,27 @@ import com.android.documentsui.model.RootInfo;
/**
* Manages searching UI behavior.
*/
-final class SearchManager implements
+final class SearchViewManager implements
SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener {
public interface SearchManagerListener {
- void onSearchChanged();
-
- void onSearchQueryChanged(String query);
+ void onSearchChanged(@Nullable String query);
}
public static final String TAG = "SearchManger";
private SearchManagerListener mListener;
- private String currentSearch;
private boolean mSearchExpanded;
+ private String mCurrentSearch;
private boolean mIgnoreNextClose;
private DocumentsToolbar mActionBar;
private MenuItem mMenu;
private SearchView mView;
- public SearchManager(SearchManagerListener listener) {
+ public SearchViewManager(SearchManagerListener listener, @Nullable Bundle savedState) {
mListener = listener;
+ mCurrentSearch = savedState != null ? savedState.getString(Shared.EXTRA_QUERY) : null;
}
public void setSearchMangerListener(SearchManagerListener listener) {
@@ -60,7 +61,8 @@ final class SearchManager implements
}
public void install(DocumentsToolbar actionBar) {
- assert (mActionBar == null);
+ // assert(mActionBar == null);
+
mActionBar = actionBar;
mMenu = actionBar.getSearchMenu();
mView = (SearchView) mMenu.getActionView();
@@ -69,6 +71,8 @@ final class SearchManager implements
mView.setOnCloseListener(this);
mView.setOnSearchClickListener(this);
mView.setOnQueryTextFocusChangeListener(this);
+
+ restoreSearch();
}
/**
@@ -80,12 +84,12 @@ final class SearchManager implements
return;
}
- if (currentSearch != null) {
+ if (mCurrentSearch != null) {
mMenu.expandActionView();
mView.setIconified(false);
mView.clearFocus();
- mView.setQuery(currentSearch, false);
+ mView.setQuery(mCurrentSearch, false);
} else {
mView.clearFocus();
if (!mView.isIconified()) {
@@ -108,13 +112,11 @@ final class SearchManager implements
return;
}
- mMenu.setVisible(visible);
if (!visible) {
- currentSearch = null;
- if (mListener != null) {
- mListener.onSearchQueryChanged(currentSearch);
- }
+ mCurrentSearch = null;
}
+
+ mMenu.setVisible(visible);
}
/**
@@ -133,8 +135,21 @@ final class SearchManager implements
return false;
}
+ private void restoreSearch() {
+ if (isSearching()) {
+ onSearchExpanded();
+ mView.setIconified(false);
+ mView.setQuery(mCurrentSearch, false);
+ mView.clearFocus();
+ }
+ }
+
+ private void onSearchExpanded() {
+ mSearchExpanded = true;
+ }
+
boolean isSearching() {
- return currentSearch != null;
+ return mCurrentSearch != null;
}
boolean isExpanded() {
@@ -142,6 +157,14 @@ final class SearchManager implements
}
/**
+ * Called when owning activity is saving state to be used to restore state during creation.
+ * @param state Bundle to save state too
+ */
+ public void onSaveInstanceState(Bundle state) {
+ state.putString(Shared.EXTRA_QUERY, mCurrentSearch);
+ }
+
+ /**
* Clears the search. Clears the SearchView background color. Triggers refreshing of the
* directory content.
* @return True if the default behavior of clearing/dismissing SearchView should be overridden.
@@ -155,15 +178,11 @@ final class SearchManager implements
return false;
}
- mView.setBackgroundColor(
- mView.getResources().getColor(android.R.color.transparent, null));
-
// Refresh the directory if a search was done
- if (currentSearch != null) {
- currentSearch = null;
+ if (mCurrentSearch != null) {
+ mCurrentSearch = null;
if (mListener != null) {
- mListener.onSearchQueryChanged(currentSearch);
- mListener.onSearchChanged();
+ mListener.onSearchChanged(mCurrentSearch);
}
}
return false;
@@ -176,18 +195,15 @@ final class SearchManager implements
*/
@Override
public void onClick(View v) {
- mSearchExpanded = true;
- mView.setBackgroundColor(
- mView.getResources().getColor(R.color.menu_search_background, null));
+ onSearchExpanded();
}
@Override
public boolean onQueryTextSubmit(String query) {
- currentSearch = query;
+ mCurrentSearch = query;
mView.clearFocus();
if (mListener != null) {
- mListener.onSearchQueryChanged(currentSearch);
- mListener.onSearchChanged();
+ mListener.onSearchChanged(mCurrentSearch);
}
return true;
}
@@ -195,7 +211,7 @@ final class SearchManager implements
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
- if (currentSearch == null) {
+ if (mCurrentSearch == null) {
mView.setIconified(true);
} else if (TextUtils.isEmpty(mView.getQuery())) {
cancelSearch();
@@ -207,4 +223,9 @@ final class SearchManager implements
public boolean onQueryTextChange(String newText) {
return false;
}
+
+ String getCurrentSearch() {
+ return mCurrentSearch;
+ }
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 22cb25a26a5c..99c2d80bdfd9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,14 +17,21 @@
package com.android.documentsui;
import android.content.Context;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
/** @hide */
public final class Shared {
+
+ public static final String TAG = "Documents";
+
+ public static final boolean DEBUG = true;
+
/** Intent action name to pick a copy destination. */
public static final String ACTION_PICK_COPY_DESTINATION =
"com.android.documentsui.PICK_COPY_DESTINATION";
@@ -34,12 +41,62 @@ public final class Shared {
* specifies if the destination directory needs to create new directory or not.
*/
public static final String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
-
- public static final boolean DEBUG = true;
- public static final String TAG = "Documents";
public static final String EXTRA_STACK = "com.android.documentsui.STACK";
/**
+ * Extra flag used to store query of type String in the bundle.
+ */
+ public static final String EXTRA_QUERY = "query";
+
+ /**
+ * Extra flag used to store state of type State in the bundle.
+ */
+ public static final String EXTRA_STATE = "state";
+
+ /**
+ * Extra flag used to store type of DirectoryFragment's type ResultType type in the bundle.
+ */
+ public static final String EXTRA_TYPE = "type";
+
+ /**
+ * Extra flag used to store root of type RootInfo in the bundle.
+ */
+ public static final String EXTRA_ROOT = "root";
+
+ /**
+ * Extra flag used to store document of DocumentInfo type in the bundle.
+ */
+ public static final String EXTRA_DOC = "document";
+
+ /**
+ * Extra flag used to store DirectoryFragment's selection of Selection type in the bundle.
+ */
+ public static final String EXTRA_SELECTION = "selection";
+
+ /**
+ * Extra flag used to store DirectoryFragment's search mode of boolean type in the bundle.
+ */
+ public static final String EXTRA_SEARCH_MODE = "searchMode";
+
+ /**
+ * Extra flag used to store DirectoryFragment's ignore state of boolean type in the bundle.
+ */
+ public static final String EXTRA_IGNORE_STATE = "ignoreState";
+
+
+ /**
+ * String prefix used to indicate the document is a directory.
+ */
+ public static final char DIR_PREFIX = '\001';
+
+ private static final Collator sCollator;
+
+ static {
+ sCollator = Collator.getInstance();
+ sCollator.setStrength(Collator.SECONDARY);
+ }
+
+ /**
* Generates a formatted quantity string.
*/
public static final String getQuantityString(Context context, int resourceId, int quantity) {
@@ -76,4 +133,26 @@ public final class Shared {
? (ArrayList<T>) list
: new ArrayList<T>(list);
}
+
+ /**
+ * Compare two strings against each other using system default collator in a
+ * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX}
+ * before other items.
+ */
+ public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
+ final boolean leftEmpty = TextUtils.isEmpty(lhs);
+ final boolean rightEmpty = TextUtils.isEmpty(rhs);
+
+ if (leftEmpty && rightEmpty) return 0;
+ if (leftEmpty) return -1;
+ if (rightEmpty) return 1;
+
+ final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
+ final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
+
+ if (leftDir && !rightDir) return -1;
+ if (rightDir && !leftDir) return 1;
+
+ return sCollator.compare(lhs, rhs);
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
index 48c1a733703c..b4d79715d479 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.app.Activity;
import android.support.design.widget.Snackbar;
import android.view.View;
@@ -26,12 +24,13 @@ public final class Snackbars {
private Snackbars() {}
public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
- return Snackbars.makeSnackbar(activity, activity.getResources().getText(messageId), duration);
+ return Snackbars.makeSnackbar(
+ activity, activity.getResources().getText(messageId), duration);
}
- public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
- {
- final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
+ public static final Snackbar makeSnackbar(
+ Activity activity, CharSequence message, int duration) {
+ final View view = activity.findViewById(R.id.coordinator_layout);
return Snackbar.make(view, message, duration);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index d141de667f2f..62f9ea7ed804 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -16,16 +16,22 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
+
import android.annotation.IntDef;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import android.util.SparseArray;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperationService.OpType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -35,6 +41,8 @@ import java.util.List;
public class State implements android.os.Parcelable {
+ private static final String TAG = "State";
+
public static final int ACTION_OPEN = 1;
public static final int ACTION_CREATE = 2;
public static final int ACTION_GET_CONTENT = 3;
@@ -77,23 +85,34 @@ public class State implements android.os.Parcelable {
public boolean forceAdvanced;
public boolean showAdvanced;
public boolean restored;
+
+ // Indicates that a copy operation (or move) includes a directory.
+ // Why? Directory creation isn't supported by some roots (like Downloads).
+ // This allows us to restrict available roots to just those with support.
public boolean directoryCopy;
public boolean openableOnly;
- /** Transfer mode for file copy/move operations. */
- public int transferMode;
+
+ /**
+ * This is basically a sub-type for the copy operation. It can be either COPY or MOVE.
+ * The only legal values, if set, are: OPERATION_COPY, OPERATION_MOVE. Other pick
+ * operations don't use this. In those cases OPERATION_UNKNOWN is also legal.
+ */
+ public @OpType int copyOperationSubType = FileOperationService.OPERATION_UNKNOWN;
/** Current user navigation stack; empty implies recents. */
public DocumentStack stack = new DocumentStack();
private boolean mStackTouched;
-
- /** Currently active search, overriding any stack. */
- public String currentSearch;
+ private boolean mInitialRootChanged;
+ private boolean mInitialDocChanged;
/** Instance state for every shown directory */
public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
+ /** UI selection */
+ public Selection selectedDocuments = new Selection();
+
/** Currently copying file */
- public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+ public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<>();
/** Name of the package that started DocsUI */
public List<String> excludedAuthorities = new ArrayList<>();
@@ -108,30 +127,46 @@ public class State implements android.os.Parcelable {
}
public void onRootChanged(RootInfo root) {
+ if (DEBUG) Log.d(TAG, "Root changed to: " + root);
+ if (!mInitialRootChanged && stack.root != null && !root.equals(stack.root)) {
+ mInitialRootChanged = true;
+ }
stack.root = root;
stack.clear();
mStackTouched = true;
}
public void pushDocument(DocumentInfo info) {
+ if (DEBUG) Log.d(TAG, "Adding doc to stack: " + info);
+ if (!mInitialDocChanged && stack.size() > 0 && !info.equals(stack.peek())) {
+ mInitialDocChanged = true;
+ }
stack.push(info);
mStackTouched = true;
}
public void popDocument() {
+ if (DEBUG) Log.d(TAG, "Popping doc off stack.");
stack.pop();
mStackTouched = true;
}
public void setStack(DocumentStack stack) {
+ if (DEBUG) Log.d(TAG, "Setting the whole darn stack to: " + stack);
this.stack = stack;
mStackTouched = true;
}
+ // This will return true even when the initial location is set.
+ // To get a read on if the user has changed something, use #hasInitialLocationChanged.
public boolean hasLocationChanged() {
return mStackTouched;
}
+ public boolean hasInitialLocationChanged() {
+ return mInitialRootChanged || mInitialDocChanged;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -150,12 +185,14 @@ public class State implements android.os.Parcelable {
out.writeInt(showAdvanced ? 1 : 0);
out.writeInt(restored ? 1 : 0);
DurableUtils.writeToParcel(out, stack);
- out.writeString(currentSearch);
out.writeMap(dirState);
+ out.writeParcelable(selectedDocuments, 0);
out.writeList(selectedDocumentsForCopy);
out.writeList(excludedAuthorities);
out.writeInt(openableOnly ? 1 : 0);
out.writeInt(mStackTouched ? 1 : 0);
+ out.writeInt(mInitialRootChanged ? 1 : 0);
+ out.writeInt(mInitialDocChanged ? 1 : 0);
}
public static final ClassLoaderCreator<State> CREATOR = new ClassLoaderCreator<State>() {
@@ -178,12 +215,14 @@ public class State implements android.os.Parcelable {
state.showAdvanced = in.readInt() != 0;
state.restored = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
- state.currentSearch = in.readString();
in.readMap(state.dirState, loader);
+ state.selectedDocuments = in.readParcelable(loader);
in.readList(state.selectedDocumentsForCopy, loader);
in.readList(state.excludedAuthorities, loader);
state.openableOnly = in.readInt() != 0;
state.mStackTouched = in.readInt() != 0;
+ state.mInitialRootChanged = in.readInt() != 0;
+ state.mInitialDocChanged = in.readInt() != 0;
return state;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 70bee3cd3c6e..dfceff8d22b0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -23,20 +23,19 @@ import static com.android.documentsui.State.MODE_LIST;
import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
-import static com.google.common.base.Preconditions.checkArgument;
+import android.annotation.IntDef;
import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ClipData;
-import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
@@ -51,11 +50,10 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
+import android.support.v13.view.DragStartHelper;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
-import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -73,7 +71,6 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.TextView;
@@ -89,57 +86,72 @@ import com.android.documentsui.Menus;
import com.android.documentsui.MessageBar;
import com.android.documentsui.MimePredicate;
import com.android.documentsui.R;
-import com.android.documentsui.RecentLoader;
+import com.android.documentsui.RecentsLoader;
import com.android.documentsui.RootsCache;
import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.State;
+import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperationService.OpType;
import com.android.documentsui.services.FileOperations;
+
import com.google.common.collect.Lists;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Display the documents inside a single directory.
*/
-public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
-
+public class DirectoryFragment extends Fragment
+ implements DocumentsAdapter.Environment, LoaderCallbacks<DirectoryResult> {
+
+ @IntDef(flag = true, value = {
+ TYPE_NORMAL,
+ TYPE_RECENT_OPEN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultType {}
public static final int TYPE_NORMAL = 1;
- public static final int TYPE_SEARCH = 2;
- public static final int TYPE_RECENT_OPEN = 3;
-
+ public static final int TYPE_RECENT_OPEN = 2;
+
+ @IntDef(flag = true, value = {
+ ANIM_NONE,
+ ANIM_SIDE,
+ ANIM_LEAVE,
+ ANIM_ENTER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AnimationType {}
public static final int ANIM_NONE = 1;
public static final int ANIM_SIDE = 2;
public static final int ANIM_LEAVE = 3;
public static final int ANIM_ENTER = 4;
+ @IntDef(flag = true, value = {
+ REQUEST_COPY_DESTINATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RequestCode {}
public static final int REQUEST_COPY_DESTINATION = 1;
- static final boolean DEBUG_ENABLE_DND = true;
-
private static final String TAG = "DirectoryFragment";
private static final int LOADER_ID = 42;
- private static final int DELETE_UNDO_TIMEOUT = 5000;
- private static final int DELETE_JOB_DELAY = 5500;
- private static final int EMPTY_REVEAL_DURATION = 250;
-
- private static final String EXTRA_TYPE = "type";
- private static final String EXTRA_ROOT = "root";
- private static final String EXTRA_DOC = "doc";
- private static final String EXTRA_QUERY = "query";
- private static final String EXTRA_IGNORE_STATE = "ignoreState";
private Model mModel;
private MultiSelectManager mSelectionManager;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
private ItemEventListener mItemEventListener = new ItemEventListener();
+ private FocusManager mFocusManager;
private IconHelper mIconHelper;
@@ -147,22 +159,26 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
private RecyclerView mRecView;
private ListeningGestureDetector mGestureDetector;
- private int mType = TYPE_NORMAL;
private String mStateKey;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
private DocumentsAdapter mAdapter;
- private LoaderCallbacks<DirectoryResult> mCallbacks;
private FragmentTuner mTuner;
private DocumentClipper mClipper;
- // These are lazily initialized.
- private LinearLayoutManager mListLayout;
- private GridLayoutManager mGridLayout;
+ private GridLayoutManager mLayout;
private int mColumnCount = 1; // This will get updated when layout changes.
private MessageBar mMessageBar;
private View mProgressBar;
+ // Directory fragment state is defined by: root, document, query, type, selection
+ private @ResultType int mType = TYPE_NORMAL;
+ private RootInfo mRoot;
+ private DocumentInfo mDocument;
+ private String mQuery = null;
+ private Selection mSelection = null;
+ private boolean mSearchMode = false;
+
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -173,7 +189,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
mEmptyView = view.findViewById(android.R.id.empty);
- mRecView = (RecyclerView) view.findViewById(R.id.list);
+ mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
mRecView.setRecyclerListener(
new RecyclerListener() {
@Override
@@ -182,35 +198,18 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
});
- // TODO: Rather than update columns on layout changes, push this
- // code (or something like it) into GridLayoutManager.
- mRecView.addOnLayoutChangeListener(
- new View.OnLayoutChangeListener() {
-
- @Override
- public void onLayoutChange(
- View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- mColumnCount = calculateColumnCount();
- if (mGridLayout != null) {
- mGridLayout.setSpanCount(mColumnCount);
- }
- }
- });
-
mRecView.setItemAnimator(new DirectoryItemAnimator(getActivity()));
- // TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
- if (DEBUG_ENABLE_DND) {
- setupDragAndDropOnDirectoryView(mRecView);
- }
+ // Make the recycler and the empty views responsive to drop events.
+ mRecView.setOnDragListener(mOnDragListener);
+ mEmptyView.setOnDragListener(mOnDragListener);
return view;
}
@Override
public void onDestroyView() {
- super.onDestroyView();
+ mSelectionManager.clearSelection();
// Cancel any outstanding thumbnail requests
final int count = mRecView.getChildCount();
@@ -219,8 +218,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
cancelThumbnailTask(view);
}
- // Clear any outstanding selection
- mSelectionManager.clearSelection();
+ super.onDestroyView();
}
@Override
@@ -230,8 +228,16 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
final Context context = getActivity();
final State state = getDisplayState();
- final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
- final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+ // Read arguments when object created for the first time.
+ // Restore state if fragment recreated.
+ Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;
+ mRoot = args.getParcelable(Shared.EXTRA_ROOT);
+ mDocument = args.getParcelable(Shared.EXTRA_DOC);
+ mStateKey = buildStateKey(mRoot, mDocument);
+ mQuery = args.getString(Shared.EXTRA_QUERY);
+ mType = args.getInt(Shared.EXTRA_TYPE);
+ mSelection = args.getParcelable(Shared.EXTRA_SELECTION);
+ mSearchMode = args.getBoolean(Shared.EXTRA_SEARCH_MODE);
mIconHelper = new IconHelper(context, MODE_GRID);
@@ -240,7 +246,15 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
mRecView.setAdapter(mAdapter);
- mGestureDetector = new ListeningGestureDetector(this.getContext(), new GestureListener());
+ mLayout = new GridLayoutManager(getContext(), mColumnCount);
+ SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
+ if (lookup != null) {
+ mLayout.setSpanSizeLookup(lookup);
+ }
+ mRecView.setLayoutManager(mLayout);
+
+ mGestureDetector =
+ new ListeningGestureDetector(this.getContext(), mDragHelper, new GestureListener());
mRecView.addOnItemTouchListener(mGestureDetector);
@@ -252,17 +266,19 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
mAdapter,
state.allowMultiple
? MultiSelectManager.MODE_MULTIPLE
- : MultiSelectManager.MODE_SINGLE);
+ : MultiSelectManager.MODE_SINGLE,
+ null);
+
mSelectionManager.addCallback(new SelectionModeListener());
mModel = new Model();
mModel.addUpdateListener(mAdapter);
mModel.addUpdateListener(mModelUpdateListener);
- mType = getArguments().getInt(EXTRA_TYPE);
- mStateKey = buildStateKey(root, doc);
+ // Make sure this is done after the RecyclerView is set up.
+ mFocusManager = new FocusManager(context, mRecView, mModel);
- mTuner = FragmentTuner.pick(state);
+ mTuner = FragmentTuner.pick(getContext(), state);
mClipper = new DocumentClipper(context);
boolean hideGridTitles;
@@ -271,7 +287,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
hideGridTitles = MimePredicate.mimeMatches(
MimePredicate.VISUAL_MIMES, state.acceptMimes);
} else {
- hideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+ hideGridTitles = (mDocument != null) && mDocument.isGridTitlesHidden();
}
GridDocumentHolder.setHideTitles(hideGridTitles);
@@ -280,90 +296,44 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
boolean svelte = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
mIconHelper.setThumbnailsEnabled(!svelte);
- mCallbacks = new LoaderCallbacks<DirectoryResult>() {
- @Override
- public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
- final String query = getArguments().getString(EXTRA_QUERY);
-
- Uri contentsUri;
- switch (mType) {
- case TYPE_NORMAL:
- contentsUri = DocumentsContract.buildChildDocumentsUri(
- doc.authority, doc.documentId);
- if (state.action == ACTION_MANAGE) {
- contentsUri = DocumentsContract.setManageMode(contentsUri);
- }
- return new DirectoryLoader(
- context, mType, root, doc, contentsUri, state.userSortOrder);
- case TYPE_SEARCH:
- contentsUri = DocumentsContract.buildSearchDocumentsUri(
- root.authority, root.rootId, query);
- if (state.action == ACTION_MANAGE) {
- contentsUri = DocumentsContract.setManageMode(contentsUri);
- }
- return new DirectoryLoader(
- context, mType, root, doc, contentsUri, state.userSortOrder);
- case TYPE_RECENT_OPEN:
- final RootsCache roots = DocumentsApplication.getRootsCache(context);
- return new RecentLoader(context, roots, state);
- default:
- throw new IllegalStateException("Unknown type " + mType);
- }
- }
-
- @Override
- public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
- if (!isAdded()) return;
-
- mModel.update(result);
- state.derivedSortOrder = result.sortOrder;
-
- updateDisplayState();
-
- // When launched into empty recents, show drawer
- if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.hasLocationChanged() &&
- context instanceof DocumentsActivity) {
- ((DocumentsActivity) context).setRootsDrawerOpen(true);
- }
+ // Kick off loader at least once
+ getLoaderManager().restartLoader(LOADER_ID, null, this);
+ }
- // Restore any previous instance state
- final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
- if (container != null && !getArguments().getBoolean(EXTRA_IGNORE_STATE, false)) {
- getView().restoreHierarchyState(container);
- } else if (mLastSortOrder != state.derivedSortOrder) {
- // The derived sort order takes the user sort order into account, but applies
- // directory-specific defaults when the user doesn't explicitly set the sort
- // order. Scroll to the top if the sort order actually changed.
- mRecView.smoothScrollToPosition(0);
- }
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
- mLastSortOrder = state.derivedSortOrder;
- }
+ mSelectionManager.getSelection(mSelection);
- @Override
- public void onLoaderReset(Loader<DirectoryResult> loader) {
- mModel.update(null);
- }
- };
+ outState.putInt(Shared.EXTRA_TYPE, mType);
+ outState.putParcelable(Shared.EXTRA_ROOT, mRoot);
+ outState.putParcelable(Shared.EXTRA_DOC, mDocument);
+ outState.putString(Shared.EXTRA_QUERY, mQuery);
+ outState.putParcelable(Shared.EXTRA_SELECTION, mSelection);
+ outState.putBoolean(Shared.EXTRA_SEARCH_MODE, mSearchMode);
- // Kick off loader at least once
- getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
}
@Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- // There's only one request code right now. Replace this with a switch statement or
- // something more scalable when more codes are added.
- if (requestCode != REQUEST_COPY_DESTINATION) {
- return;
+ public void onActivityResult(@RequestCode int requestCode, int resultCode, Intent data) {
+ switch(requestCode) {
+ case REQUEST_COPY_DESTINATION:
+ handleCopyResult(resultCode, data);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown request code: " + requestCode);
}
+ }
+
+ private void handleCopyResult(int resultCode, Intent data) {
if (resultCode == Activity.RESULT_CANCELED || data == null) {
// User pressed the back button or otherwise cancelled the destination pick. Don't
// proceed with the copy.
return;
}
- int operationType = data.getIntExtra(
+ @OpType int operationType = data.getIntExtra(
FileOperationService.EXTRA_OPERATION,
FileOperationService.OPERATION_COPY);
@@ -387,7 +357,9 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
private boolean handleViewItem(String id) {
final Cursor cursor = mModel.getItem(id);
- checkNotNull(cursor, "Cursor cannot be null.");
+
+ assert(cursor != null);
+
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
if (mTuner.isDocumentEnabled(docMimeType, docFlags)) {
@@ -417,7 +389,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
public void onSortOrderChanged() {
// Sort order is implemented as a sorting wrapper around directory
// results. So when sort order changes, we force a reload of the directory.
- getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
+ getLoaderManager().restartLoader(LOADER_ID, null, this);
}
public void onViewModeChanged() {
@@ -432,60 +404,46 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
/**
- * Returns a {@code LayoutManager} for {@code mode}, lazily initializing
- * classes as needed.
+ * Updates the layout after the view mode switches.
+ * @param mode The new view mode.
*/
- private void updateLayout(int mode) {
- final LayoutManager layout;
- switch (mode) {
- case MODE_GRID:
- if (mGridLayout == null) {
- mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
- SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
- if (lookup != null) {
- mGridLayout.setSpanSizeLookup(lookup);
- }
- }
- layout = mGridLayout;
- break;
- case MODE_LIST:
- if (mListLayout == null) {
- mListLayout = new LinearLayoutManager(getContext());
- }
- layout = mListLayout;
- break;
- default:
- throw new IllegalArgumentException("Unsupported layout mode: " + mode);
+ private void updateLayout(@ViewMode int mode) {
+ mColumnCount = calculateColumnCount(mode);
+ if (mLayout != null) {
+ mLayout.setSpanCount(mColumnCount);
}
int pad = getDirectoryPadding(mode);
mRecView.setPadding(pad, pad, pad, pad);
- // setting layout manager automatically invalidates existing ViewHolders.
- mRecView.setLayoutManager(layout);
+ mRecView.requestLayout();
mSelectionManager.handleLayoutChanged(); // RecyclerView doesn't do this for us
mIconHelper.setViewMode(mode);
}
- private int calculateColumnCount() {
+ private int calculateColumnCount(@ViewMode int mode) {
+ if (mode == MODE_LIST) {
+ // List mode is a "grid" with 1 column.
+ return 1;
+ }
+
int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width);
int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
- checkState(mRecView.getWidth() > 0);
+ assert(mRecView.getWidth() > 0);
+
int columnCount = Math.max(1,
(mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
return columnCount;
}
- private int getDirectoryPadding(int mode) {
+ private int getDirectoryPadding(@ViewMode int mode) {
switch (mode) {
case MODE_GRID:
- return getResources().getDimensionPixelSize(
- R.dimen.grid_container_padding);
+ return getResources().getDimensionPixelSize(R.dimen.grid_container_padding);
case MODE_LIST:
- return getResources().getDimensionPixelSize(
- R.dimen.list_container_padding);
+ return getResources().getDimensionPixelSize(R.dimen.list_container_padding);
default:
throw new IllegalArgumentException("Unsupported layout mode: " + mode);
}
@@ -514,7 +472,9 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
public boolean onBeforeItemStateChange(String modelId, boolean selected) {
if (selected) {
final Cursor cursor = mModel.getItem(modelId);
- checkNotNull(cursor, "Cursor cannot be null.");
+
+ assert(cursor != null);
+
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
return mTuner.canSelectType(docMimeType, docFlags);
@@ -525,13 +485,18 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
@Override
public void onItemStateChanged(String modelId, boolean selected) {
final Cursor cursor = mModel.getItem(modelId);
- checkNotNull(cursor, "Cursor cannot be null.");
+ if (cursor == null) {
+ Log.e(TAG, "Model returned null cursor for document: " + modelId
+ + ". Ignoring state changed event.");
+ return;
+ }
// TODO: Should this be happening in onSelectionChanged? Technically this callback is
// triggered on "silent" selection updates (i.e. we might be reacting to unfinalized
// selection changes here)
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
- if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) {
+ if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0
+ && (docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) {
mNoDeleteCount += selected ? 1 : -1;
}
if ((docFlags & Document.FLAG_SUPPORTS_RENAME) != 0) {
@@ -602,7 +567,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
private void updateActionMenu() {
- checkNotNull(mMenu);
+ assert(mMenu != null);
// Delegate update logic to our owning action, since specialized logic is desired.
mTuner.updateActionMenu(mMenu, mType, canDeleteSelection(), canRenameSelection());
@@ -737,54 +702,36 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
private void deleteDocuments(final Selection selected) {
+ assert(!selected.isEmpty());
- checkArgument(!selected.isEmpty());
final DocumentInfo srcParent = getDisplayState().stack.peek();
new GetDocumentsTask() {
@Override
- void onDocumentsReady(List<DocumentInfo> docs) {
- // Hide the files in the UI.
- final SparseArray<String> hidden = mAdapter.hide(selected.getAll());
-
- checkState(DELETE_JOB_DELAY > DELETE_UNDO_TIMEOUT);
- String operationId = FileOperations.delete(
- getActivity(), docs, srcParent, getDisplayState().stack,
- DELETE_JOB_DELAY);
- showDeleteSnackbar(hidden, operationId);
- }
- }.execute(selected);
- }
-
- private void showDeleteSnackbar(final SparseArray<String> hidden, final String jobId) {
-
- Context context = getActivity();
- String message = Shared.getQuantityString(context, R.plurals.deleting, hidden.size());
-
- // Show a snackbar informing the user that files will be deleted, and give them an option to
- // cancel.
- final Activity activity = getActivity();
- Snackbars.makeSnackbar(activity, message, DELETE_UNDO_TIMEOUT)
- .setAction(
- R.string.undo,
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {}
- })
- .setCallback(
- new Snackbar.Callback() {
- @Override
- public void onDismissed(Snackbar snackbar, int event) {
- if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
- // If the delete was cancelled, just unhide the files.
- FileOperations.cancel(activity, jobId);
- mAdapter.unhide(hidden);
- }
+ void onDocumentsReady(final List<DocumentInfo> docs) {
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.delete_confirmation_title)
+ .setMessage(
+ Shared.getQuantityString(
+ getActivity(),
+ R.plurals.delete_confirmation_message,
+ docs.size()))
+ .setPositiveButton(
+ android.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ // Hide the files in the UI.
+ mAdapter.hide(selected.getAll());
+ FileOperations.delete(
+ getActivity(), docs, srcParent, getDisplayState().stack);
}
})
- .show();
+ .setNegativeButton(android.R.string.no, null)
+ .show();
+ }
+ }.execute(selected);
}
- private void transferDocuments(final Selection selected, final int mode) {
+ private void transferDocuments(final Selection selected, final @OpType int mode) {
// Pop up a dialog to pick a destination. This is inadequate but works for now.
// TODO: Implement a picker that is to spec.
final Intent intent = new Intent(
@@ -793,29 +740,47 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
getActivity(),
DocumentsActivity.class);
+ // Set an appropriate title on the drawer when it is shown in the picker.
+ // Coupled with the fact that we auto-open the drawer for copy/move operations
+ // it should basically be the thing people see first.
+ int drawerTitleId = mode == FileOperationService.OPERATION_MOVE
+ ? R.string.menu_move : R.string.menu_copy;
+ intent.putExtra(DocumentsContract.EXTRA_PROMPT, getResources().getString(drawerTitleId));
+
new GetDocumentsTask() {
@Override
void onDocumentsReady(List<DocumentInfo> docs) {
+ // TODO: Can this move to Fragment bundle state?
getDisplayState().selectedDocumentsForCopy = docs;
- boolean directoryCopy = false;
- for (DocumentInfo info : docs) {
- if (Document.MIME_TYPE_DIR.equals(info.mimeType)) {
- directoryCopy = true;
- break;
- }
- }
- intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, directoryCopy);
+ // Determine if there is a directory in the set of documents
+ // to be copied? Why? Directory creation isn't supported by some roots
+ // (like Downloads). This informs DocumentsActivity (the "picker")
+ // to restrict available roots to just those with support.
+ intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
+
+ // This just identifies the type of request...we'll check it
+ // when we reveive a response.
startActivityForResult(intent, REQUEST_COPY_DESTINATION);
}
+
}.execute(selected);
}
+ private static boolean hasDirectory(List<DocumentInfo> docs) {
+ for (DocumentInfo info : docs) {
+ if (Document.MIME_TYPE_DIR.equals(info.mimeType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void renameDocuments(Selection selected) {
// Batch renaming not supported
// Rename option is only available in menu when 1 document selected
- checkArgument(selected.size() == 1);
+ assert(selected.size() == 1);
new GetDocumentsTask() {
@Override
@@ -828,13 +793,12 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
@Override
public void initDocumentHolder(DocumentHolder holder) {
holder.addEventListener(mItemEventListener);
+ holder.itemView.setOnFocusChangeListener(mFocusManager);
}
@Override
public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {
- if (DEBUG_ENABLE_DND) {
- setupDragAndDropOnDocumentView(holder.itemView, cursor);
- }
+ setupDragAndDropOnDocumentView(holder.itemView, cursor);
}
@Override
@@ -876,22 +840,15 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
msgView.setText(msg);
imageView.setImageResource(drawable);
- content.animate().cancel(); // cancel any ongoing animations
-
- content.setAlpha(0);
mEmptyView.setVisibility(View.VISIBLE);
+ mEmptyView.requestFocus();
mRecView.setVisibility(View.GONE);
-
- // fade in the content, so it looks purdy like
- content.animate()
- .alpha(1f)
- .setDuration(EMPTY_REVEAL_DURATION)
- .setListener(null);
}
private void showDirectory() {
mEmptyView.setVisibility(View.GONE);
mRecView.setVisibility(View.VISIBLE);
+ mRecView.requestFocus();
}
private String findCommonMimeType(List<String> mimeTypes) {
@@ -936,7 +893,8 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
private void copyFromClipData(final ClipData clipData, final DocumentInfo destination) {
- checkNotNull(clipData);
+ assert(clipData != null);
+
new AsyncTask<Void, Void, List<DocumentInfo>>() {
@Override
@@ -952,7 +910,8 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) {
- if (!canCopy(docs, destination)) {
+ BaseActivity activity = (BaseActivity) getActivity();
+ if (!canCopy(docs, activity.getCurrentRoot(), destination)) {
Snackbars.makeSnackbar(
getActivity(),
R.string.clipboard_files_cannot_paste,
@@ -977,25 +936,6 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
FileOperations.copy(getActivity(), docs, tmpStack);
}
- private ClipData getClipDataFromDocuments(List<DocumentInfo> docs) {
- Context context = getActivity();
- final ContentResolver resolver = context.getContentResolver();
- ClipData clipData = null;
- for (DocumentInfo doc : docs) {
- final Uri uri = DocumentsContract.buildDocumentUri(doc.authority, doc.documentId);
- if (clipData == null) {
- // TODO: figure out what this string should be.
- // Currently it is not displayed anywhere in the UI, but this might change.
- final String label = "";
- clipData = ClipData.newUri(resolver, label, uri);
- } else {
- // TODO: update list of mime types in ClipData.
- clipData.addItem(new ClipData.Item(uri));
- }
- }
- return clipData;
- }
-
public void copySelectedToClipboard() {
Selection selection = mSelectionManager.getSelection(new Selection());
if (!selection.isEmpty()) {
@@ -1005,7 +945,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
void copySelectionToClipboard(Selection selection) {
- checkArgument(!selection.isEmpty());
+ assert(!selection.isEmpty());
new GetDocumentsTask() {
@Override
void onDocumentsReady(List<DocumentInfo> docs) {
@@ -1032,13 +972,13 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
*
* @return true if the list of files can be copied to destination.
*/
- boolean canCopy(List<DocumentInfo> files, DocumentInfo dest) {
- BaseActivity activity = (BaseActivity) getActivity();
-
- final RootInfo root = activity.getCurrentRoot();
+ private boolean canCopy(List<DocumentInfo> files, RootInfo root, DocumentInfo dest) {
+ if (dest == null || !dest.isDirectory() || !dest.isCreateSupported()) {
+ return false;
+ }
- // Can't copy folders to Downloads.
- if (root.isDownloads()) {
+ // Can't copy folders to downloads, because we don't show folders there.
+ if (!root.isDownloads()) {
for (DocumentInfo docs : files) {
if (docs.isDirectory()) {
return false;
@@ -1046,7 +986,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
}
- return dest != null && dest.isDirectory() && dest.isCreateSupported();
+ return true;
}
public void selectAllFiles() {
@@ -1057,9 +997,11 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
}
- private void setupDragAndDropOnDirectoryView(View view) {
- // Listen for drops on non-directory items and empty space.
- view.setOnDragListener(mOnDragListener);
+ /**
+ * Attempts to restore focus on the directory listing.
+ */
+ public void requestFocus() {
+ mFocusManager.restoreLastFocus();
}
private void setupDragAndDropOnDocumentView(View view, Cursor cursor) {
@@ -1070,7 +1012,8 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
view.setOnDragListener(mOnDragListener);
}
- view.setOnLongClickListener(mLongClickListener);
+ // Make all items draggable.
+ view.setOnLongClickListener(mDragHelper);
}
private View.OnDragListener mOnDragListener = new View.OnDragListener() {
@@ -1081,28 +1024,66 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
// TODO: Check if the event contains droppable data.
return true;
- // TODO: Highlight potential drop target directory?
// TODO: Expand drop target directory on hover?
case DragEvent.ACTION_DRAG_ENTERED:
- case DragEvent.ACTION_DRAG_LOCATION:
+ setDropTargetHighlight(v, true);
+ return true;
case DragEvent.ACTION_DRAG_EXITED:
+ setDropTargetHighlight(v, false);
+ return true;
+
+ case DragEvent.ACTION_DRAG_LOCATION:
+ return true;
+
case DragEvent.ACTION_DRAG_ENDED:
+ if (event.getResult()) {
+ // Exit selection mode if the drop was handled.
+ mSelectionManager.clearSelection();
+ }
return true;
case DragEvent.ACTION_DROP:
- String dstId = getModelId(v);
- DocumentInfo dstDir = null;
- if (dstId != null) {
- Cursor dstCursor = mModel.getItem(dstId);
- checkNotNull(dstCursor, "Cursor cannot be null.");
- dstDir = DocumentInfo.fromDirectoryCursor(dstCursor);
- // TODO: Do not drop into the directory where the documents came from.
+ // After a drop event, always stop highlighting the target.
+ setDropTargetHighlight(v, false);
+ // Don't copy from the cwd into the cwd. Note: this currently doesn't work for
+ // multi-window drag, because localState isn't carried over from one process to
+ // another.
+ Object src = event.getLocalState();
+ DocumentInfo dst = getDestination(v);
+ if (Objects.equals(src, dst)) {
+ return false;
}
- copyFromClipData(event.getClipData(), dstDir);
+ copyFromClipData(event.getClipData(), dst);
return true;
}
return false;
}
+
+ private DocumentInfo getDestination(View v) {
+ String id = getModelId(v);
+ if (id != null) {
+ Cursor dstCursor = mModel.getItem(id);
+ assert(dstCursor != null);
+ return DocumentInfo.fromDirectoryCursor(dstCursor);
+ }
+
+ if (v == mRecView || v == mEmptyView) {
+ return getDisplayState().stack.peek();
+ }
+
+ return null;
+ }
+
+ private void setDropTargetHighlight(View v, boolean highlight) {
+ // Note: use exact comparison - this code is searching for views which are children of
+ // the RecyclerView instance in the UI.
+ if (v.getParent() == mRecView) {
+ RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(v);
+ if (vh instanceof DocumentHolder) {
+ ((DocumentHolder) vh).setHighlighted(highlight);
+ }
+ }
+ }
};
/**
@@ -1128,21 +1109,14 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
* a document item view.
*/
private String getModelId(View view) {
- while (true) {
- if (view.getLayoutParams() instanceof RecyclerView.LayoutParams) {
- RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
- if (vh instanceof DocumentHolder) {
- return ((DocumentHolder) vh).modelId;
- } else {
- return null;
- }
+ View itemView = mRecView.findContainingItemView(view);
+ if (itemView != null) {
+ RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(itemView);
+ if (vh instanceof DocumentHolder) {
+ return ((DocumentHolder) vh).modelId;
}
- ViewParent parent = view.getParent();
- if (parent == null || !(parent instanceof View)) {
- return null;
- }
- view = (View) parent;
}
+ return null;
}
private List<DocumentInfo> getDraggableDocuments(View currentItemView) {
@@ -1162,10 +1136,11 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
final Cursor cursor = mModel.getItem(modelId);
- checkNotNull(cursor, "Cursor cannot be null.");
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- return Lists.newArrayList(doc);
+ assert(cursor != null);
+
+ return Lists.newArrayList(
+ DocumentInfo.fromDirectoryCursor(cursor));
}
private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
@@ -1255,119 +1230,43 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
return false;
}
- boolean handled = false;
- if (Events.isNavigationKeyCode(keyCode)) {
- // Find the target item and focus it.
- int endPos = findTargetPosition(doc.itemView, keyCode);
-
- if (endPos != RecyclerView.NO_POSITION) {
- focusItem(endPos);
+ // Ignore tab key events. Those should be handled by the top-level key handler.
+ if (keyCode == KeyEvent.KEYCODE_TAB) {
+ return false;
+ }
- // Handle any necessary adjustments to selection.
- boolean extendSelection = event.isShiftPressed();
- if (extendSelection) {
- int startPos = doc.getAdapterPosition();
- mSelectionManager.selectRange(startPos, endPos);
+ if (mFocusManager.handleKey(doc, keyCode, event)) {
+ // Handle range selection adjustments. Extending the selection will adjust the
+ // bounds of the in-progress range selection. Each time an unshifted navigation
+ // event is received, the range selection is restarted.
+ if (shouldExtendSelection(event)) {
+ if (!mSelectionManager.isRangeSelectionActive()) {
+ // Start a range selection if one isn't active
+ mSelectionManager.startRangeSelection(doc.getAdapterPosition());
}
- handled = true;
- }
- } else {
- // Handle enter key events
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- handled = onActivate(doc);
+ mSelectionManager.snapRangeSelection(mFocusManager.getFocusPosition());
+ } else {
+ mSelectionManager.endRangeSelection();
}
+ return true;
}
- return handled;
- }
-
- /**
- * Finds the destination position where the focus should land for a given navigation event.
- *
- * @param view The view that received the event.
- * @param keyCode The key code for the event.
- * @return The adapter position of the destination item. Could be RecyclerView.NO_POSITION.
- */
- private int findTargetPosition(View view, int keyCode) {
- if (keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
- return 0;
- }
-
- if (keyCode == KeyEvent.KEYCODE_MOVE_END) {
- return mAdapter.getItemCount() - 1;
- }
-
- // Find a navigation target based on the arrow key that the user pressed.
- int searchDir = -1;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- searchDir = View.FOCUS_UP;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- searchDir = View.FOCUS_DOWN;
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- searchDir = View.FOCUS_LEFT;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- searchDir = View.FOCUS_RIGHT;
- break;
- }
-
- if (searchDir != -1) {
- View targetView = view.focusSearch(searchDir);
- // TargetView can be null, for example, if the user pressed <down> at the bottom
- // of the list.
- if (targetView != null) {
- // Ignore navigation targets that aren't items in the RecyclerView.
- if (targetView.getParent() == mRecView) {
- return mRecView.getChildAdapterPosition(targetView);
- }
+ // Handle enter key events
+ if (keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (event.isShiftPressed()) {
+ return onSelect(doc);
+ } else {
+ return onActivate(doc);
}
}
- return RecyclerView.NO_POSITION;
+ return false;
}
- /**
- * Requests focus for the item in the given adapter position, scrolling the RecyclerView if
- * necessary.
- *
- * @param pos
- */
- public void focusItem(final int pos) {
- // If the item is already in view, focus it; otherwise, scroll to it and focus it.
- RecyclerView.ViewHolder vh = mRecView.findViewHolderForAdapterPosition(pos);
- if (vh != null) {
- vh.itemView.requestFocus();
- } else {
- mRecView.smoothScrollToPosition(pos);
- // Set a one-time listener to request focus when the scroll has completed.
- mRecView.addOnScrollListener(
- new RecyclerView.OnScrollListener() {
- @Override
- public void onScrollStateChanged (RecyclerView view, int newState) {
- if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- // When scrolling stops, find the item and focus it.
- RecyclerView.ViewHolder vh =
- view.findViewHolderForAdapterPosition(pos);
- if (vh != null) {
- vh.itemView.requestFocus();
- } else {
- // This might happen in weird corner cases, e.g. if the user is
- // scrolling while a delete operation is in progress. In that
- // case, just don't attempt to focus the missing item.
- Log.w(
- TAG, "Unable to focus position " + pos + " after a scroll");
- }
- view.removeOnScrollListener(this);
- }
- }
- });
- }
+ private boolean shouldExtendSelection(KeyEvent event) {
+ return Events.isNavigationKeyCode(event.getKeyCode()) &&
+ event.isShiftPressed();
}
-
-
}
private final class ModelUpdateListener implements Model.UpdateListener {
@@ -1382,7 +1281,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
if (model.isEmpty()) {
- if (getDisplayState().currentSearch != null) {
+ if (mSearchMode) {
showNoResults(getDisplayState().stack.root);
} else {
showEmptyDirectory();
@@ -1399,18 +1298,18 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
}
- private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {
+ private DragStartHelper mDragHelper = new DragStartHelper(null) {
@Override
- public boolean onLongClick(View v) {
- if (mGestureDetector.mouseSpawnedLastEvent()) {
+ protected boolean onDragStart(View v) {
+ if (isSelected(getModelId(v))) {
List<DocumentInfo> docs = getDraggableDocuments(v);
if (docs.isEmpty()) {
return false;
}
- v.startDrag(
- getClipDataFromDocuments(docs),
+ v.startDragAndDrop(
+ mClipper.getClipDataForDocuments(docs),
new DrawableShadowBuilder(getDragShadowIcon(docs)),
- null,
+ getDisplayState().stack.peek(),
View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
View.DRAG_FLAG_GLOBAL_URI_WRITE
);
@@ -1428,9 +1327,12 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
implements OnItemTouchListener {
private int mLastTool = -1;
+ private DragStartHelper mDragHelper;
- public ListeningGestureDetector(Context context, GestureListener listener) {
+ public ListeningGestureDetector(
+ Context context, DragStartHelper dragHelper, GestureListener listener) {
super(context, listener);
+ mDragHelper = dragHelper;
setOnDoubleTapListener(listener);
}
@@ -1445,12 +1347,27 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
mLastTool = e.getToolType(0);
- onTouchEvent(e); // bounce this forward to our detecty heart
+
+ // Detect drag events. When a drag is detected, intercept the rest of the gesture.
+ View itemView = rv.findChildViewUnder(e.getX(), e.getY());
+ if (itemView != null && mDragHelper.handleTouch(itemView, e)) {
+ return true;
+ }
+ // Forward unhandled events to the GestureDetector.
+ onTouchEvent(e);
+
return false;
}
@Override
- public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
+ public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+ View itemView = rv.findChildViewUnder(e.getX(), e.getY());
+ mDragHelper.handleTouch(itemView, e);
+ // Note: even though this event is being handled as part of a drag gesture, continue
+ // forwarding to the GestureDetector. The detector needs to see the entire cluster of
+ // events in order to properly interpret gestures.
+ onTouchEvent(e);
+ }
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
@@ -1508,32 +1425,51 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
public static void showDirectory(
FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
- show(fm, TYPE_NORMAL, root, doc, null, anim);
+ create(fm, TYPE_NORMAL, root, doc, null, anim);
}
- public static void showSearch(FragmentManager fm, RootInfo root, String query, int anim) {
- show(fm, TYPE_SEARCH, root, null, query, anim);
+ public static void showRecentsOpen(FragmentManager fm, int anim) {
+ create(fm, TYPE_RECENT_OPEN, null, null, null, anim);
}
- public static void showRecentsOpen(FragmentManager fm, int anim) {
- show(fm, TYPE_RECENT_OPEN, null, null, null, anim);
+ public static void reloadSearch(FragmentManager fm, RootInfo root, DocumentInfo doc,
+ String query) {
+ DirectoryFragment df = get(fm);
+
+ df.mQuery = query;
+ df.mRoot = root;
+ df.mDocument = doc;
+ df.mSearchMode = query != null;
+ df.getLoaderManager().restartLoader(LOADER_ID, null, df);
}
- private static void show(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+ public static void reload(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
+ String query) {
+ DirectoryFragment df = get(fm);
+ df.mType = type;
+ df.mQuery = query;
+ df.mRoot = root;
+ df.mDocument = doc;
+ df.mSearchMode = query != null;
+ df.getLoaderManager().restartLoader(LOADER_ID, null, df);
+ }
+
+ public static void create(FragmentManager fm, int type, RootInfo root, DocumentInfo doc,
String query, int anim) {
final Bundle args = new Bundle();
- args.putInt(EXTRA_TYPE, type);
- args.putParcelable(EXTRA_ROOT, root);
- args.putParcelable(EXTRA_DOC, doc);
- args.putString(EXTRA_QUERY, query);
+ args.putInt(Shared.EXTRA_TYPE, type);
+ args.putParcelable(Shared.EXTRA_ROOT, root);
+ args.putParcelable(Shared.EXTRA_DOC, doc);
+ args.putString(Shared.EXTRA_QUERY, query);
+ args.putParcelable(Shared.EXTRA_SELECTION, new Selection());
final FragmentTransaction ft = fm.beginTransaction();
switch (anim) {
case ANIM_SIDE:
- args.putBoolean(EXTRA_IGNORE_STATE, true);
+ args.putBoolean(Shared.EXTRA_IGNORE_STATE, true);
break;
case ANIM_ENTER:
- args.putBoolean(EXTRA_IGNORE_STATE, true);
+ args.putBoolean(Shared.EXTRA_IGNORE_STATE, true);
ft.setCustomAnimations(R.animator.dir_enter, R.animator.dir_frozen);
break;
case ANIM_LEAVE:
@@ -1544,7 +1480,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
final DirectoryFragment fragment = new DirectoryFragment();
fragment.setArguments(args);
- ft.replace(R.id.container_directory, fragment);
+ ft.replace(getFragmentId(), fragment);
ft.commitAllowingStateLoss();
}
@@ -1558,9 +1494,78 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
public static @Nullable DirectoryFragment get(FragmentManager fm) {
// TODO: deal with multiple directories shown at once
- Fragment fragment = fm.findFragmentById(R.id.container_directory);
+ Fragment fragment = fm.findFragmentById(getFragmentId());
return fragment instanceof DirectoryFragment
? (DirectoryFragment) fragment
: null;
}
-}
+
+ private static int getFragmentId() {
+ return R.id.container_directory;
+ }
+
+ @Override
+ public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
+ Context context = getActivity();
+ State state = getDisplayState();
+
+ Uri contentsUri;
+ switch (mType) {
+ case TYPE_NORMAL:
+ contentsUri = mSearchMode ? DocumentsContract.buildSearchDocumentsUri(
+ mRoot.authority, mRoot.rootId, mQuery)
+ : DocumentsContract.buildChildDocumentsUri(
+ mDocument.authority, mDocument.documentId);
+ if (state.action == ACTION_MANAGE) {
+ contentsUri = DocumentsContract.setManageMode(contentsUri);
+ }
+ return new DirectoryLoader(
+ context, mType, mRoot, mDocument, contentsUri, state.userSortOrder,
+ mSearchMode);
+ case TYPE_RECENT_OPEN:
+ final RootsCache roots = DocumentsApplication.getRootsCache(context);
+ return new RecentsLoader(context, roots, state);
+ default:
+ throw new IllegalStateException("Unknown type " + mType);
+ }
+ }
+
+ @Override
+ public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
+ if (!isAdded()) return;
+
+ State state = getDisplayState();
+
+ mAdapter.notifyDataSetChanged();
+ mModel.update(result);
+
+ state.derivedSortOrder = result.sortOrder;
+
+ updateLayout(state.derivedMode);
+
+ if (mSelection != null) {
+ mSelectionManager.setItemsSelected(mSelection.toList(), true);
+ }
+
+ // Restore any previous instance state
+ final SparseArray<Parcelable> container = state.dirState.remove(mStateKey);
+ if (container != null && !getArguments().getBoolean(Shared.EXTRA_IGNORE_STATE, false)) {
+ getView().restoreHierarchyState(container);
+ } else if (mLastSortOrder != state.derivedSortOrder) {
+ // The derived sort order takes the user sort order into account, but applies
+ // directory-specific defaults when the user doesn't explicitly set the sort
+ // order. Scroll to the top if the sort order actually changed.
+ mRecView.smoothScrollToPosition(0);
+ }
+
+ mLastSortOrder = state.derivedSortOrder;
+
+ mTuner.onModelLoaded(mModel, mType, mSearchMode);
+
+ }
+
+ @Override
+ public void onLoaderReset(Loader<DirectoryResult> loader) {
+ mModel.update(null);
+ }
+ }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
index 1bfc6e909c5a..3b5ce87ebfb0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -16,9 +16,6 @@
package com.android.documentsui.dirlist;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
-
import android.content.Context;
import android.database.Cursor;
import android.graphics.Rect;
@@ -75,27 +72,42 @@ public abstract class DocumentHolder
*/
public abstract void bind(Cursor cursor, String modelId, State state);
+ /**
+ * Makes the associated item view appear selected. Note that this merely affects the appearance
+ * of the view, it doesn't actually select the item.
+ *
+ * @param selected
+ */
public void setSelected(boolean selected) {
itemView.setActivated(selected);
itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
}
+ /**
+ * Highlights the associated item view.
+ * @param highlighted
+ */
+ public void setHighlighted(boolean highlighted) {
+ itemView.setBackgroundColor(highlighted ? mSelectedItemColor : mDefaultItemColor);
+ }
+
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// Event listener should always be set.
- checkNotNull(mEventListener);
+ assert(mEventListener != null);
+
return mEventListener.onKey(this, keyCode, event);
}
public void addEventListener(DocumentHolder.EventListener listener) {
// Just handle one for now; switch to a list if necessary.
- checkState(mEventListener == null);
+ assert(mEventListener == null);
mEventListener = listener;
}
public void addOnKeyListener(View.OnKeyListener listener) {
// Just handle one for now; switch to a list if necessary.
- checkState(mKeyListener == null);
+ assert(mKeyListener == null);
mKeyListener = listener;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
index 43c2f6386347..0930c22b356c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -27,7 +27,6 @@ import android.util.SparseArray;
import com.android.documentsui.State;
-import java.nio.channels.UnsupportedAddressTypeException;
import java.util.List;
/**
@@ -87,7 +86,7 @@ abstract class DocumentsAdapter
* we adjust sizes.
*/
GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
- throw new UnsupportedAddressTypeException();
+ throw new UnsupportedOperationException();
}
static boolean isDirectory(Cursor cursor) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
new file mode 100644
index 000000000000..ac05c0570a46
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
@@ -0,0 +1,561 @@
+/*
+ * 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.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.method.KeyListener;
+import android.text.method.TextKeyListener;
+import android.text.method.TextKeyListener.Capitalize;
+import android.text.style.BackgroundColorSpan;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.documentsui.Events;
+import com.android.documentsui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * A class that handles navigation and focus within the DirectoryFragment.
+ */
+class FocusManager implements View.OnFocusChangeListener {
+ private static final String TAG = "FocusManager";
+
+ private RecyclerView mView;
+ private DocumentsAdapter mAdapter;
+ private GridLayoutManager mLayout;
+
+ private TitleSearchHelper mSearchHelper;
+ private Model mModel;
+
+ private int mLastFocusPosition = RecyclerView.NO_POSITION;
+
+ public FocusManager(Context context, RecyclerView view, Model model) {
+ mView = view;
+ mAdapter = (DocumentsAdapter) view.getAdapter();
+ mLayout = (GridLayoutManager) view.getLayoutManager();
+ mModel = model;
+
+ mSearchHelper = new TitleSearchHelper(context);
+ }
+
+ /**
+ * Handles navigation (setting focus, adjusting selection if needed) arising from incoming key
+ * events.
+ *
+ * @param doc The DocumentHolder receiving the key event.
+ * @param keyCode
+ * @param event
+ * @return Whether the event was handled.
+ */
+ public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ // Search helper gets first crack, for doing type-to-focus.
+ if (mSearchHelper.handleKey(doc, keyCode, event)) {
+ return true;
+ }
+
+ // Translate space/shift-space into PgDn/PgUp
+ if (keyCode == KeyEvent.KEYCODE_SPACE) {
+ if (event.isShiftPressed()) {
+ keyCode = KeyEvent.KEYCODE_PAGE_UP;
+ } else {
+ keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
+ }
+ }
+
+ if (Events.isNavigationKeyCode(keyCode)) {
+ // Find the target item and focus it.
+ int endPos = findTargetPosition(doc.itemView, keyCode, event);
+
+ if (endPos != RecyclerView.NO_POSITION) {
+ focusItem(endPos);
+ }
+ // Swallow all navigation keystrokes. Otherwise they go to the app's global
+ // key-handler, which will route them back to the DF and cause focus to be reset.
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ // Remember focus events on items.
+ if (hasFocus && v.getParent() == mView) {
+ mLastFocusPosition = mView.getChildAdapterPosition(v);
+ }
+ }
+
+ /**
+ * Requests focus on the item that last had focus. Scrolls to that item if necessary.
+ */
+ public void restoreLastFocus() {
+ if (mAdapter.getItemCount() == 0) {
+ // Nothing to focus.
+ return;
+ }
+
+ if (mLastFocusPosition != RecyclerView.NO_POSITION) {
+ // The system takes care of situations when a view is no longer on screen, etc,
+ focusItem(mLastFocusPosition);
+ } else {
+ // Focus the first visible item
+ focusItem(mLayout.findFirstVisibleItemPosition());
+ }
+ }
+
+ /**
+ * @return The adapter position of the last focused item.
+ */
+ public int getFocusPosition() {
+ return mLastFocusPosition;
+ }
+
+ /**
+ * Finds the destination position where the focus should land for a given navigation event.
+ *
+ * @param view The view that received the event.
+ * @param keyCode The key code for the event.
+ * @param event
+ * @return The adapter position of the destination item. Could be RecyclerView.NO_POSITION.
+ */
+ private int findTargetPosition(View view, int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ return 0;
+ case KeyEvent.KEYCODE_MOVE_END:
+ return mAdapter.getItemCount() - 1;
+ case KeyEvent.KEYCODE_PAGE_UP:
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ return findPagedTargetPosition(view, keyCode, event);
+ }
+
+ // Find a navigation target based on the arrow key that the user pressed.
+ int searchDir = -1;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP:
+ searchDir = View.FOCUS_UP;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ searchDir = View.FOCUS_DOWN;
+ break;
+ }
+
+ if (inGridMode()) {
+ int currentPosition = mView.getChildAdapterPosition(view);
+ // Left and right arrow keys only work in grid mode.
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (currentPosition > 0) {
+ // Stop backward focus search at the first item, otherwise focus will wrap
+ // around to the last visible item.
+ searchDir = View.FOCUS_BACKWARD;
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (currentPosition < mAdapter.getItemCount() - 1) {
+ // Stop forward focus search at the last item, otherwise focus will wrap
+ // around to the first visible item.
+ searchDir = View.FOCUS_FORWARD;
+ }
+ break;
+ }
+ }
+
+ if (searchDir != -1) {
+ // Focus search behaves badly if the parent RecyclerView is focused. However, focusable
+ // shouldn't be unset on RecyclerView, otherwise focus isn't properly restored after
+ // events that cause a UI rebuild (like rotating the device). Compromise: turn focusable
+ // off while performing the focus search.
+ // TODO: Revisit this when RV focus issues are resolved.
+ mView.setFocusable(false);
+ View targetView = view.focusSearch(searchDir);
+ mView.setFocusable(true);
+ // TargetView can be null, for example, if the user pressed <down> at the bottom
+ // of the list.
+ if (targetView != null) {
+ // Ignore navigation targets that aren't items in the RecyclerView.
+ if (targetView.getParent() == mView) {
+ return mView.getChildAdapterPosition(targetView);
+ }
+ }
+ }
+
+ return RecyclerView.NO_POSITION;
+ }
+
+ /**
+ * Given a PgUp/PgDn event and the current view, find the position of the target view.
+ * This returns:
+ * <li>The position of the topmost (or bottom-most) visible item, if the current item is not
+ * the top- or bottom-most visible item.
+ * <li>The position of an item that is one page's worth of items up (or down) if the current
+ * item is the top- or bottom-most visible item.
+ * <li>The first (or last) item, if paging up (or down) would go past those limits.
+ * @param view The view that received the key event.
+ * @param keyCode Must be KEYCODE_PAGE_UP or KEYCODE_PAGE_DOWN.
+ * @param event
+ * @return The adapter position of the target item.
+ */
+ private int findPagedTargetPosition(View view, int keyCode, KeyEvent event) {
+ int first = mLayout.findFirstVisibleItemPosition();
+ int last = mLayout.findLastVisibleItemPosition();
+ int current = mView.getChildAdapterPosition(view);
+ int pageSize = last - first + 1;
+
+ if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
+ if (current > first) {
+ // If the current item isn't the first item, target the first item.
+ return first;
+ } else {
+ // If the current item is the first item, target the item one page up.
+ int target = current - pageSize;
+ return target < 0 ? 0 : target;
+ }
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) {
+ if (current < last) {
+ // If the current item isn't the last item, target the last item.
+ return last;
+ } else {
+ // If the current item is the last item, target the item one page down.
+ int target = current + pageSize;
+ int max = mAdapter.getItemCount() - 1;
+ return target < max ? target : max;
+ }
+ }
+
+ throw new IllegalArgumentException("Unsupported keyCode: " + keyCode);
+ }
+
+ /**
+ * Requests focus for the item in the given adapter position, scrolling the RecyclerView if
+ * necessary.
+ *
+ * @param pos
+ */
+ private void focusItem(final int pos) {
+ focusItem(pos, null);
+ }
+
+ /**
+ * Requests focus for the item in the given adapter position, scrolling the RecyclerView if
+ * necessary.
+ *
+ * @param pos
+ * @param callback A callback to call after the given item has been focused.
+ */
+ private void focusItem(final int pos, @Nullable final FocusCallback callback) {
+ // If the item is already in view, focus it; otherwise, scroll to it and focus it.
+ RecyclerView.ViewHolder vh = mView.findViewHolderForAdapterPosition(pos);
+ if (vh != null) {
+ if (vh.itemView.requestFocus() && callback != null) {
+ callback.onFocus(vh.itemView);
+ }
+ } else {
+ // Set a one-time listener to request focus when the scroll has completed.
+ mView.addOnScrollListener(
+ new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView view, int newState) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ // When scrolling stops, find the item and focus it.
+ RecyclerView.ViewHolder vh =
+ view.findViewHolderForAdapterPosition(pos);
+ if (vh != null) {
+ if (vh.itemView.requestFocus() && callback != null) {
+ callback.onFocus(vh.itemView);
+ }
+ } else {
+ // This might happen in weird corner cases, e.g. if the user is
+ // scrolling while a delete operation is in progress. In that
+ // case, just don't attempt to focus the missing item.
+ Log.w(TAG, "Unable to focus position " + pos + " after scroll");
+ }
+ view.removeOnScrollListener(this);
+ }
+ }
+ });
+ mView.smoothScrollToPosition(pos);
+ }
+ }
+
+ /**
+ * @return Whether the layout manager is currently in a grid-configuration.
+ */
+ private boolean inGridMode() {
+ return mLayout.getSpanCount() > 1;
+ }
+
+ private interface FocusCallback {
+ public void onFocus(View view);
+ }
+
+ /**
+ * A helper class for handling type-to-focus. Instantiate this class, and pass it KeyEvents via
+ * the {@link #handleKey(DocumentHolder, int, KeyEvent)} method. The class internally will build
+ * up a string from individual key events, and perform searching based on that string. When an
+ * item is found that matches the search term, that item will be focused. This class also
+ * highlights instances of the search term found in the view.
+ */
+ private class TitleSearchHelper {
+ static private final int SEARCH_TIMEOUT = 500; // ms
+
+ private final KeyListener mTextListener = new TextKeyListener(Capitalize.NONE, false);
+ private final Editable mSearchString = Editable.Factory.getInstance().newEditable("");
+ private final Highlighter mHighlighter = new Highlighter();
+ private final BackgroundColorSpan mSpan;
+
+ private List<String> mIndex;
+ private boolean mActive;
+ private Timer mTimer;
+ private KeyEvent mLastEvent;
+ private Handler mUiRunner;
+
+ public TitleSearchHelper(Context context) {
+ mSpan = new BackgroundColorSpan(context.getColor(R.color.accent_dark));
+ // Handler for running things on the main UI thread. Needed for updating the UI from a
+ // timer (see #activate, below).
+ mUiRunner = new Handler(Looper.getMainLooper());
+ }
+
+ /**
+ * Handles alphanumeric keystrokes for type-to-focus. This method builds a search term out
+ * of individual key events, and then performs a search for the given string.
+ *
+ * @param doc The document holder receiving the key event.
+ * @param keyCode
+ * @param event
+ * @return Whether the event was handled.
+ */
+ public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_ESCAPE:
+ case KeyEvent.KEYCODE_ENTER:
+ if (mActive) {
+ // These keys end any active searches.
+ endSearch();
+ return true;
+ } else {
+ // Don't handle these key events if there is no active search.
+ return false;
+ }
+ case KeyEvent.KEYCODE_SPACE:
+ // This allows users to search for files with spaces in their names, but ignores
+ // spacebar events when a text search is not active. Ignoring the spacebar
+ // event is necessary because other handlers (see FocusManager#handleKey) also
+ // listen for and handle it.
+ if (!mActive) {
+ return false;
+ }
+ }
+
+ // Navigation keys also end active searches.
+ if (Events.isNavigationKeyCode(keyCode)) {
+ endSearch();
+ // Don't handle the keycode, so navigation still occurs.
+ return false;
+ }
+
+ // Build up the search string, and perform the search.
+ boolean handled = mTextListener.onKeyDown(doc.itemView, mSearchString, keyCode, event);
+
+ // Delete is processed by the text listener, but not "handled". Check separately for it.
+ if (keyCode == KeyEvent.KEYCODE_DEL) {
+ handled = true;
+ }
+
+ if (handled) {
+ mLastEvent = event;
+ if (mSearchString.length() == 0) {
+ // Don't perform empty searches.
+ return false;
+ }
+ search();
+ }
+
+ return handled;
+ }
+
+ /**
+ * Activates the search helper, which changes its key handling and updates the search index
+ * and highlights if necessary. Call this each time the search term is updated.
+ */
+ private void search() {
+ if (!mActive) {
+ // The model listener invalidates the search index when the model changes.
+ mModel.addUpdateListener(mModelListener);
+
+ // Used to keep the current search alive until the timeout expires. If the user
+ // presses another key within that time, that keystroke is added to the current
+ // search. Otherwise, the current search ends, and subsequent keystrokes start a new
+ // search.
+ mTimer = new Timer();
+ mActive = true;
+ }
+
+ // If the search index was invalidated, rebuild it
+ if (mIndex == null) {
+ buildIndex();
+ }
+
+ // Search for the current search term.
+ // Perform case-insensitive search.
+ String searchString = mSearchString.toString().toLowerCase();
+ for (int pos = 0; pos < mIndex.size(); pos++) {
+ String title = mIndex.get(pos);
+ if (title != null && title.startsWith(searchString)) {
+ focusItem(pos, new FocusCallback() {
+ @Override
+ public void onFocus(View view) {
+ mHighlighter.applyHighlight(view);
+ // Using a timer repeat period of SEARCH_TIMEOUT/2 means the amount of
+ // time between the last keystroke and a search expiring is actually
+ // between 500 and 750 ms. A smaller timer period results in less
+ // variability but does more polling.
+ mTimer.schedule(new TimeoutTask(), 0, SEARCH_TIMEOUT / 2);
+ }
+ });
+ break;
+ }
+ }
+ }
+
+ /**
+ * Ends the current search (see {@link #search()}.
+ */
+ private void endSearch() {
+ if (mActive) {
+ mModel.removeUpdateListener(mModelListener);
+ mTimer.cancel();
+ }
+
+ mHighlighter.removeHighlight();
+
+ mIndex = null;
+ mSearchString.clear();
+ mActive = false;
+ }
+
+ /**
+ * Builds a search index for finding items by title. Queries the model and adapter, so both
+ * must be set up before calling this method.
+ */
+ private void buildIndex() {
+ int itemCount = mAdapter.getItemCount();
+ List<String> index = new ArrayList<>(itemCount);
+ for (int i = 0; i < itemCount; i++) {
+ String modelId = mAdapter.getModelId(i);
+ if (modelId != null) {
+ String title =
+ getCursorString(mModel.getItem(modelId), Document.COLUMN_DISPLAY_NAME);
+ // Perform case-insensitive search.
+ index.add(title.toLowerCase());
+ } else {
+ index.add("");
+ }
+ }
+ mIndex = index;
+ }
+
+ private Model.UpdateListener mModelListener = new Model.UpdateListener() {
+ @Override
+ public void onModelUpdate(Model model) {
+ // Invalidate the search index when the model updates.
+ mIndex = null;
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ // Invalidate the search index when the model updates.
+ mIndex = null;
+ }
+ };
+
+ private class TimeoutTask extends TimerTask {
+ @Override
+ public void run() {
+ long last = mLastEvent.getEventTime();
+ long now = SystemClock.uptimeMillis();
+ if ((now - last) > SEARCH_TIMEOUT) {
+ // endSearch must run on the main thread because it does UI work
+ mUiRunner.post(new Runnable() {
+ @Override
+ public void run() {
+ endSearch();
+ }
+ });
+ }
+ }
+ };
+
+ private class Highlighter {
+ private Spannable mCurrentHighlight;
+
+ /**
+ * Applies title highlights to the given view. The view must have a title field that is a
+ * spannable text field. If this condition is not met, this function does nothing.
+ *
+ * @param view
+ */
+ private void applyHighlight(View view) {
+ TextView titleView = (TextView) view.findViewById(android.R.id.title);
+ if (titleView == null) {
+ return;
+ }
+
+ CharSequence tmpText = titleView.getText();
+ if (tmpText instanceof Spannable) {
+ if (mCurrentHighlight != null) {
+ mCurrentHighlight.removeSpan(mSpan);
+ }
+ mCurrentHighlight = (Spannable) tmpText;
+ mCurrentHighlight.setSpan(
+ mSpan, 0, mSearchString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ /**
+ * Removes title highlights from the given view. The view must have a title field that is a
+ * spannable text field. If this condition is not met, this function does nothing.
+ *
+ * @param view
+ */
+ private void removeHighlight() {
+ if (mCurrentHighlight != null) {
+ mCurrentHighlight.removeSpan(mSpan);
+ }
+ }
+ };
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index a295ab2524fb..f99ec85c358b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -22,17 +22,18 @@ import static com.android.documentsui.State.ACTION_GET_CONTENT;
import static com.android.documentsui.State.ACTION_MANAGE;
import static com.android.documentsui.State.ACTION_OPEN;
import static com.android.documentsui.State.ACTION_OPEN_TREE;
-import static com.android.internal.util.Preconditions.checkArgument;
+import android.content.Context;
+import android.provider.DocumentsContract.Document;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.documentsui.BaseActivity;
import com.android.documentsui.Menus;
import com.android.documentsui.MimePredicate;
import com.android.documentsui.R;
import com.android.documentsui.State;
-
-import android.os.SystemProperties;
-import android.provider.DocumentsContract.Document;
-import android.view.Menu;
-import android.view.MenuItem;
+import com.android.documentsui.dirlist.DirectoryFragment.ResultType;
/**
* Providers support for specializing the DirectoryFragment to the "host" Activity.
@@ -40,26 +41,28 @@ import android.view.MenuItem;
*/
public abstract class FragmentTuner {
+ final Context mContext;
final State mState;
- public FragmentTuner(State state) {
+ public FragmentTuner(Context context, State state) {
+ mContext = context;
mState = state;
}
- public static FragmentTuner pick(State state) {
+ public static FragmentTuner pick(Context context, State state) {
switch (state.action) {
case ACTION_BROWSE:
- return new FilesTuner(state);
+ return new FilesTuner(context, state);
case ACTION_MANAGE:
- return new DownloadsTuner(state);
+ return new DownloadsTuner(context, state);
default:
- return new DocumentsTuner(state);
+ return new DocumentsTuner(context, state);
}
}
- public abstract void updateActionMenu(Menu menu, int dirType, boolean canDelete,
- boolean canRename);
+ public abstract void updateActionMenu(
+ Menu menu, @ResultType int dirType, boolean canDelete, boolean canRename);
// Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
// A folder is enabled such that it may be double clicked, even in settings
@@ -76,13 +79,15 @@ public abstract class FragmentTuner {
return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
}
+ abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
+
/**
* Provides support for Platform specific specializations of DirectoryFragment.
*/
private static final class DocumentsTuner extends FragmentTuner {
- public DocumentsTuner(State state) {
- super(state);
+ public DocumentsTuner(Context context, State state) {
+ super(context, state);
}
@Override
@@ -130,30 +135,28 @@ public abstract class FragmentTuner {
}
@Override
- public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
- boolean canRename) {
-
- boolean copyEnabled = dirType != DirectoryFragment.TYPE_RECENT_OPEN;
- boolean moveEnabled =
- SystemProperties.getBoolean("debug.documentsui.enable_move", false);
- menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
+ public void updateActionMenu(
+ Menu menu, @ResultType int dirType, boolean canDelete, boolean canRename) {
- final MenuItem open = menu.findItem(R.id.menu_open);
- final MenuItem share = menu.findItem(R.id.menu_share);
- final MenuItem delete = menu.findItem(R.id.menu_delete);
- final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
- final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
- final MenuItem rename = menu.findItem(R.id.menu_rename);
+ MenuItem open = menu.findItem(R.id.menu_open);
+ MenuItem share = menu.findItem(R.id.menu_share);
+ MenuItem delete = menu.findItem(R.id.menu_delete);
+ MenuItem rename = menu.findItem(R.id.menu_rename);
open.setVisible(true);
share.setVisible(false);
delete.setVisible(false);
- copyTo.setVisible(copyEnabled);
- copyTo.setEnabled(copyEnabled);
- moveTo.setVisible(moveEnabled);
- moveTo.setEnabled(moveEnabled);
rename.setVisible(false);
}
+
+ @Override
+ void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
+ // When launched into empty root, open drawer.
+ if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
+ // This noops on layouts without drawer, so no need to guard.
+ ((BaseActivity) mContext).setRootsDrawerOpen(true);
+ }
+ }
}
/**
@@ -161,34 +164,34 @@ public abstract class FragmentTuner {
*/
private static final class DownloadsTuner extends FragmentTuner {
- public DownloadsTuner(State state) {
- super(state);
+ public DownloadsTuner(Context context, State state) {
+ super(context, state);
}
@Override
- public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
- boolean canRename) {
- checkArgument(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
-
- boolean moveEnabled =
- SystemProperties.getBoolean("debug.documentsui.enable_move", false);
- menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(true);
-
- final MenuItem open = menu.findItem(R.id.menu_open);
- final MenuItem share = menu.findItem(R.id.menu_share);
- final MenuItem delete = menu.findItem(R.id.menu_delete);
- final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
- final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
- final MenuItem rename = menu.findItem(R.id.menu_rename);
+ public void updateActionMenu(
+ Menu menu, @ResultType int resultType, boolean canDelete, boolean canRename) {
+ assert(resultType != DirectoryFragment.TYPE_RECENT_OPEN);
+
+ MenuItem open = menu.findItem(R.id.menu_open);
+ MenuItem delete = menu.findItem(R.id.menu_delete);
+ MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
+ MenuItem moveTo = menu.findItem(R.id.menu_move_to);
+ MenuItem rename = menu.findItem(R.id.menu_rename);
+ MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
open.setVisible(false);
delete.setVisible(canDelete);
+ copy.setEnabled(true); // to clipboard
copyTo.setVisible(true);
copyTo.setEnabled(true);
- moveTo.setVisible(moveEnabled);
- moveTo.setEnabled(moveEnabled);
+ moveTo.setVisible(true);
+ moveTo.setEnabled(true);
rename.setVisible(false);
}
+
+ @Override
+ void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {}
}
/**
@@ -196,13 +199,13 @@ public abstract class FragmentTuner {
*/
private static final class FilesTuner extends FragmentTuner {
- public FilesTuner(State state) {
- super(state);
+ public FilesTuner(Context context, State state) {
+ super(context, state);
}
@Override
- public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
- boolean canRename) {
+ public void updateActionMenu(
+ Menu menu, @ResultType int dirType, boolean canDelete, boolean canRename) {
MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
@@ -214,13 +217,22 @@ public abstract class FragmentTuner {
menu.findItem(R.id.menu_share).setVisible(true);
menu.findItem(R.id.menu_delete).setVisible(canDelete);
-
menu.findItem(R.id.menu_open).setVisible(false);
menu.findItem(R.id.menu_copy_to).setVisible(true);
menu.findItem(R.id.menu_move_to).setVisible(true);
+ menu.findItem(R.id.menu_move_to).setEnabled(canDelete);
Menus.disableHiddenItems(menu, copy, paste);
}
+
+ @Override
+ void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
+ // When launched into empty root, open drawer.
+ if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
+ // This noops on layouts without drawer, so no need to guard.
+ ((BaseActivity) mContext).setRootsDrawerOpen(true);
+ }
+ }
}
private static boolean isDirectory(String mimeType) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
index e672327dfdae..90b23419fcd3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -17,7 +17,6 @@
package com.android.documentsui.dirlist;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
import android.content.Context;
import android.database.Cursor;
@@ -58,11 +57,12 @@ final class GridDirectoryHolder extends DocumentHolder {
* @param state Current display state.
*/
public void bind(Cursor cursor, String modelId, State state) {
- checkNotNull(cursor, "Cursor cannot be null.");
+ assert(cursor != null);
this.modelId = modelId;
final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
- mTitle.setText(docDisplayName);
+ mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
+
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index c4ac0f515e0f..a4bce1626fb4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -19,7 +19,6 @@ package com.android.documentsui.dirlist;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
import android.content.Context;
import android.database.Cursor;
@@ -32,7 +31,6 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.documentsui.IconUtils;
import com.android.documentsui.R;
import com.android.documentsui.RootCursorWrapper;
import com.android.documentsui.Shared;
@@ -80,9 +78,9 @@ final class GridDocumentHolder extends DocumentHolder {
* @param state Current display state.
*/
public void bind(Cursor cursor, String modelId, State state) {
- this.modelId = modelId;
+ assert(cursor != null);
- checkNotNull(cursor, "Cursor cannot be null.");
+ this.modelId = modelId;
final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
@@ -100,15 +98,14 @@ final class GridDocumentHolder extends DocumentHolder {
mIconThumb.animate().cancel();
mIconThumb.setAlpha(0f);
- mIconMimeSm.setImageDrawable(IconUtils.loadMimeIcon(mContext, docMimeType));
-
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
- mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMimeLg);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMimeLg,
+ mIconMimeSm);
if (mHideTitles) {
mTitle.setVisibility(View.GONE);
} else {
- mTitle.setText(docDisplayName);
+ mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
mTitle.setVisibility(View.VISIBLE);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
index 53ed62e540e4..ff0f4b10b060 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
@@ -32,6 +32,7 @@ import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.ImageView;
@@ -199,11 +200,12 @@ public class IconHelper {
* @param docFlags Flags for the file being represented.
* @param docIcon Custom icon (if any) for the file being requested.
* @param iconThumb The itemview's thumbnail icon.
- * @param iconMime The itemview's mime icon.
+ * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown.
+ * @param subIconMime The second itemview's mime icon. Always visible.
* @return
*/
public void loadThumbnail(Uri uri, String mimeType, int docFlags, int docIcon,
- ImageView iconThumb, ImageView iconMime) {
+ ImageView iconThumb, ImageView iconMime, @Nullable ImageView subIconMime) {
boolean cacheHit = false;
final String docAuthority = uri.getAuthority();
@@ -225,6 +227,12 @@ public class IconHelper {
}
}
+ final Drawable icon = getDocumentIcon(mContext, docAuthority,
+ DocumentsContract.getDocumentId(uri), mimeType, docIcon);
+ if (subIconMime != null) {
+ subIconMime.setImageDrawable(icon);
+ }
+
if (cacheHit) {
iconMime.setImageDrawable(null);
iconMime.setAlpha(0f);
@@ -232,8 +240,7 @@ public class IconHelper {
} else {
// Add a mime icon if the thumbnail is being loaded in the background.
iconThumb.setImageDrawable(null);
- iconMime.setImageDrawable(getDocumentIcon(
- mContext, docAuthority, DocumentsContract.getDocumentId(uri), mimeType, docIcon));
+ iconMime.setImageDrawable(icon);
iconMime.setAlpha(1f);
iconThumb.setAlpha(0f);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 00ea27b8b304..b940ffbcda30 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -19,7 +19,6 @@ package com.android.documentsui.dirlist;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
import android.content.Context;
import android.database.Cursor;
@@ -79,9 +78,9 @@ final class ListDocumentHolder extends DocumentHolder {
*/
@Override
public void bind(Cursor cursor, String modelId, State state) {
- this.modelId = modelId;
+ assert(cursor != null);
- checkNotNull(cursor, "Cursor cannot be null.");
+ this.modelId = modelId;
final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
@@ -101,9 +100,9 @@ final class ListDocumentHolder extends DocumentHolder {
mIconThumb.setAlpha(0f);
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
- mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime, null);
- mTitle.setText(docDisplayName);
+ mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
mTitle.setVisibility(View.VISIBLE);
if (docSummary != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 075b3ea9cdfe..5e55e1a8b9ea 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -22,20 +22,18 @@ import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.State.SORT_ORDER_SIZE;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
import android.database.Cursor;
import android.os.Bundle;
-import android.os.Looper;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.android.documentsui.BaseActivity.SiblingProvider;
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
@@ -48,7 +46,7 @@ import java.util.Map;
* The data model for the current loaded directory.
*/
@VisibleForTesting
-public class Model implements SiblingProvider {
+public class Model {
private static final String TAG = "Model";
private boolean mIsLoading;
@@ -171,7 +169,7 @@ public class Model implements SiblingProvider {
final String displayName = getCursorString(
mCursor, Document.COLUMN_DISPLAY_NAME);
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
- stringValues[pos] = DocumentInfo.DIR_PREFIX + displayName;
+ stringValues[pos] = Shared.DIR_PREFIX + displayName;
} else {
stringValues[pos] = displayName;
}
@@ -228,7 +226,7 @@ public class Model implements SiblingProvider {
final String lhs = pivotValue;
final String rhs = sortKey[mid];
- final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
+ final int compare = Shared.compareToIgnoreCaseNullable(lhs, rhs);
if (compare < 0) {
right = mid;
@@ -358,7 +356,7 @@ public class Model implements SiblingProvider {
return (l == -1) ? Long.MAX_VALUE : l;
}
- @Nullable Cursor getItem(String modelId) {
+ public @Nullable Cursor getItem(String modelId) {
Integer pos = mPositions.get(modelId);
if (pos != null) {
mCursor.moveToPosition(pos);
@@ -381,25 +379,21 @@ public class Model implements SiblingProvider {
final List<DocumentInfo> docs = new ArrayList<>(size);
for (String modelId: items.getAll()) {
final Cursor cursor = getItem(modelId);
- checkNotNull(cursor, "Cursor cannot be null.");
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- docs.add(doc);
- }
- return docs;
- }
+ assert(cursor != null);
- @Override
- public Cursor getCursor() {
- if (Looper.myLooper() != Looper.getMainLooper()) {
- throw new IllegalStateException("Can't call getCursor from non-main thread.");
+ docs.add(DocumentInfo.fromDirectoryCursor(cursor));
}
- return mCursor;
+ return docs;
}
void addUpdateListener(UpdateListener listener) {
mUpdateListeners.add(listener);
}
+ void removeUpdateListener(UpdateListener listener) {
+ mUpdateListeners.remove(listener);
+ }
+
static interface UpdateListener {
/**
* Called when a successful update has occurred.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 69a67111ca38..42dba4591326 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -24,6 +24,7 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.database.Cursor;
import android.provider.DocumentsContract.Document;
+import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.SparseArray;
import android.view.ViewGroup;
@@ -180,9 +181,10 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
return hiddenItems;
}
+ @VisibleForTesting
@Override
public void unhide(SparseArray<String> ids) {
- if (DEBUG) Log.d(TAG, "Un-iding ids: " + ids);
+ if (DEBUG) Log.d(TAG, "Unhiding ids: " + ids);
// An ArrayList can shrink at runtime...and in fact
// it does when we clear it completely.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 516b25e6f572..b0cc09a134f9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -19,13 +19,13 @@ package com.android.documentsui.dirlist;
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.dirlist.ModelBackedDocumentsAdapter.ITEM_TYPE_DIRECTORY;
import static com.android.documentsui.dirlist.ModelBackedDocumentsAdapter.ITEM_TYPE_DOCUMENT;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
+import android.annotation.IntDef;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.GridLayoutManager;
@@ -41,12 +41,13 @@ import com.android.documentsui.Events.InputEvent;
import com.android.documentsui.Events.MotionInputEvent;
import com.android.documentsui.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -58,10 +59,13 @@ import java.util.Set;
*/
public final class MultiSelectManager {
- /** Selection mode for multiple select. **/
+ @IntDef(flag = true, value = {
+ MODE_MULTIPLE,
+ MODE_SINGLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SelectionMode {}
public static final int MODE_MULTIPLE = 0;
-
- /** Selection mode for multiple select. **/
public static final int MODE_SINGLE = 1;
private static final String TAG = "MultiSelectManager";
@@ -79,14 +83,19 @@ public final class MultiSelectManager {
/**
- * @param recyclerView
- * @param mode Selection mode
+ * @param mode Selection single or multiple selection mode.
+ * @param initialSelection selection state probably preserved in external state.
*/
public MultiSelectManager(
- final RecyclerView recyclerView, DocumentsAdapter adapter, int mode) {
- this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode);
+ final RecyclerView recyclerView,
+ DocumentsAdapter adapter,
+ @SelectionMode int mode,
+ @Nullable Selection initialSelection) {
+
+ this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode, initialSelection);
if (mode == MODE_MULTIPLE) {
+ // TODO: Don't load this on low memory devices.
mBandManager = new BandController();
}
@@ -116,10 +125,22 @@ public final class MultiSelectManager {
* @hide
*/
@VisibleForTesting
- MultiSelectManager(SelectionEnvironment environment, DocumentsAdapter adapter, int mode) {
- mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
- mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
+ MultiSelectManager(
+ SelectionEnvironment environment,
+ DocumentsAdapter adapter,
+ @SelectionMode int mode,
+ @Nullable Selection initialSelection) {
+
+ assert(environment != null);
+ assert(adapter != null);
+
+ mEnvironment = environment;
+ mAdapter = adapter;
+
mSingleSelect = mode == MODE_SINGLE;
+ if (initialSelection != null) {
+ mSelection.copyFrom(initialSelection);
+ }
mAdapter.registerAdapterDataObserver(
new RecyclerView.AdapterDataObserver() {
@@ -148,8 +169,8 @@ public final class MultiSelectManager {
@Override
public void onItemRangeRemoved(int startPosition, int itemCount) {
- checkState(startPosition >= 0);
- checkState(itemCount > 0);
+ assert(startPosition >= 0);
+ assert(itemCount > 0);
mSelection.cancelProvisionalSelection();
// Remove any disappeared IDs from the selection.
@@ -203,6 +224,13 @@ public final class MultiSelectManager {
}
/**
+ * Updates selection to include items in {@code selection}.
+ */
+ public void updateSelection(Selection selection) {
+ setItemsSelected(selection.toList(), true);
+ }
+
+ /**
* Sets the selected state of the specified items. Note that the callback will NOT
* be consulted to see if an item can be selected.
*
@@ -329,7 +357,8 @@ public final class MultiSelectManager {
* @param modelId
*/
public void toggleSelection(String modelId) {
- checkNotNull(modelId);
+ assert(modelId != null);
+
boolean changed = false;
if (mSelection.contains(modelId)) {
changed = attemptDeselect(modelId);
@@ -343,39 +372,42 @@ public final class MultiSelectManager {
}
/**
- * Handle a range selection event.
- * <li> If the MSM is currently in single-select mode, only the last item in the range will
- * actually be selected.
- * <li>If a range selection is not already active, one will be started, and the given range of
- * items will be selected. The given startPos becomes the anchor for the range selection.
- * <li>If a range selection is already active, the anchor is not changed. The range is extended
- * from its current anchor to endPos.
+ * Starts a range selection. If a range selection is already active, this will start a new range
+ * selection (which will reset the range anchor).
*
- * @param startPos
- * @param endPos
+ * @param pos The anchor position for the selection range.
*/
- public void selectRange(int startPos, int endPos) {
- // In single-select mode, just select the last item in the range.
- if (mSingleSelect) {
- attemptSelect(mAdapter.getModelId(endPos));
- return;
- }
+ void startRangeSelection(int pos) {
+ attemptSelect(mAdapter.getModelId(pos));
+ setSelectionRangeBegin(pos);
+ }
- // In regular (i.e. multi-select) mode
- if (!isRangeSelectionActive()) {
- // If a range selection isn't active, start one up
- attemptSelect(mAdapter.getModelId(startPos));
- setSelectionRangeBegin(startPos);
- }
- // Extend the range selection
- mRanger.snapSelection(endPos);
+ /**
+ * Sets the end point for the current range selection, started by a call to
+ * {@link #startRangeSelection(int)}. This function should only be called when a range selection
+ * is active (see {@link #isRangeSelectionActive()}. Items in the range [anchor, end] will be
+ * selected.
+ *
+ * @param pos The new end position for the selection range.
+ */
+ void snapRangeSelection(int pos) {
+ assert(mRanger != null);
+
+ mRanger.snapSelection(pos);
notifySelectionChanged();
}
/**
+ * Stops an in-progress range selection.
+ */
+ void endRangeSelection() {
+ mRanger = null;
+ }
+
+ /**
* @return Whether or not there is a current range selection active.
*/
- private boolean isRangeSelectionActive() {
+ boolean isRangeSelectionActive() {
return mRanger != null;
}
@@ -407,7 +439,7 @@ public final class MultiSelectManager {
* @param selected New selection state.
*/
private void updateRange(int begin, int end, boolean selected) {
- checkState(end >= begin);
+ assert(end >= begin);
for (int i = begin; i <= end; i++) {
String id = mAdapter.getModelId(i);
if (id == null) {
@@ -445,7 +477,7 @@ public final class MultiSelectManager {
* @return True if the update was applied.
*/
private boolean attemptDeselect(String id) {
- checkArgument(id != null);
+ assert(id != null);
if (notifyBeforeItemStateChange(id, false)) {
mSelection.remove(id);
notifyItemStateChanged(id, false);
@@ -462,7 +494,7 @@ public final class MultiSelectManager {
* @return True if the update was applied.
*/
private boolean attemptSelect(String id) {
- checkArgument(id != null);
+ assert(id != null);
boolean canSelect = notifyBeforeItemStateChange(id, true);
if (!canSelect) {
return false;
@@ -490,7 +522,7 @@ public final class MultiSelectManager {
* (identified by {@code position}) changes.
*/
private void notifyItemStateChanged(String id, boolean selected) {
- checkArgument(id != null);
+ assert(id != null);
int lastListener = mCallbacks.size() - 1;
for (int i = lastListener; i > -1; i--) {
mCallbacks.get(i).onItemStateChanged(id, selected);
@@ -526,8 +558,8 @@ public final class MultiSelectManager {
}
private void snapSelection(int position) {
- checkState(mRanger != null);
- checkArgument(position != RecyclerView.NO_POSITION);
+ assert(mRanger != null);
+ assert(position != RecyclerView.NO_POSITION);
if (mEnd == UNDEFINED || mEnd == mBegin) {
// Reset mEnd so it can be established in establishRange.
@@ -539,7 +571,7 @@ public final class MultiSelectManager {
}
private void establishRange(int position) {
- checkState(mRanger.mEnd == UNDEFINED);
+ assert(mRanger.mEnd == UNDEFINED);
if (position == mBegin) {
mEnd = position;
@@ -555,8 +587,8 @@ public final class MultiSelectManager {
}
private void reviseRange(int position) {
- checkState(mEnd != UNDEFINED);
- checkState(mBegin != mEnd);
+ assert(mEnd != UNDEFINED);
+ assert(mBegin != mEnd);
if (position == mEnd) {
if (DEBUG) Log.i(TAG, "Skipping no-op revision click on mEndRange.");
@@ -615,7 +647,7 @@ public final class MultiSelectManager {
* Object representing the current selection. Provides read only access
* public access, and private write access.
*/
- public static final class Selection {
+ public static final class Selection implements Parcelable {
// This class tracks selected items by managing two sets: the saved selection, and the total
// selection. Saved selections are those which have been completed by tapping an item or by
@@ -628,14 +660,22 @@ public final class MultiSelectManager {
// item A is tapped (and selected), then an in-progress band select covers A then uncovers
// A, A should still be selected as it has been saved. To ensure this behavior, the saved
// selection must be tracked separately.
- private Set<String> mSavedSelection = new HashSet<>();
- private Set<String> mTotalSelection = new HashSet<>();
+ private final Set<String> mSelection;
+ private final Set<String> mProvisionalSelection;
+ private String mDirectoryKey;
- @VisibleForTesting
- public Selection(String... ids) {
- for (int i = 0; i < ids.length; i++) {
- add(ids[i]);
- }
+ public Selection() {
+ mSelection = new HashSet<String>();
+ mProvisionalSelection = new HashSet<String>();
+ }
+
+ /**
+ * Used by CREATOR.
+ */
+ private Selection(String directoryKey, List<String> selection) {
+ mDirectoryKey = directoryKey;
+ mSelection = new HashSet<String>(selection);
+ mProvisionalSelection = new HashSet<String>();
}
/**
@@ -643,53 +683,70 @@ public final class MultiSelectManager {
* @return true if the position is currently selected.
*/
public boolean contains(@Nullable String id) {
- return mTotalSelection.contains(id);
+ return mSelection.contains(id) || mProvisionalSelection.contains(id);
}
/**
* Returns an unordered array of selected positions.
*/
public String[] getAll() {
- return mTotalSelection.toArray(new String[0]);
+ return toList().toArray(new String[0]);
+ }
+
+ /**
+ * Returns an unordered array of selected positions (including any
+ * provisional selections current in effect).
+ */
+ public List<String> toList() {
+ ArrayList<String> selection = new ArrayList<String>(mSelection);
+ selection.addAll(mProvisionalSelection);
+ return selection;
}
/**
* @return size of the selection.
*/
public int size() {
- return mTotalSelection.size();
+ return mSelection.size() + mProvisionalSelection.size();
}
/**
* @return true if the selection is empty.
*/
public boolean isEmpty() {
- return mTotalSelection.isEmpty();
+ return mSelection.isEmpty() && mProvisionalSelection.isEmpty();
}
/**
* Sets the provisional selection, which is a temporary selection that can be saved,
* canceled, or adjusted at a later time. When a new provision selection is applied, the old
* one (if it exists) is abandoned.
- * @return Array with entry for each position added or removed. Entries which were added
- * contain a value of true, and entries which were removed contain a value of false.
+ * @return Map of ids added or removed. Added ids have a value of true, removed are false.
*/
@VisibleForTesting
- protected Map<String, Boolean> setProvisionalSelection(Set<String> provisionalSelection) {
+ protected Map<String, Boolean> setProvisionalSelection(Set<String> newSelection) {
Map<String, Boolean> delta = new HashMap<>();
- for (String id: mTotalSelection) {
+ for (String id: mProvisionalSelection) {
// Mark each item that used to be in the selection but is unsaved and not in the new
// provisional selection.
- if (!provisionalSelection.contains(id) && !mSavedSelection.contains(id)) {
+ if (!newSelection.contains(id) && !mSelection.contains(id)) {
delta.put(id, false);
}
}
- for (String id: provisionalSelection) {
+ for (String id: mSelection) {
+ // Mark each item that used to be in the selection but is unsaved and not in the new
+ // provisional selection.
+ if (!newSelection.contains(id)) {
+ delta.put(id, false);
+ }
+ }
+
+ for (String id: newSelection) {
// Mark each item that was not previously in the selection but is in the new
// provisional selection.
- if (!mTotalSelection.contains(id)) {
+ if (!mSelection.contains(id) && !mProvisionalSelection.contains(id)) {
delta.put(id, true);
}
}
@@ -700,9 +757,9 @@ public final class MultiSelectManager {
for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
String id = entry.getKey();
if (entry.getValue()) {
- mTotalSelection.add(id);
+ mProvisionalSelection.add(id);
} else {
- mTotalSelection.remove(id);
+ mProvisionalSelection.remove(id);
}
}
@@ -716,7 +773,8 @@ public final class MultiSelectManager {
*/
@VisibleForTesting
protected void applyProvisionalSelection() {
- mSavedSelection = new HashSet<>(mTotalSelection);
+ mSelection.addAll(mProvisionalSelection);
+ mProvisionalSelection.clear();
}
/**
@@ -725,15 +783,14 @@ public final class MultiSelectManager {
*/
@VisibleForTesting
void cancelProvisionalSelection() {
- mTotalSelection = new HashSet<>(mSavedSelection);
+ mProvisionalSelection.clear();
}
/** @hide */
@VisibleForTesting
boolean add(String id) {
- if (!mTotalSelection.contains(id)) {
- mTotalSelection.add(id);
- mSavedSelection.add(id);
+ if (!mSelection.contains(id)) {
+ mSelection.add(id);
return true;
}
return false;
@@ -742,31 +799,32 @@ public final class MultiSelectManager {
/** @hide */
@VisibleForTesting
boolean remove(String id) {
- if (mTotalSelection.contains(id)) {
- mTotalSelection.remove(id);
- mSavedSelection.remove(id);
+ if (mSelection.contains(id)) {
+ mSelection.remove(id);
return true;
}
return false;
}
public void clear() {
- mSavedSelection.clear();
- mTotalSelection.clear();
+ mSelection.clear();
}
/**
* Trims this selection to be the intersection of itself with the set of given IDs.
*/
public void intersect(Collection<String> ids) {
- mSavedSelection.retainAll(ids);
- mTotalSelection.retainAll(ids);
+ mSelection.retainAll(ids);
+ mProvisionalSelection.retainAll(ids);
}
@VisibleForTesting
void copyFrom(Selection source) {
- mSavedSelection = new HashSet<>(source.mSavedSelection);
- mTotalSelection = new HashSet<>(source.mTotalSelection);
+ mSelection.clear();
+ mSelection.addAll(source.mSelection);
+
+ mProvisionalSelection.clear();
+ mProvisionalSelection.addAll(source.mProvisionalSelection);
}
@Override
@@ -775,24 +833,19 @@ public final class MultiSelectManager {
return "size=0, items=[]";
}
- StringBuilder buffer = new StringBuilder(mTotalSelection.size() * 28);
- buffer.append("{size=")
- .append(mTotalSelection.size())
- .append(", ")
- .append("items=[");
- for (Iterator<String> i = mTotalSelection.iterator(); i.hasNext(); ) {
- buffer.append(i.next());
- if (i.hasNext()) {
- buffer.append(", ");
- }
- }
- buffer.append("]}");
+ StringBuilder buffer = new StringBuilder(size() * 28);
+ buffer.append("Selection{")
+ .append("applied{size=" + mSelection.size())
+ .append(", entries=" + mSelection)
+ .append("}, provisional{size=" + mProvisionalSelection.size())
+ .append(", entries=" + mProvisionalSelection)
+ .append("}}");
return buffer.toString();
}
@Override
public int hashCode() {
- return mSavedSelection.hashCode() ^ mTotalSelection.hashCode();
+ return mSelection.hashCode() ^ mProvisionalSelection.hashCode();
}
@Override
@@ -805,9 +858,59 @@ public final class MultiSelectManager {
return false;
}
- return mSavedSelection.equals(((Selection) that).mSavedSelection) &&
- mTotalSelection.equals(((Selection) that).mTotalSelection);
+ return mSelection.equals(((Selection) that).mSelection) &&
+ mProvisionalSelection.equals(((Selection) that).mProvisionalSelection);
+ }
+
+ /**
+ * Sets the state key for this selection, which allows us to match selections
+ * to particular states (of DirectoryFragment). Basically this lets us avoid
+ * loading a persisted selection in the wrong directory.
+ */
+ public void setDirectoryKey(String key) {
+ mDirectoryKey = key;
+ }
+
+ /**
+ * Sets the state key for this selection, which allows us to match selections
+ * to particular states (of DirectoryFragment). Basically this lets us avoid
+ * loading a persisted selection in the wrong directory.
+ */
+ public boolean hasDirectoryKey(String key) {
+ return key.equals(mDirectoryKey);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
}
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mDirectoryKey);
+ dest.writeList(new ArrayList<>(mSelection));
+ // We don't include provisional selection since it is
+ // typically coupled to some other runtime state (like a band).
+ }
+
+ public static final ClassLoaderCreator<Selection> CREATOR =
+ new ClassLoaderCreator<Selection>() {
+ @Override
+ public Selection createFromParcel(Parcel in) {
+ return createFromParcel(in, null);
+ }
+
+ @Override
+ public Selection createFromParcel(Parcel in, ClassLoader loader) {
+ return new Selection(
+ in.readString(),
+ (ArrayList<String>) in.readArrayList(loader));
+ }
+
+ @Override
+ public Selection[] newArray(int size) {
+ return new Selection[size];
+ }
+ };
}
/**
@@ -1085,7 +1188,7 @@ public final class MultiSelectManager {
* @param input
*/
private void processInputEvent(InputEvent input) {
- checkArgument(input.isMouseEvent());
+ assert(input.isMouseEvent());
if (shouldStop(input)) {
endBandSelect();
@@ -1099,7 +1202,6 @@ public final class MultiSelectManager {
}
mCurrentPosition = input.getOrigin();
- mModel.resizeSelection(input.getOrigin());
scrollViewIfNecessary();
resizeBandSelectRectangle();
}
@@ -1388,6 +1490,7 @@ public final class MultiSelectManager {
* top-left of the viewport would have a relative origin of (0, 0), even though its
* absolute point has a higher y-value.
*/
+ @VisibleForTesting
void resizeSelection(Point relativePointer) {
mPointer = mHelper.createAbsolutePoint(relativePointer);
updateModel();
@@ -1515,7 +1618,7 @@ public final class MultiSelectManager {
private void updateSelection(Rect rect) {
int columnStart =
Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
- checkState(columnStart >= 0);
+ assert(columnStart >= 0);
int columnEnd = columnStart;
for (int i = columnStart; i < mColumnBounds.size()
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 0bb682e7c967..0018d01aa85c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -17,7 +17,6 @@
package com.android.documentsui.dirlist;
import static com.android.documentsui.Shared.TAG;
-import static com.android.internal.util.Preconditions.checkArgument;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -38,6 +37,7 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -45,14 +45,17 @@ import android.widget.TextView.OnEditorActionListener;
import com.android.documentsui.BaseActivity;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.R;
+import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.model.DocumentInfo;
+
/**
* Dialog to rename file or directory.
*/
public class RenameDocumentFragment extends DialogFragment {
private static final String TAG_RENAME_DOCUMENT = "rename_document";
private DocumentInfo mDocument;
+ private EditText mEditText;
public static void show(FragmentManager fm, DocumentInfo document) {
final RenameDocumentFragment dialog = new RenameDocumentFragment();
@@ -60,6 +63,11 @@ public class RenameDocumentFragment extends DialogFragment {
dialog.show(fm, TAG_RENAME_DOCUMENT);
}
+ /**
+ * Creates the dialog UI.
+ * @param savedInstanceState
+ * @return
+ */
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
@@ -67,9 +75,7 @@ public class RenameDocumentFragment extends DialogFragment {
LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
View view = dialogInflater.inflate(R.layout.dialog_file_name, null, false);
- final EditText editText = (EditText) view.findViewById(android.R.id.text1);
- editText.setText(mDocument.displayName);
-
+ mEditText = (EditText) view.findViewById(android.R.id.text1);
builder.setTitle(R.string.menu_rename);
builder.setView(view);
@@ -78,7 +84,7 @@ public class RenameDocumentFragment extends DialogFragment {
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- renameDocuments(editText.getText().toString());
+ renameDocuments(mEditText.getText().toString());
}
});
@@ -86,29 +92,100 @@ public class RenameDocumentFragment extends DialogFragment {
final AlertDialog dialog = builder.create();
- editText.setOnEditorActionListener(
+ mEditText.setOnEditorActionListener(
new OnEditorActionListener() {
@Override
public boolean onEditorAction(
TextView view, int actionId, @Nullable KeyEvent event) {
- if (event != null
+ if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER
- && event.hasNoModifiers()) {
- renameDocuments(editText.getText().toString());
+ && event.hasNoModifiers())) {
+ renameDocuments(mEditText.getText().toString());
dialog.dismiss();
return true;
}
return false;
}
});
-
return dialog;
}
+ /**
+ * Sets/Restores the data.
+ * @param savedInstanceState
+ * @return
+ */
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if(savedInstanceState == null) {
+ // Fragment created for the first time, we set the text.
+ // mDocument value was set in show
+ mEditText.setText(mDocument.displayName);
+ }
+ else {
+ // Fragment restored, text was restored automatically.
+ // mDocument value needs to be restored.
+ mDocument = savedInstanceState.getParcelable(Shared.EXTRA_DOC);
+ }
+ // Do selection in both cases, because we cleared it.
+ selectFileName(mEditText);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ // Clear selection before storing state and restore it manually,
+ // because otherwise after rotation selection is displayed with cut/copy menu visible :/
+ clearFileNameSelection(mEditText);
+
+ super.onSaveInstanceState(outState);
+
+ outState.putParcelable(Shared.EXTRA_DOC, mDocument);
+ }
+
+ /**
+ * Validates if string is a proper document name.
+ * Checks if string is not empty. More rules might be added later.
+ * @param docName string representing document name
+ * @returns true if string is a valid name.
+ **/
+ private boolean isValidDocumentName(String docName) {
+ return !docName.isEmpty();
+ }
+
+ /**
+ * Fills text field with the file name and selects the name without extension.
+ *
+ * @param editText text field to be filled
+ */
+ private void selectFileName(EditText editText) {
+ String text = editText.getText().toString();
+ int separatorIndex = text.indexOf(".");
+ editText.setSelection(0,
+ (separatorIndex == -1 || mDocument.isDirectory()) ? text.length() : separatorIndex);
+ }
+
+ /**
+ * Clears selection in text field.
+ *
+ * @param editText text field to be cleared.
+ */
+ private void clearFileNameSelection(EditText editText) {
+ editText.setSelection(0, 0);
+ }
+
private void renameDocuments(String newDisplayName) {
BaseActivity activity = (BaseActivity) getActivity();
- new RenameDocumentsTask(activity, newDisplayName).execute(mDocument);
+ if (isValidDocumentName(newDisplayName)) {
+ new RenameDocumentsTask(activity, newDisplayName).execute(mDocument);
+ } else {
+ Log.w(TAG, "Failed to rename file - invalid name:" + newDisplayName);
+ Snackbars.makeSnackbar(getActivity(), R.string.rename_error,
+ Snackbar.LENGTH_SHORT).show();
+ }
+
}
private class RenameDocumentsTask extends AsyncTask<DocumentInfo, Void, DocumentInfo> {
@@ -127,7 +204,7 @@ public class RenameDocumentFragment extends DialogFragment {
@Override
protected DocumentInfo doInBackground(DocumentInfo... document) {
- checkArgument(document.length == 1);
+ assert(document.length == 1);
final ContentResolver resolver = mActivity.getContentResolver();
ContentProviderClient client = null;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
index 2485ad96a233..3ee5cfc38f8d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -16,8 +16,6 @@
package com.android.documentsui.dirlist;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.content.Context;
import android.database.Cursor;
import android.support.v7.widget.GridLayoutManager;
@@ -204,12 +202,12 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
}
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
- checkArgument(itemCount == 1);
+ assert(itemCount == 1);
notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
}
public void onItemRangeInserted(int positionStart, int itemCount) {
- checkArgument(itemCount == 1);
+ assert(itemCount == 1);
if (positionStart < mBreakPosition) {
mBreakPosition++;
}
@@ -217,7 +215,7 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
- checkArgument(itemCount == 1);
+ assert(itemCount == 1);
if (positionStart < mBreakPosition) {
mBreakPosition--;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 4b5499ab4e80..d74121e536bd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -26,7 +26,6 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsProvider;
import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.RootCursorWrapper;
@@ -38,7 +37,7 @@ import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ProtocolException;
-import java.text.Collator;
+import java.util.Objects;
/**
* Representation of a {@link Document}.
@@ -47,13 +46,6 @@ public class DocumentInfo implements Durable, Parcelable {
private static final int VERSION_INIT = 1;
private static final int VERSION_SPLIT_URI = 2;
- private static final Collator sCollator;
-
- static {
- sCollator = Collator.getInstance();
- sCollator.setStrength(Collator.SECONDARY);
- }
-
public String authority;
public String documentId;
public String mimeType;
@@ -215,7 +207,13 @@ public class DocumentInfo implements Durable, Parcelable {
return "Document{"
+ "docId=" + documentId
+ ", name=" + displayName
+ + ", isContainer=" + isContainer()
+ ", isDirectory=" + isDirectory()
+ + ", isArchive=" + isArchive()
+ + ", isVirtualDocument=" + isVirtualDocument()
+ + ", isDeleteSupported=" + isDeleteSupported()
+ + ", isCreateSupported=" + isCreateSupported()
+ + ", isRenameSupported=" + isRenameSupported()
+ "}";
}
@@ -239,6 +237,10 @@ public class DocumentInfo implements Durable, Parcelable {
return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
}
+ public boolean isRemoveSupported() {
+ return (flags & Document.FLAG_SUPPORTS_REMOVE) != 0;
+ }
+
public boolean isRenameSupported() {
return (flags & Document.FLAG_SUPPORTS_RENAME) != 0;
}
@@ -263,16 +265,23 @@ public class DocumentInfo implements Durable, Parcelable {
return derivedUri.hashCode() + mimeType.hashCode();
}
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (!(other instanceof DocumentInfo)) {
+ public boolean equals(Object o) {
+ if (o == null) {
return false;
}
- DocumentInfo that = (DocumentInfo) other;
- // Uri + mime type should be totally unique.
- return derivedUri.equals(that.derivedUri) && mimeType.equals(that.mimeType);
+ if (this == o) {
+ return true;
+ }
+
+ if (o instanceof DocumentInfo) {
+ DocumentInfo other = (DocumentInfo) o;
+ // Uri + mime type should be totally unique.
+ return Objects.equals(derivedUri, other.derivedUri)
+ && Objects.equals(mimeType, other.mimeType);
+ }
+
+ return false;
}
public static String getCursorString(Cursor cursor, String columnName) {
@@ -312,31 +321,4 @@ public class DocumentInfo implements Durable, Parcelable {
fnfe.initCause(t);
throw fnfe;
}
-
- /**
- * String prefix used to indicate the document is a directory.
- */
- public static final char DIR_PREFIX = '\001';
-
- /**
- * Compare two strings against each other using system default collator in a
- * case-insensitive mode. Clusters strings prefixed with {@link #DIR_PREFIX}
- * before other items.
- */
- public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
- final boolean leftEmpty = TextUtils.isEmpty(lhs);
- final boolean rightEmpty = TextUtils.isEmpty(rhs);
-
- if (leftEmpty && rightEmpty) return 0;
- if (leftEmpty) return -1;
- if (rightEmpty) return 1;
-
- final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
- final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
-
- if (leftDir && !rightDir) return -1;
- if (rightDir && !leftDir) return 1;
-
- return sCollator.compare(lhs, rhs);
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 3f14a5506adf..38970585afc3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -16,10 +16,12 @@
package com.android.documentsui.model;
+import static com.android.documentsui.Shared.compareToIgnoreCaseNullable;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import android.annotation.IntDef;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
@@ -36,17 +38,31 @@ import com.android.documentsui.R;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.ProtocolException;
import java.util.Objects;
/**
* Representation of a {@link Root}.
*/
-public class RootInfo implements Durable, Parcelable {
+public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
private static final int VERSION_INIT = 1;
private static final int VERSION_DROP_TYPE = 2;
// The values of these constants determine the sort order of various roots in the RootsFragment.
+ @IntDef(flag = true, value = {
+ TYPE_IMAGES,
+ TYPE_VIDEO,
+ TYPE_AUDIO,
+ TYPE_RECENTS,
+ TYPE_DOWNLOADS,
+ TYPE_LOCAL,
+ TYPE_MTP,
+ TYPE_OTHER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RootType {}
public static final int TYPE_IMAGES = 1;
public static final int TYPE_VIDEO = 2;
public static final int TYPE_AUDIO = 3;
@@ -69,7 +85,7 @@ public class RootInfo implements Durable, Parcelable {
/** Derived fields that aren't persisted */
public String[] derivedMimeTypes;
public int derivedIcon;
- public int derivedType;
+ public @RootType int derivedType;
public RootInfo() {
reset();
@@ -171,7 +187,7 @@ public class RootInfo implements Durable, Parcelable {
// TODO: remove these special case icons
if (isHome()) {
- derivedIcon = R.drawable.ic_root_home;
+ derivedIcon = R.drawable.ic_root_documents;
derivedType = TYPE_LOCAL;
} else if (isExternalStorage()) {
derivedIcon = R.drawable.ic_root_smartphone;
@@ -241,14 +257,44 @@ public class RootInfo implements Durable, Parcelable {
}
public boolean isLibrary() {
- return derivedType == TYPE_IMAGES || derivedType == TYPE_VIDEO || derivedType == TYPE_AUDIO
- || derivedType == TYPE_RECENTS || derivedType == TYPE_DOWNLOADS;
+ return derivedType == TYPE_IMAGES
+ || derivedType == TYPE_VIDEO
+ || derivedType == TYPE_AUDIO
+ || derivedType == TYPE_RECENTS;
}
public boolean hasSettings() {
return (flags & Root.FLAG_HAS_SETTINGS) != 0;
}
+ public boolean supportsChildren() {
+ return (flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
+ }
+
+ public boolean supportsCreate() {
+ return (flags & Root.FLAG_SUPPORTS_CREATE) != 0;
+ }
+
+ public boolean supportsRecents() {
+ return (flags & Root.FLAG_SUPPORTS_RECENTS) != 0;
+ }
+
+ public boolean supportsSearch() {
+ return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0;
+ }
+
+ public boolean isAdvanced() {
+ return (flags & Root.FLAG_ADVANCED) != 0;
+ }
+
+ public boolean isLocalOnly() {
+ return (flags & Root.FLAG_LOCAL_ONLY) != 0;
+ }
+
+ public boolean isEmpty() {
+ return (flags & Root.FLAG_EMPTY) != 0;
+ }
+
public Drawable loadIcon(Context context) {
if (derivedIcon != 0) {
return context.getDrawable(derivedIcon);
@@ -276,12 +322,21 @@ public class RootInfo implements Durable, Parcelable {
@Override
public boolean equals(Object o) {
- if (o instanceof RootInfo) {
- final RootInfo root = (RootInfo) o;
- return Objects.equals(authority, root.authority) && Objects.equals(rootId, root.rootId);
- } else {
+ if (o == null) {
return false;
}
+
+ if (this == o) {
+ return true;
+ }
+
+ if (o instanceof RootInfo) {
+ RootInfo other = (RootInfo) o;
+ return Objects.equals(authority, other.authority)
+ && Objects.equals(rootId, other.rootId);
+ }
+
+ return false;
}
@Override
@@ -290,6 +345,22 @@ public class RootInfo implements Durable, Parcelable {
}
@Override
+ public int compareTo(RootInfo other) {
+ // Sort by root type, then title, then summary.
+ int score = derivedType - other.derivedType;
+ if (score != 0) {
+ return score;
+ }
+
+ score = compareToIgnoreCaseNullable(title, other.title);
+ if (score != 0) {
+ return score;
+ }
+
+ return compareToIgnoreCaseNullable(summary, other.summary);
+ }
+
+ @Override
public String toString() {
return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index dad86977c7a2..ad48a70c4075 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -29,7 +29,6 @@ import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
-import static com.google.common.base.Preconditions.checkArgument;
import android.annotation.StringRes;
import android.app.Notification;
@@ -67,12 +66,15 @@ import java.util.ArrayList;
import java.util.List;
class CopyJob extends Job {
+
private static final String TAG = "CopyJob";
- private static final int PROGRESS_INTERVAL_MILLIS = 1000;
+ private static final int PROGRESS_INTERVAL_MILLIS = 500;
+
final List<DocumentInfo> mSrcs;
final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>();
private long mStartTime = -1;
+
private long mBatchSize;
private long mBytesCopied;
private long mLastNotificationTime;
@@ -92,7 +94,7 @@ class CopyJob extends Job {
String id, DocumentStack stack, List<DocumentInfo> srcs) {
super(service, appContext, listener, OPERATION_COPY, id, stack);
- checkArgument(!srcs.isEmpty());
+ assert(!srcs.isEmpty());
this.mSrcs = srcs;
}
@@ -105,7 +107,7 @@ class CopyJob extends Job {
@OpType int opType, String id, DocumentStack destination, List<DocumentInfo> srcs) {
super(service, appContext, listener, opType, id, destination);
- checkArgument(!srcs.isEmpty());
+ assert(!srcs.isEmpty());
this.mSrcs = srcs;
}
@@ -129,10 +131,19 @@ class CopyJob extends Job {
}
Notification getProgressNotification(@StringRes int msgId) {
- double completed = (double) this.mBytesCopied / mBatchSize;
- mProgressBuilder.setProgress(100, (int) (completed * 100), false);
- mProgressBuilder.setContentInfo(
- NumberFormat.getPercentInstance().format(completed));
+ if (mBatchSize >= 0) {
+ double completed = (double) this.mBytesCopied / mBatchSize;
+ mProgressBuilder.setProgress(100, (int) (completed * 100), false);
+ mProgressBuilder.setContentInfo(
+ NumberFormat.getPercentInstance().format(completed));
+ } else {
+ // If the total file size failed to compute on some files, then show
+ // an indeterminate spinner. CopyJob would most likely fail on those
+ // files while copying, but would continue with another files.
+ // Also, if the total size is 0 bytes, show an indeterminate spinner.
+ mProgressBuilder.setProgress(0, 0, true);
+ }
+
if (mRemainingTime > 0) {
mProgressBuilder.setContentText(service.getString(msgId,
DateUtils.formatDuration(mRemainingTime)));
@@ -208,11 +219,15 @@ class CopyJob extends Job {
}
@Override
- void start() throws RemoteException {
+ void start() {
mStartTime = elapsedRealtime();
- // client
- mBatchSize = calculateSize(mSrcs);
+ try {
+ mBatchSize = calculateSize(mSrcs);
+ } catch (ResourceException e) {
+ Log.w(TAG, "Failed to calculate total size. Copying without progress.");
+ mBatchSize = -1;
+ }
DocumentInfo srcInfo;
DocumentInfo dstInfo = stack.peek();
@@ -220,9 +235,13 @@ class CopyJob extends Job {
srcInfo = mSrcs.get(i);
// Guard unsupported recursive operation.
- if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
- onFileFailed(srcInfo,
- "Skipping recursive operation on directory " + dstInfo.derivedUri + ".");
+ try {
+ if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
+ throw new ResourceException("Cannot copy to itself recursively.");
+ }
+ } catch (ResourceException e) {
+ Log.e(TAG, e.toString());
+ onFileFailed(srcInfo);
continue;
}
@@ -230,7 +249,12 @@ class CopyJob extends Job {
"Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")"
+ " to " + dstInfo.displayName + " (" + dstInfo.derivedUri + ")");
- processDocument(srcInfo, null, dstInfo);
+ try {
+ processDocument(srcInfo, null, dstInfo);
+ } catch (ResourceException e) {
+ Log.e(TAG, e.toString());
+ onFileFailed(srcInfo);
+ }
}
Metrics.logFileOperation(service, operationType, mSrcs, dstInfo);
}
@@ -259,13 +283,12 @@ class CopyJob extends Job {
* @param src DocumentInfos for the documents to copy.
* @param srcParent DocumentInfo for the parent of the document to process.
* @param dstDirInfo The destination directory.
- * @return True on success, false on failure.
- * @throws RemoteException
+ * @throws ResourceException
*
* TODO: Stop passing srcParent, as it's not used for copy, but for move only.
*/
- boolean processDocument(DocumentInfo src, DocumentInfo srcParent,
- DocumentInfo dstDirInfo) throws RemoteException {
+ void processDocument(DocumentInfo src, DocumentInfo srcParent,
+ DocumentInfo dstDirInfo) throws ResourceException {
// TODO: When optimized copy kicks in, we'll not making any progress updates.
// For now. Local storage isn't using optimized copy.
@@ -274,22 +297,28 @@ class CopyJob extends Job {
// If not supported, then fallback to byte-by-byte copy/move.
if (src.authority.equals(dstDirInfo.authority)) {
if ((src.flags & Document.FLAG_SUPPORTS_COPY) != 0) {
- if (DocumentsContract.copyDocument(getClient(src), src.derivedUri,
- dstDirInfo.derivedUri) == null) {
- onFileFailed(src,
- "Provider side copy failed for documents: " + src.derivedUri + ".");
- return false;
+ try {
+ if (DocumentsContract.copyDocument(getClient(src), src.derivedUri,
+ dstDirInfo.derivedUri) == null) {
+ throw new ResourceException("Provider side copy failed for document %s.",
+ src.derivedUri);
+ }
+ } catch (ResourceException e) {
+ throw e;
+ } catch (RemoteException | RuntimeException e) {
+ throw new ResourceException(
+ "Provider side copy failed for document %s due to an exception.",
+ src.derivedUri, e);
}
- return true;
+ return;
}
}
// If we couldn't do an optimized copy...we fall back to vanilla byte copy.
- return byteCopyDocument(src, dstDirInfo);
+ byteCopyDocument(src, dstDirInfo);
}
- boolean byteCopyDocument(DocumentInfo src, DocumentInfo dest)
- throws RemoteException {
+ void byteCopyDocument(DocumentInfo src, DocumentInfo dest) throws ResourceException {
final String dstMimeType;
final String dstDisplayName;
@@ -297,8 +326,14 @@ class CopyJob extends Job {
// If the file is virtual, but can be converted to another format, then try to copy it
// as such format. Also, append an extension for the target mime type (if known).
if (src.isVirtualDocument()) {
- final String[] streamTypes = getContentResolver().getStreamTypes(
- src.derivedUri, "*/*");
+ String[] streamTypes = null;
+ try {
+ streamTypes = getContentResolver().getStreamTypes(src.derivedUri, "*/*");
+ } catch (RuntimeException e) {
+ throw new ResourceException(
+ "Failed to obtain streamable types for %s due to an exception.",
+ src.derivedUri, e);
+ }
if (streamTypes != null && streamTypes.length > 0) {
dstMimeType = streamTypes[0];
final String extension = MimeTypeMap.getSingleton().
@@ -306,8 +341,8 @@ class CopyJob extends Job {
dstDisplayName = src.displayName +
(extension != null ? "." + extension : src.displayName);
} else {
- onFileFailed(src, "Cannot copy virtual file. No streamable formats available.");
- return false;
+ throw new ResourceException("Cannot copy virtual file %s. No streamable formats "
+ + "available.", src.derivedUri);
}
} else {
dstMimeType = src.mimeType;
@@ -316,33 +351,35 @@ class CopyJob extends Job {
// Create the target document (either a file or a directory), then copy recursively the
// contents (bytes or children).
- final Uri dstUri = DocumentsContract.createDocument(
- getClient(dest), dest.derivedUri, dstMimeType, dstDisplayName);
+ Uri dstUri = null;
+ try {
+ dstUri = DocumentsContract.createDocument(
+ getClient(dest), dest.derivedUri, dstMimeType, dstDisplayName);
+ } catch (RemoteException | RuntimeException e) {
+ throw new ResourceException(
+ "Couldn't create destination document " + dstDisplayName + " in directory %s "
+ + "due to an exception.", dest.derivedUri, e);
+ }
if (dstUri == null) {
// If this is a directory, the entire subdir will not be copied over.
- onFileFailed(src,
- "Couldn't create destination document " + dstDisplayName
- + " in directory " + dest.displayName + ".");
- return false;
+ throw new ResourceException(
+ "Couldn't create destination document " + dstDisplayName + " in directory %s.",
+ dest.derivedUri);
}
DocumentInfo dstInfo = null;
try {
dstInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
- } catch (FileNotFoundException e) {
- onFileFailed(src,
- "Could not load DocumentInfo for newly created file: " + dstUri + ".");
- return false;
+ } catch (FileNotFoundException | RuntimeException e) {
+ throw new ResourceException("Could not load DocumentInfo for newly created file %s.",
+ dstUri);
}
- final boolean success;
if (Document.MIME_TYPE_DIR.equals(src.mimeType)) {
- success = copyDirectoryHelper(src, dstInfo);
+ copyDirectoryHelper(src, dstInfo);
} else {
- success = copyFileHelper(src, dstInfo, dstMimeType);
+ copyFileHelper(src, dstInfo, dest, dstMimeType);
}
-
- return success;
}
/**
@@ -352,11 +389,10 @@ class CopyJob extends Job {
* @param srcDir Info of the directory to copy from. The routine will copy the directory's
* contents, not the directory itself.
* @param destDir Info of the directory to copy to. Must be created beforehand.
- * @return True on success, false if some of the children failed to copy.
- * @throws RemoteException
+ * @throws ResourceException
*/
- private boolean copyDirectoryHelper(DocumentInfo srcDir, DocumentInfo destDir)
- throws RemoteException {
+ private void copyDirectoryHelper(DocumentInfo srcDir, DocumentInfo destDir)
+ throws ResourceException {
// Recurse into directories. Copy children into the new subdirectory.
final String queryColumns[] = new String[] {
Document.COLUMN_DISPLAY_NAME,
@@ -367,106 +403,143 @@ class CopyJob extends Job {
};
Cursor cursor = null;
boolean success = true;
+ // Iterate over srcs in the directory; copy to the destination directory.
+ final Uri queryUri = buildChildDocumentsUri(srcDir.authority, srcDir.documentId);
try {
- // Iterate over srcs in the directory; copy to the destination directory.
- final Uri queryUri = buildChildDocumentsUri(srcDir.authority, srcDir.documentId);
- cursor = getClient(srcDir).query(queryUri, queryColumns, null, null, null);
+ try {
+ cursor = getClient(srcDir).query(queryUri, queryColumns, null, null, null);
+ } catch (RemoteException | RuntimeException e) {
+ throw new ResourceException("Failed to query children of %s due to an exception.",
+ srcDir.derivedUri, e);
+ }
+
+ DocumentInfo src;
while (cursor.moveToNext() && !isCanceled()) {
- DocumentInfo src = DocumentInfo.fromCursor(cursor, srcDir.authority);
- success &= processDocument(src, srcDir, destDir);
+ try {
+ src = DocumentInfo.fromCursor(cursor, srcDir.authority);
+ processDocument(src, srcDir, destDir);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to recursively process a file %s due to an exception."
+ .format(srcDir.derivedUri.toString()), e);
+ success = false;
+ }
}
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to copy a file %s to %s. "
+ .format(srcDir.derivedUri.toString(), destDir.derivedUri.toString()), e);
+ success = false;
} finally {
IoUtils.closeQuietly(cursor);
}
- return success;
+ if (!success) {
+ throw new RuntimeException("Some files failed to copy during a recursive "
+ + "directory copy.");
+ }
}
/**
* Handles copying a single file.
*
- * @param srcUriInfo Info of the file to copy from.
- * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand.
+ * @param src Info of the file to copy from.
+ * @param dest Info of the *file* to copy to. Must be created beforehand.
+ * @param destParent Info of the parent of the destination.
* @param mimeType Mime type for the target. Can be different than source for virtual files.
- * @return True on success, false on error.
- * @throws RemoteException
+ * @throws ResourceException
*/
- private boolean copyFileHelper(DocumentInfo src, DocumentInfo dest, String mimeType)
- throws RemoteException {
+ private void copyFileHelper(DocumentInfo src, DocumentInfo dest, DocumentInfo destParent,
+ String mimeType) throws ResourceException {
CancellationSignal canceller = new CancellationSignal();
+ AssetFileDescriptor srcFileAsAsset = null;
ParcelFileDescriptor srcFile = null;
ParcelFileDescriptor dstFile = null;
InputStream in = null;
OutputStream out = null;
+ boolean success = false;
- boolean success = true;
try {
// If the file is virtual, but can be converted to another format, then try to copy it
// as such format.
if (src.isVirtualDocument()) {
- final AssetFileDescriptor srcFileAsAsset =
- getClient(src).openTypedAssetFileDescriptor(
+ try {
+ srcFileAsAsset = getClient(src).openTypedAssetFileDescriptor(
src.derivedUri, mimeType, null, canceller);
+ } catch (FileNotFoundException | RemoteException | RuntimeException e) {
+ throw new ResourceException("Failed to open a file as asset for %s due to an "
+ + "exception.", src.derivedUri, e);
+ }
srcFile = srcFileAsAsset.getParcelFileDescriptor();
- in = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
+ try {
+ in = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
+ } catch (IOException e) {
+ throw new ResourceException("Failed to open a file input stream for %s due "
+ + "an exception.", src.derivedUri, e);
+ }
} else {
- srcFile = getClient(src).openFile(src.derivedUri, "r", canceller);
+ try {
+ srcFile = getClient(src).openFile(src.derivedUri, "r", canceller);
+ } catch (FileNotFoundException | RemoteException | RuntimeException e) {
+ throw new ResourceException(
+ "Failed to open a file for %s due to an exception.", src.derivedUri, e);
+ }
in = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
}
- dstFile = getClient(dest).openFile(dest.derivedUri, "w", canceller);
+ try {
+ dstFile = getClient(dest).openFile(dest.derivedUri, "w", canceller);
+ } catch (FileNotFoundException | RemoteException | RuntimeException e) {
+ throw new ResourceException("Failed to open the destination file %s for writing "
+ + "due to an exception.", dest.derivedUri, e);
+ }
out = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
byte[] buffer = new byte[32 * 1024];
int len;
- while ((len = in.read(buffer)) != -1) {
- if (isCanceled()) {
- if (DEBUG) Log.d(TAG, "Canceled copy mid-copy. Id:" + id);
- success = false;
- break;
+ try {
+ while ((len = in.read(buffer)) != -1) {
+ if (isCanceled()) {
+ if (DEBUG) Log.d(TAG, "Canceled copy mid-copy of: " + src.derivedUri);
+ return;
+ }
+ out.write(buffer, 0, len);
+ makeCopyProgress(len);
}
- out.write(buffer, 0, len);
- makeCopyProgress(len);
+
+ srcFile.checkError();
+ } catch (IOException e) {
+ throw new ResourceException(
+ "Failed to copy bytes from %s to %s due to an IO exception.",
+ src.derivedUri, dest.derivedUri, e);
}
- srcFile.checkError();
- } catch (IOException e) {
- success = false;
- onFileFailed(src, "Exception thrown while copying from "
- + src.derivedUri + " to " + dest.derivedUri + ".");
+ if (src.isVirtualDocument()) {
+ convertedFiles.add(src);
+ }
- if (dstFile != null) {
+ success = true;
+ } finally {
+ if (!success) {
+ if (dstFile != null) {
+ try {
+ dstFile.closeWithError("Error copying bytes.");
+ } catch (IOException closeError) {
+ Log.w(TAG, "Error closing destination.", closeError);
+ }
+ }
+
+ if (DEBUG) Log.d(TAG, "Cleaning up failed operation leftovers.");
+ canceller.cancel();
try {
- dstFile.closeWithError(e.getMessage());
- } catch (IOException closeError) {
- Log.e(TAG, "Error closing destination", closeError);
+ deleteDocument(dest, destParent);
+ } catch (ResourceException e) {
+ Log.w(TAG, "Failed to cleanup after copy error: " + src.derivedUri, e);
}
}
- } finally {
+
// This also ensures the file descriptors are closed.
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
}
-
- if (!success) {
- if (DEBUG) Log.d(TAG, "Cleaning up failed operation leftovers.");
- canceller.cancel();
- try {
- DocumentsContract.deleteDocument(getClient(dest), dest.derivedUri);
- } catch (RemoteException e) {
- // RemoteExceptions usually signal that the connection is dead, so there's no
- // point attempting to continue. Propagate the exception up so the copy job is
- // cancelled.
- Log.w(TAG, "Failed to cleanup after copy error: " + src.derivedUri, e);
- throw e;
- }
- }
-
- if (src.isVirtualDocument() && success) {
- convertedFiles.add(src);
- }
-
- return success;
}
/**
@@ -475,16 +548,20 @@ class CopyJob extends Job {
*
* @param srcs
* @return Size in bytes.
- * @throws RemoteException
+ * @throws ResourceException
*/
- private long calculateSize(List<DocumentInfo> srcs)
- throws RemoteException {
+ private long calculateSize(List<DocumentInfo> srcs) throws ResourceException {
long result = 0;
for (DocumentInfo src : srcs) {
if (src.isDirectory()) {
// Directories need to be recursed into.
- result += calculateFileSizesRecursively(getClient(src), src.derivedUri);
+ try {
+ result += calculateFileSizesRecursively(getClient(src), src.derivedUri);
+ } catch (RemoteException e) {
+ throw new ResourceException("Failed to obtain the client for %s.",
+ src.derivedUri);
+ }
} else {
result += src.size;
}
@@ -495,10 +572,10 @@ class CopyJob extends Job {
/**
* Calculates (recursively) the cumulative size of all the files under the given directory.
*
- * @throws RemoteException
+ * @throws ResourceException
*/
private static long calculateFileSizesRecursively(
- ContentProviderClient client, Uri uri) throws RemoteException {
+ ContentProviderClient client, Uri uri) throws ResourceException {
final String authority = uri.getAuthority();
final Uri queryUri = buildChildDocumentsUri(authority, getDocumentId(uri));
final String queryColumns[] = new String[] {
@@ -524,6 +601,9 @@ class CopyJob extends Job {
result += size > 0 ? size : 0;
}
}
+ } catch (RemoteException | RuntimeException e) {
+ throw new ResourceException(
+ "Failed to calculate size for %s due to an exception.", uri, e);
} finally {
IoUtils.closeQuietly(cursor);
}
@@ -533,21 +613,22 @@ class CopyJob extends Job {
/**
* Returns true if {@code doc} is a descendant of {@code parentDoc}.
- * @throws RemoteException
+ * @throws ResourceException
*/
boolean isDescendentOf(DocumentInfo doc, DocumentInfo parent)
- throws RemoteException {
+ throws ResourceException {
if (parent.isDirectory() && doc.authority.equals(parent.authority)) {
- return isChildDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+ try {
+ return isChildDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+ } catch (RemoteException | RuntimeException e) {
+ throw new ResourceException(
+ "Failed to check if %s is a child of %s due to an exception.",
+ doc.derivedUri, parent.derivedUri, e);
+ }
}
return false;
}
- private void onFileFailed(DocumentInfo file, String msg) {
- Log.w(TAG, msg);
- onFileFailed(file);
- }
-
@Override
public String toString() {
return new StringBuilder()
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 11c3a29fe319..8f451623cf72 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -22,7 +22,6 @@ import static com.android.documentsui.services.FileOperationService.OPERATION_DE
import android.app.Notification;
import android.app.Notification.Builder;
import android.content.Context;
-import android.os.RemoteException;
import android.util.Log;
import com.android.documentsui.Metrics;
@@ -58,8 +57,8 @@ final class DeleteJob extends Job {
@Override
Builder createProgressBuilder() {
return super.createProgressBuilder(
- service.getString(R.string.move_notification_title),
- R.drawable.ic_menu_copy,
+ service.getString(R.string.delete_notification_title),
+ R.drawable.ic_menu_delete,
service.getString(android.R.string.cancel),
R.drawable.ic_cab_cancel);
}
@@ -81,13 +80,13 @@ final class DeleteJob extends Job {
}
@Override
- void start() throws RemoteException {
+ void start() {
for (DocumentInfo doc : mSrcs) {
if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
- // TODO: Start using mSrcParent as soon as DocumentsProvider::removeDocument() is
- // implemented.
- if (!deleteDocument(doc)) {
- Log.w(TAG, "Failed to delete document @ " + doc.derivedUri);
+ try {
+ deleteDocument(doc, mSrcParent);
+ } catch (ResourceException e) {
+ Log.e(TAG, "Failed to delete document @ " + doc.derivedUri);
onFileFailed(doc);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 3a025c28c1d9..580fa38258a6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -17,9 +17,6 @@
package com.android.documentsui.services;
import static com.android.documentsui.Shared.DEBUG;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
import android.annotation.IntDef;
import android.app.NotificationManager;
@@ -71,11 +68,6 @@ public class FileOperationService extends Service implements Job.Listener {
// such case, this needs to be replaced with pairs of parent and child.
public static final String EXTRA_SRC_PARENT = "com.android.documentsui.SRC_PARENT";
- public static final int OPERATION_UNKNOWN = -1;
- public static final int OPERATION_COPY = 1;
- public static final int OPERATION_MOVE = 2;
- public static final int OPERATION_DELETE = 3;
-
@IntDef(flag = true, value = {
OPERATION_UNKNOWN,
OPERATION_COPY,
@@ -84,6 +76,10 @@ public class FileOperationService extends Service implements Job.Listener {
})
@Retention(RetentionPolicy.SOURCE)
public @interface OpType {}
+ public static final int OPERATION_UNKNOWN = -1;
+ public static final int OPERATION_COPY = 1;
+ public static final int OPERATION_MOVE = 2;
+ public static final int OPERATION_DELETE = 3;
// TODO: Move it to a shared file when more operations are implemented.
public static final int FAILURE_COPY = 1;
@@ -137,12 +133,12 @@ public class FileOperationService extends Service implements Job.Listener {
String jobId = intent.getStringExtra(EXTRA_JOB_ID);
@OpType int operationType = intent.getIntExtra(EXTRA_OPERATION, OPERATION_UNKNOWN);
- checkArgument(jobId != null);
+ assert(jobId != null);
if (intent.hasExtra(EXTRA_CANCEL)) {
handleCancel(intent);
} else {
- checkArgument(operationType != OPERATION_UNKNOWN);
+ assert(operationType != OPERATION_UNKNOWN);
handleOperation(intent, serviceId, jobId, operationType);
}
@@ -174,9 +170,9 @@ public class FileOperationService extends Service implements Job.Listener {
mWakeLock.acquire();
}
- checkState(job != null);
+ assert(job != null);
int delay = intent.getIntExtra(EXTRA_DELAY, DEFAULT_DELAY);
- checkArgument(delay <= MAX_DELAY);
+ assert(delay <= MAX_DELAY);
if (DEBUG) Log.d(
TAG, "Scheduling job " + job.id + " to run in " + delay + " milliseconds.");
ScheduledFuture<?> future = executor.schedule(job, delay, TimeUnit.MILLISECONDS);
@@ -189,8 +185,10 @@ public class FileOperationService extends Service implements Job.Listener {
* @param intent The cancellation intent.
*/
private void handleCancel(Intent intent) {
- checkArgument(intent.hasExtra(EXTRA_CANCEL));
- String jobId = checkNotNull(intent.getStringExtra(EXTRA_JOB_ID));
+ assert(intent.hasExtra(EXTRA_CANCEL));
+ assert(intent.getStringExtra(EXTRA_JOB_ID) != null);
+
+ String jobId = intent.getStringExtra(EXTRA_JOB_ID);
if (DEBUG) Log.d(TAG, "handleCancel: " + jobId);
@@ -254,7 +252,8 @@ public class FileOperationService extends Service implements Job.Listener {
throw new UnsupportedOperationException();
}
- return checkNotNull(job);
+ assert(job != null);
+ return job;
}
@GuardedBy("mRunning")
@@ -262,7 +261,7 @@ public class FileOperationService extends Service implements Job.Listener {
if (DEBUG) Log.d(TAG, "deleteJob: " + job.id);
JobRecord record = mRunning.remove(job.id);
- checkArgument(record != null);
+ assert(record != null);
record.job.cleanup();
if (mRunning.isEmpty()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
index 9d017ee7943d..b53e1659dae3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
@@ -22,7 +22,6 @@ import static com.android.documentsui.Shared.EXTRA_STACK;
import static com.android.documentsui.Shared.asArrayList;
import static com.android.documentsui.Shared.getQuantityString;
import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
-import static com.android.documentsui.services.FileOperationService.EXTRA_DELAY;
import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
@@ -165,19 +164,16 @@ public final class FileOperations {
* Use {@link #createJobId} if you don't have one handy.
* @param srcDocs A list of src files to copy.
* @param srcParent Parent of all the source documents.
- * @param delay Number of milliseconds to wait before executing the job.
* @return Id of the job.
*/
public static String delete(
Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
- DocumentStack location, int delay) {
+ DocumentStack location) {
String jobId = createJobId();
- if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id " + jobId
- + " delayed by " + delay + " milliseconds.");
+ if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id " + jobId + ".");
Intent intent = createBaseIntent(OPERATION_DELETE, activity, jobId, srcDocs, srcParent,
location);
- intent.putExtra(EXTRA_DELAY, delay);
activity.startService(intent);
return jobId;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index 77517ca9085b..c723ac60c334 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -23,8 +23,6 @@ import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.DrawableRes;
import android.annotation.PluralsRes;
@@ -98,7 +96,7 @@ abstract public class Job implements Runnable {
Job(Context service, Context appContext, Listener listener,
@OpType int operationType, String id, DocumentStack stack) {
- checkArgument(operationType != OPERATION_UNKNOWN);
+ assert(operationType != OPERATION_UNKNOWN);
this.service = service;
this.appContext = appContext;
@@ -116,19 +114,17 @@ abstract public class Job implements Runnable {
listener.onStart(this);
try {
start();
- } catch (Exception e) {
- // In the case of an unmanaged failure, we still want
- // to resolve business in an orderly fashion. That'll
- // ensure the service is shut down and notifications
- // shown/closed.
- Log.e(TAG, "Operation failed due to an exception.", e);
+ } catch (RuntimeException e) {
+ // No exceptions should be thrown here, as all calls to the provider must be
+ // handled within Job implementations. However, just in case catch them here.
+ Log.e(TAG, "Operation failed due to an unhandled runtime exception.", e);
Metrics.logFileOperationErrors(service, operationType, failedFiles);
} finally {
listener.onFinished(this);
}
}
- abstract void start() throws RemoteException;
+ abstract void start();
abstract Notification getSetupNotification();
// TODO: Progress notification for deletes.
@@ -152,7 +148,8 @@ abstract public class Job implements Runnable {
mClients.put(doc.authority, client);
}
- return checkNotNull(client);
+ assert(client != null);
+ return client;
}
final void cleanup() {
@@ -186,20 +183,25 @@ abstract public class Job implements Runnable {
return false;
}
- final boolean deleteDocument(DocumentInfo doc) {
+ final void deleteDocument(DocumentInfo doc, DocumentInfo parent) throws ResourceException {
try {
- DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to delete file: " + doc.derivedUri, e);
- return false;
+ if (doc.isRemoveSupported()) {
+ DocumentsContract.removeDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+ } else if (doc.isDeleteSupported()) {
+ DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
+ } else {
+ throw new ResourceException("Unable to delete source document as the file is " +
+ "not deletable nor removable: %s.", doc.derivedUri);
+ }
+ } catch (RemoteException | RuntimeException e) {
+ throw new ResourceException("Failed to delete file %s due to an exception.",
+ doc.derivedUri, e);
}
-
- return true; // victory dance!
}
Notification getSetupNotification(String content) {
- mProgressBuilder.setProgress(0, 0, true);
- mProgressBuilder.setContentText(content);
+ mProgressBuilder.setProgress(0, 0, true)
+ .setContentText(content);
return mProgressBuilder.build();
}
@@ -218,6 +220,7 @@ abstract public class Job implements Runnable {
.setCategory(Notification.CATEGORY_ERROR)
.setSmallIcon(icon)
.setAutoCancel(true);
+
return errorBuilder.build();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index 9b7207726256..dc39235b35c5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -21,11 +21,9 @@ import static com.android.documentsui.services.FileOperationService.OPERATION_MO
import android.app.Notification;
import android.app.Notification.Builder;
import android.content.Context;
-import android.net.Uri;
import android.os.RemoteException;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import android.util.Log;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
@@ -36,7 +34,6 @@ import java.util.List;
// TODO: Stop extending CopyJob.
final class MoveJob extends CopyJob {
- private static final String TAG = "MoveJob";
final DocumentInfo mSrcParent;
/**
@@ -80,8 +77,8 @@ final class MoveJob extends CopyJob {
R.plurals.move_error_notification_title, R.drawable.ic_menu_copy);
}
- boolean processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
- throws RemoteException {
+ void processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
+ throws ResourceException {
// TODO: When optimized move kicks in, we're not making any progress updates. FIX IT!
@@ -89,13 +86,19 @@ final class MoveJob extends CopyJob {
// If not supported, then fallback to byte-by-byte copy/move.
if (src.authority.equals(dest.authority)) {
if ((src.flags & Document.FLAG_SUPPORTS_MOVE) != 0) {
- if (DocumentsContract.moveDocument(getClient(src), src.derivedUri,
- srcParent != null ? srcParent.derivedUri : mSrcParent.derivedUri,
- dest.derivedUri) == null) {
- onFileFailed(src);
- return false;
+ try {
+ if (DocumentsContract.moveDocument(getClient(src), src.derivedUri,
+ srcParent != null ? srcParent.derivedUri : mSrcParent.derivedUri,
+ dest.derivedUri) == null) {
+ throw new ResourceException("Provider side move failed for document %s.",
+ src.derivedUri);
+ }
+ } catch (RuntimeException | RemoteException e) {
+ throw new ResourceException(
+ "Provider side move failed for document %s due to an exception.",
+ src.derivedUri, e);
}
- return true;
+ return;
}
}
@@ -103,16 +106,15 @@ final class MoveJob extends CopyJob {
// conversion, and the source file should not be deleted in such case (as it's a different
// file).
if (src.isVirtualDocument()) {
- Log.w(TAG, "Cannot move virtual files byte by byte.");
- onFileFailed(src);
- return false;
+ throw new ResourceException("Cannot move virtual file %s byte by byte.",
+ src.derivedUri);
}
// If we couldn't do an optimized copy...we fall back to vanilla byte copy.
- boolean copied = byteCopyDocument(src, dest);
+ byteCopyDocument(src, dest);
- // TODO: Replace deleteDocument() with removeDocument() once implemented.
- return copied && !isCanceled() && deleteDocument(src);
+ // Remove the source document.
+ deleteDocument(src, srcParent);
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java b/packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java
new file mode 100644
index 000000000000..7d3d91a2d50d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/ResourceException.java
@@ -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.
+ */
+
+package com.android.documentsui.services;
+
+import android.net.Uri;
+
+public class ResourceException extends Exception {
+ public ResourceException(String message, Exception e) {
+ super(message, e);
+ }
+
+ public ResourceException(String message, Uri uri1, Exception e) {
+ super(String.format(message, uri1.toString()), e);
+ }
+
+ public ResourceException(String message, Uri uri1, Uri uri2, Exception e) {
+ super(String.format(message, uri1.toString(), uri2.toString()), e);
+ }
+
+ public ResourceException(String message) {
+ super(message);
+ }
+
+ public ResourceException(String message, Uri uri1) {
+ super(String.format(message, uri1.toString()));
+ }
+
+ public ResourceException(String message, Uri uri1, Uri uri2) {
+ super(message.format(uri1.toString(), uri2.toString()));
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
new file mode 100644
index 000000000000..adcfef333def
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StubProvider.ROOT_0_ID;
+import static com.android.documentsui.StubProvider.ROOT_1_ID;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.provider.DocumentsContract.Document;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.MotionEvent;
+
+import com.android.documentsui.bots.DirectoryListBot;
+import com.android.documentsui.bots.KeyboardBot;
+import com.android.documentsui.bots.RootsListBot;
+import com.android.documentsui.bots.UiBot;
+import com.android.documentsui.model.RootInfo;
+
+/**
+ * Provides basic test environment for UI tests:
+ * - Launches activity
+ * - Creates and gives access to test root directories and test files
+ * - Cleans up the test environment
+ */
+public abstract class ActivityTest<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
+
+ static final int TIMEOUT = 5000;
+
+ // Testing files. For custom ones, override initTestFiles().
+ public static final String dirName1 = "Dir1";
+ public static final String fileName1 = "file1.log";
+ public static final String fileName2 = "file12.png";
+ public static final String fileName3 = "anotherFile0.log";
+ public static final String fileName4 = "poodles.text";
+ public static final String fileNameNoRename = "NO_RENAMEfile.txt";
+
+ public Bots bots;
+ public UiDevice device;
+ public Context context;
+
+ public RootInfo rootDir0;
+ public RootInfo rootDir1;
+
+ ContentResolver mResolver;
+ DocumentsProviderHelper mDocsHelper;
+ ContentProviderClient mClient;
+
+ public ActivityTest(Class<T> activityClass) {
+ super(activityClass);
+ }
+
+ /*
+ * Returns the root that will be opened within the activity.
+ * By default tests are started with one of the test roots.
+ * Override the method if you want to open different root on start.
+ * @return Root that will be opened. Return null if you want to open activity's default root.
+ */
+ @Nullable
+ protected RootInfo getInitialRoot() {
+ return rootDir0;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ device = UiDevice.getInstance(getInstrumentation());
+ // NOTE: Must be the "target" context, else security checks in content provider will fail.
+ context = getInstrumentation().getTargetContext();
+
+ bots = new Bots(device, context, TIMEOUT);
+
+ Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
+ bots.main.revealLauncher();
+
+ mResolver = context.getContentResolver();
+ mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
+ mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
+
+ rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
+ rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+
+ launchActivity();
+
+ bots.main.revealApp();
+ resetStorage();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mClient.release();
+ super.tearDown();
+ }
+
+ void launchActivity() {
+ final Intent intent = context.getPackageManager().getLaunchIntentForPackage(
+ UiBot.TARGET_PKG);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (getInitialRoot() != null) {
+ intent.setData(getInitialRoot().getUri());
+ }
+ setActivityIntent(intent);
+ getActivity(); // Launch the activity.
+ }
+
+ void resetStorage() throws RemoteException {
+ mClient.call("clear", null, null);
+ device.waitForIdle();
+ }
+
+ void initTestFiles() throws RemoteException {
+ mDocsHelper.createFolder(rootDir0, dirName1);
+ mDocsHelper.createDocument(rootDir0, "text/plain", fileName1);
+ mDocsHelper.createDocument(rootDir0, "image/png", fileName2);
+ mDocsHelper.createDocumentWithFlags(rootDir0.documentId, "text/plain", fileNameNoRename,
+ Document.FLAG_SUPPORTS_WRITE);
+
+ mDocsHelper.createDocument(rootDir1, "text/plain", fileName3);
+ mDocsHelper.createDocument(rootDir1, "text/plain", fileName4);
+ }
+
+ void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException {
+ bots.directory.assertDocumentsCount(4);
+ bots.directory.assertDocumentsPresent(fileName1, fileName2, dirName1, fileNameNoRename);
+ }
+
+ void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException {
+ bots.directory.assertDocumentsCount(2);
+ bots.directory.assertDocumentsPresent(fileName3, fileName4);
+ }
+
+ /**
+ * Handy collection of bots for working with Files app.
+ */
+ public static final class Bots {
+ public final UiBot main;
+ public final RootsListBot roots;
+ public final DirectoryListBot directory;
+ public final KeyboardBot keyboard;
+
+ private Bots(UiDevice device, Context context, int timeout) {
+ this.main = new UiBot(device, context, TIMEOUT);
+ this.roots = new RootsListBot(device, context, TIMEOUT);
+ this.directory = new DirectoryListBot(device, context, TIMEOUT);
+ this.keyboard = new KeyboardBot(device, context, TIMEOUT);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
index 5df4dcaf11a7..af478eafc38e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
@@ -92,7 +92,8 @@ public class DocumentsProviderHelper {
Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
return uri;
} catch (RemoteException e) {
- throw new RuntimeException("Couldn't create document: " + name + " with mimetype " + mimeType, e);
+ throw new RuntimeException("Couldn't create document: " + name + " with mimetype "
+ + mimeType, e);
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
index 243c3577500c..79d7887198b5 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java
@@ -16,144 +16,87 @@
package com.android.documentsui;
-import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
-import android.app.Instrumentation;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.provider.DocumentsContract;
import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.documentsui.model.RootInfo;
@LargeTest
-public class DownloadsActivityUiTest extends ActivityInstrumentationTestCase2<DownloadsActivity> {
-
- private static final int TIMEOUT = 5000;
- private static final String TAG = "DownloadsActivityUiTest";
- private static final String TARGET_PKG = "com.android.documentsui";
- private static final String LAUNCHER_PKG = "com.android.launcher";
-
- private UiBot mBot;
- private UiDevice mDevice;
- private Context mContext;
- private ContentResolver mResolver;
- private DocumentsProviderHelper mDocsHelper;
- private ContentProviderClient mClient;
- private RootInfo mRoot;
+public class DownloadsActivityUiTest extends ActivityTest<DownloadsActivity> {
public DownloadsActivityUiTest() {
super(DownloadsActivity.class);
}
- public void setUp() throws Exception {
- // Initialize UiDevice instance.
- Instrumentation instrumentation = getInstrumentation();
-
- mDevice = UiDevice.getInstance(instrumentation);
-
- Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
-
- // Start from the home screen.
- mDevice.pressHome();
- mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), TIMEOUT);
-
- // NOTE: Must be the "target" context, else security checks in content provider will fail.
- mContext = instrumentation.getTargetContext();
- mResolver = mContext.getContentResolver();
-
- mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
- mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
-
- mRoot = mDocsHelper.getRoot(ROOT_0_ID);
-
- // Open the Downloads activity on our stub provider root.
- Intent intent = new Intent(DocumentsContract.ACTION_MANAGE_ROOT);
- intent.setDataAndType(mRoot.getUri(), DocumentsContract.Root.MIME_TYPE_ITEM);
+ @Override
+ void launchActivity() {
+ final Intent intent = new Intent(DocumentsContract.ACTION_MANAGE_ROOT);
+ intent.setDataAndType(rootDir0.getUri(), DocumentsContract.Root.MIME_TYPE_ITEM);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
setActivityIntent(intent);
- getActivity(); // Start the activity.
-
- // Wait for the app to appear.
- mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT);
- mDevice.waitForIdle();
-
- mBot = new UiBot(mDevice, mContext, TIMEOUT);
-
- resetStorage(); // Just in case a test failed and tearDown didn't happen.
+ getActivity(); // Launch the activity.
}
@Override
- protected void tearDown() throws Exception {
- Log.d(TAG, "Resetting storage from setUp");
- resetStorage();
- mClient.release();
-
- super.tearDown();
- }
-
- private void resetStorage() throws RemoteException {
- mClient.call("clear", null, null);
- // TODO: Would be nice to have an event to wait on here.
- mDevice.waitForIdle();
- }
-
- private void initTestFiles() throws RemoteException {
- mDocsHelper.createDocument(mRoot, "text/plain", "file0.log");
- mDocsHelper.createDocument(mRoot, "image/png", "file1.png");
- mDocsHelper.createDocument(mRoot, "text/csv", "file2.csv");
+ void initTestFiles() throws RemoteException {
+ mDocsHelper.createDocument(rootDir0, "text/plain", "file0.log");
+ mDocsHelper.createDocument(rootDir0, "image/png", "file1.png");
+ mDocsHelper.createDocument(rootDir0, "text/csv", "file2.csv");
}
public void testWindowTitle() throws Exception {
initTestFiles();
- mBot.assertWindowTitle(ROOT_0_ID);
+ bots.main.assertWindowTitle(ROOT_0_ID);
}
public void testFilesListed() throws Exception {
initTestFiles();
- mBot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
+ bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv");
}
public void testFilesList_LiveUpdate() throws Exception {
initTestFiles();
- mDocsHelper.createDocument(mRoot, "yummers/sandwich", "Ham & Cheese.sandwich");
- mBot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
+ mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
+
+ bots.directory.waitForDocument("Ham & Cheese.sandwich");
+ bots.directory.assertDocumentsPresent(
+ "file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
}
public void testDeleteDocument() throws Exception {
initTestFiles();
- mBot.clickDocument("file1.png");
- mDevice.waitForIdle();
- mBot.menuDelete().click();
+ bots.directory.clickDocument("file1.png");
+ device.waitForIdle();
+ bots.main.menuDelete().click();
- mBot.waitForDeleteSnackbar();
- assertFalse(mBot.hasDocuments("file1.png"));
+ bots.directory.waitForDeleteSnackbar();
+ bots.directory.assertDocumentsAbsent("file1.png");
- mBot.waitForDeleteSnackbarGone();
- assertFalse(mBot.hasDocuments("file1.png"));
+ bots.directory.waitForDeleteSnackbarGone();
+ bots.directory.assertDocumentsAbsent("file1.png");
}
public void testSupportsShare() throws Exception {
initTestFiles();
- mBot.clickDocument("file1.png");
- mDevice.waitForIdle();
- assertNotNull(mBot.menuShare());
+ bots.directory.clickDocument("file1.png");
+ device.waitForIdle();
+ assertNotNull(bots.main.menuShare());
+ }
+
+ public void testClosesOnBack() throws Exception {
+ DownloadsActivity activity = getActivity();
+ device.pressBack();
+ device.wait(Until.gone(By.text(ROOT_0_ID)), TIMEOUT); // wait for the window to go away
+ assertTrue(activity.isDestroyed());
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 868dbbb39e1b..498471e6828b 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -16,123 +16,50 @@
package com.android.documentsui;
-import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;
-import android.app.Instrumentation;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
import android.os.RemoteException;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.Until;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.MotionEvent;
+import android.view.KeyEvent;
import com.android.documentsui.model.RootInfo;
@LargeTest
-public class FilesActivityUiTest extends ActivityInstrumentationTestCase2<FilesActivity> {
-
- private static final int TIMEOUT = 5000;
- private static final String TAG = "FilesActivityUiTest";
- private static final String TARGET_PKG = "com.android.documentsui";
- private static final String LAUNCHER_PKG = "com.android.launcher";
-
- private UiBot mBot;
- private UiDevice mDevice;
- private Context mContext;
- private ContentResolver mResolver;
- private DocumentsProviderHelper mDocsHelper;
- private ContentProviderClient mClient;
- private RootInfo mRoot_0;
- private RootInfo mRoot_1;
+public class FilesActivityUiTest extends ActivityTest<FilesActivity> {
public FilesActivityUiTest() {
super(FilesActivity.class);
}
- public void setUp() throws Exception {
- // Initialize UiDevice instance.
- Instrumentation instrumentation = getInstrumentation();
-
- mDevice = UiDevice.getInstance(instrumentation);
-
- Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
-
- // Start from the home screen.
- mDevice.pressHome();
- mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), TIMEOUT);
-
- // NOTE: Must be the "target" context, else security checks in content provider will fail.
- mContext = instrumentation.getTargetContext();
- mResolver = mContext.getContentResolver();
-
- mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
- assertNotNull("Failed to acquire ContentProviderClient.", mClient);
- mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
-
- // Launch app.
- Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- setActivityIntent(intent);
- getActivity(); // Start the activity.
-
- // Wait for the app to appear.
- mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT);
- mDevice.waitForIdle();
-
- mBot = new UiBot(mDevice, mContext, TIMEOUT);
-
- resetStorage(); // Just incase a test failed and tearDown didn't happen.
- }
-
@Override
- protected void tearDown() throws Exception {
- Log.d(TAG, "Resetting storage from setUp");
- resetStorage();
- mClient.release();
-
- super.tearDown();
+ protected RootInfo getInitialRoot() {
+ return null;
}
- private void resetStorage() throws RemoteException {
- mClient.call("clear", null, null);
- // TODO: Would be nice to have an event to wait on here.
- mDevice.waitForIdle();
- }
-
- private void initTestFiles() throws RemoteException {
- mRoot_0 = mDocsHelper.getRoot(ROOT_0_ID);
- mRoot_1 = mDocsHelper.getRoot(ROOT_1_ID);
-
- mDocsHelper.createDocument(mRoot_0, "text/plain", "file0.log");
- mDocsHelper.createDocument(mRoot_0, "image/png", "file1.png");
- mDocsHelper.createDocument(mRoot_0, "text/csv", "file2.csv");
+ @Override
+ public void initTestFiles() throws RemoteException {
+ mDocsHelper.createDocument(rootDir0, "text/plain", "file0.log");
+ mDocsHelper.createDocument(rootDir0, "image/png", "file1.png");
+ mDocsHelper.createDocument(rootDir0, "text/csv", "file2.csv");
- mDocsHelper.createDocument(mRoot_1, "text/plain", "anotherFile0.log");
- mDocsHelper.createDocument(mRoot_1, "text/plain", "poodles.text");
+ mDocsHelper.createDocument(rootDir1, "text/plain", "anotherFile0.log");
+ mDocsHelper.createDocument(rootDir1, "text/plain", "poodles.text");
}
public void testRootsListed() throws Exception {
initTestFiles();
- mBot.openRoot(ROOT_0_ID);
+ bots.roots.openRoot(ROOT_0_ID);
// Should also have Drive, but that requires pre-configuration of devices
// We omit for now.
- mBot.assertHasRoots(
+ bots.roots.assertHasRoots(
"Images",
"Videos",
"Audio",
"Downloads",
- "Home",
+ "Documents",
ROOT_0_ID,
ROOT_1_ID);
}
@@ -140,60 +67,107 @@ public class FilesActivityUiTest extends ActivityInstrumentationTestCase2<FilesA
public void testFilesListed() throws Exception {
initTestFiles();
- mBot.openRoot(ROOT_0_ID);
- mBot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
+ bots.roots.openRoot(ROOT_0_ID);
+ bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv");
}
- public void testLoadsHomeByDefault() throws Exception {
+ public void testLoadsHomeDirectoryByDefault() throws Exception {
initTestFiles();
- mDevice.waitForIdle();
- mBot.assertWindowTitle("Home");
+ device.waitForIdle();
+ bots.main.assertWindowTitle("Documents");
}
public void testRootClickSetsWindowTitle() throws Exception {
initTestFiles();
- mBot.openRoot("Downloads");
- mBot.assertWindowTitle("Downloads");
+ bots.roots.openRoot("Downloads");
+ bots.main.assertWindowTitle("Downloads");
}
public void testFilesList_LiveUpdate() throws Exception {
initTestFiles();
- mBot.openRoot(ROOT_0_ID);
- mDocsHelper.createDocument(mRoot_0, "yummers/sandwich", "Ham & Cheese.sandwich");
+ bots.roots.openRoot(ROOT_0_ID);
+ mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
- mDevice.waitForIdle();
- mBot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
+ bots.directory.waitForDocument("Ham & Cheese.sandwich");
+ bots.directory.assertDocumentsPresent(
+ "file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
+ }
+
+ public void testCreateDirectory() throws Exception {
+ initTestFiles();
+
+ bots.roots.openRoot(ROOT_0_ID);
+
+ bots.main.openOverflowMenu();
+ bots.main.menuNewFolder().click();
+ bots.main.setDialogText("Kung Fu Panda");
+
+ bots.keyboard.pressEnter();
+
+ bots.directory.assertDocumentsPresent("Kung Fu Panda");
}
public void testDeleteDocument() throws Exception {
initTestFiles();
- mBot.openRoot(ROOT_0_ID);
+ bots.roots.openRoot(ROOT_0_ID);
+
+ bots.directory.clickDocument("file1.png");
+ device.waitForIdle();
+ bots.main.menuDelete().click();
- mBot.clickDocument("file1.png");
- mDevice.waitForIdle();
- mBot.menuDelete().click();
+ bots.main.findDialogOkButton().click();
- mBot.waitForDeleteSnackbar();
- assertFalse(mBot.hasDocuments("file1.png"));
+ bots.directory.assertDocumentsAbsent("file1.png");
+ }
+
+ public void testDeleteDocument_Cancel() throws Exception {
+ initTestFiles();
+
+ bots.roots.openRoot(ROOT_0_ID);
- mBot.waitForDeleteSnackbarGone();
- assertFalse(mBot.hasDocuments("file1.png"));
+ bots.directory.clickDocument("file1.png");
+ device.waitForIdle();
+ bots.main.menuDelete().click();
- // Now delete from another root.
- mBot.openRoot(ROOT_1_ID);
+ bots.main.findDialogCancelButton().click();
- mBot.clickDocument("poodles.text");
- mDevice.waitForIdle();
- mBot.menuDelete().click();
+ bots.directory.assertDocumentsPresent("file1.png");
+ }
+
+ // Tests that pressing tab switches focus between the roots and directory listings.
+ public void testKeyboard_tab() throws Exception {
+ bots.main.pressKey(KeyEvent.KEYCODE_TAB);
+ bots.roots.assertHasFocus();
+ bots.main.pressKey(KeyEvent.KEYCODE_TAB);
+ bots.directory.assertHasFocus();
+ }
- mBot.waitForDeleteSnackbar();
- assertFalse(mBot.hasDocuments("poodles.text"));
+ // Tests that arrow keys do not switch focus away from the dir list.
+ public void testKeyboard_arrowsDirList() throws Exception {
+ for (int i = 0; i < 10; i++) {
+ bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ bots.directory.assertHasFocus();
+ }
+ for (int i = 0; i < 10; i++) {
+ bots.main.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ bots.directory.assertHasFocus();
+ }
+ }
- mBot.waitForDeleteSnackbarGone();
- assertFalse(mBot.hasDocuments("poodles.text"));
+ // Tests that arrow keys do not switch focus away from the roots list.
+ public void testKeyboard_arrowsRootsList() throws Exception {
+ bots.main.pressKey(KeyEvent.KEYCODE_TAB);
+ for (int i = 0; i < 10; i++) {
+ bots.main.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ bots.roots.assertHasFocus();
+ }
+ for (int i = 0; i < 10; i++) {
+ bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ bots.roots.assertHasFocus();
+ }
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
index 5c6254f90964..5f33b32d7d54 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
@@ -17,150 +17,134 @@
package com.android.documentsui;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
-import static com.android.documentsui.UiTestEnvironment.TIMEOUT;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
@LargeTest
-public class RenameDocumentUiTest extends InstrumentationTestCase {
-
- private static final String TAG = "RenamDocumentUiTest";
+public class RenameDocumentUiTest extends ActivityTest<FilesActivity> {
private final String newName = "kitties.log";
- private UiTestEnvironment mHelper;
+ public RenameDocumentUiTest() {
+ super(FilesActivity.class);
+ }
@Override
public void setUp() throws Exception {
super.setUp();
- mHelper = new UiTestEnvironment(getInstrumentation());
- mHelper.launch();
- mHelper.initTestFiles();
- mHelper.bot().openRoot(ROOT_0_ID);
+ initTestFiles();
}
public void testRenameEnabled_SingleSelection() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().assertMenuEnabled(R.string.menu_rename, true);
+ bots.directory.selectDocument(fileName1);
+ bots.main.openOverflowMenu();
+ bots.main.assertMenuEnabled(R.string.menu_rename, true);
// Dismiss more options window
- mHelper.device().pressBack();
+ device.pressBack();
}
public void testNoRenameSupport_SingleSelection() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileNameNoRename);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().assertMenuEnabled(R.string.menu_rename, false);
+ bots.directory.selectDocument(fileNameNoRename);
+ bots.main.openOverflowMenu();
+ bots.main.assertMenuEnabled(R.string.menu_rename, false);
// Dismiss more options window
- mHelper.device().pressBack();
+ device.pressBack();
}
public void testOneHasRenameSupport_MultipleSelection() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().selectDocument(UiTestEnvironment.fileNameNoRename);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().assertMenuEnabled(R.string.menu_rename, false);
+ bots.directory.selectDocument(fileName1);
+ bots.directory.selectDocument(fileNameNoRename);
+ bots.main.openOverflowMenu();
+ bots.main.assertMenuEnabled(R.string.menu_rename, false);
// Dismiss more options window
- mHelper.device().pressBack();
+ device.pressBack();
}
public void testRenameDisabled_MultipleSelection() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().selectDocument(UiTestEnvironment.fileName2);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().assertMenuEnabled(R.string.menu_rename, false);
+ bots.directory.selectDocument(fileName1);
+ bots.directory.selectDocument(fileName2);
+ bots.main.openOverflowMenu();
+ bots.main.assertMenuEnabled(R.string.menu_rename, false);
// Dismiss more options window
- mHelper.device().pressBack();
+ device.pressBack();
}
public void testRenameFile_OkButton() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().openDialog(R.string.menu_rename);
- mHelper.bot().setDialogText(newName);
- mHelper.bot().dismissKeyboardIfPresent();
-
- mHelper.device().waitForIdle(TIMEOUT);
- mHelper.bot().findRenameDialogOkButton().click();
- mHelper.device().waitForIdle(TIMEOUT);
-
- mHelper.bot().assertDocument(UiTestEnvironment.fileName1, false);
- mHelper.bot().assertDocument(newName, true);
- mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0());
+ bots.directory.selectDocument(fileName1);
+ bots.main.openOverflowMenu();
+ bots.main.menuRename().click();
+ bots.main.setDialogText(newName);
+
+ device.waitForIdle(TIMEOUT);
+ bots.main.findDialogOkButton().click();
+ device.waitForIdle(TIMEOUT);
+
+ bots.directory.assertDocumentsAbsent(fileName1);
+ bots.directory.assertDocumentsPresent(newName);
+ bots.directory.assertDocumentsCount(4);
}
public void testRenameFile_Enter() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().openDialog(R.string.menu_rename);
- mHelper.bot().setDialogText(newName);
+ bots.directory.selectDocument(fileName1);
+ bots.main.openOverflowMenu();
+ bots.main.menuRename().click();
+ bots.main.setDialogText(newName);
- pressEnter();
+ bots.keyboard.pressEnter();
- mHelper.bot().assertDocument(UiTestEnvironment.fileName1, false);
- mHelper.bot().assertDocument(newName, true);
- mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0());
+ bots.directory.assertDocumentsAbsent(fileName1);
+ bots.directory.assertDocumentsPresent(newName);
+ bots.directory.assertDocumentsCount(4);
}
public void testRenameFile_Cancel() throws Exception {
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().openDialog(R.string.menu_rename);
- mHelper.bot().setDialogText(newName);
- mHelper.bot().dismissKeyboardIfPresent();
-
- mHelper.device().waitForIdle(TIMEOUT);
- mHelper.bot().findRenameDialogCancelButton().click();
- mHelper.device().waitForIdle(TIMEOUT);
-
- mHelper.bot().assertDocument(UiTestEnvironment.fileName1, true);
- mHelper.bot().assertDocument(newName, false);
- mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0());
+ bots.directory.selectDocument(fileName1);
+ bots.main.openOverflowMenu();
+ bots.main.menuRename().click();
+ bots.main.setDialogText(newName);
+
+ device.waitForIdle(TIMEOUT);
+ bots.main.findDialogCancelButton().click();
+ device.waitForIdle(TIMEOUT);
+
+ bots.directory.assertDocumentsPresent(fileName1);
+ bots.directory.assertDocumentsAbsent(newName);
+ bots.directory.assertDocumentsCount(4);
}
public void testRenameDir() throws Exception {
String oldName = "Dir1";
String newName = "Dir123";
- mHelper.bot().selectDocument(oldName);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().openDialog(R.string.menu_rename);
- mHelper.bot().setDialogText(newName);
+ bots.directory.selectDocument(oldName);
+ bots.main.openOverflowMenu();
+ bots.main.menuRename().click();
+ bots.main.setDialogText(newName);
- pressEnter();
+ bots.keyboard.pressEnter();
- mHelper.bot().assertDocument(oldName, false);
- mHelper.bot().assertDocument(newName, true);
- mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0());
+ bots.directory.assertDocumentsAbsent(oldName);
+ bots.directory.assertDocumentsPresent(newName);
+ bots.directory.assertDocumentsCount(4);
}
public void testRename_NameExists() throws Exception {
// Check that document with the new name exists
- mHelper.bot().assertDocument(UiTestEnvironment.fileName2, true);
- mHelper.bot().selectDocument(UiTestEnvironment.fileName1);
- mHelper.bot().openOverflowMenu();
- mHelper.bot().openDialog(R.string.menu_rename);
- mHelper.bot().setDialogText(UiTestEnvironment.fileName2);
-
- pressEnter();
-
- mHelper.bot().assertSnackbar(R.string.rename_error);
- mHelper.bot().assertDocument(UiTestEnvironment.fileName1, true);
- mHelper.bot().assertDocument(UiTestEnvironment.fileName2, true);
- mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0());
+ bots.directory.assertDocumentsPresent(fileName2);
+ bots.directory.selectDocument(fileName1);
+ bots.main.openOverflowMenu();
+ bots.main.menuRename().click();
+ bots.main.setDialogText(fileName2);
+
+ bots.keyboard.pressEnter();
+
+ bots.directory.assertSnackbar(R.string.rename_error);
+ bots.directory.assertDocumentsPresent(fileName1);
+ bots.directory.assertDocumentsPresent(fileName2);
+ bots.directory.assertDocumentsCount(4);
}
-
- private void pressEnter() {
- mHelper.device().waitForIdle(TIMEOUT);
- mHelper.device().pressEnter();
- mHelper.device().waitForIdle(TIMEOUT);
- }
-
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
new file mode 100644
index 000000000000..73c1c5ffc955
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsUiTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.documentsui;
+
+import static com.android.documentsui.StubProvider.ROOT_0_ID;
+import static com.android.documentsui.StubProvider.ROOT_1_ID;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+@LargeTest
+public class RootsUiTest extends ActivityTest<FilesActivity> {
+
+ private static final String TAG = "RootUiTest";
+
+ public RootsUiTest() {
+ super(FilesActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ initTestFiles();
+ }
+
+ public void testRootTapped_GoToRootFromChildDir() throws Exception {
+ bots.directory.openDocument(dirName1);
+ bots.main.assertWindowTitle(dirName1);
+ bots.roots.openRoot(ROOT_0_ID);
+ bots.main.assertWindowTitle(ROOT_0_ID);
+ assertDefaultContentOfTestDir0();
+ }
+
+ public void testRootChanged_ClearSelection() throws Exception {
+ bots.directory.selectDocument(fileName1);
+ bots.main.assertInActionMode(true);
+
+ bots.roots.openRoot(ROOT_1_ID);
+ bots.main.assertInActionMode(false);
+ }
+
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
index 042ec85ad212..8c3fd904762a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
@@ -19,143 +19,128 @@ package com.android.documentsui;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;
-import android.support.test.uiautomator.UiObject;
-import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
@LargeTest
-public class SearchViewUiTest extends InstrumentationTestCase {
+public class SearchViewUiTest extends ActivityTest<FilesActivity> {
- private static final String TAG = "SearchViewUiTest";
-
- private UiTestEnvironment mEnv;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mEnv = new UiTestEnvironment(getInstrumentation());
- mEnv.launch();
-
- }
-
- @Override
- protected void tearDown() throws Exception {
- mEnv.device().pressBack();
- super.tearDown();
+ public SearchViewUiTest() {
+ super(FilesActivity.class);
}
public void testSearchView_ExpandsOnClick() throws Exception {
- mEnv.bot().openSearchView();
- mEnv.bot().assertSearchTextFiledAndIcon(true, false);
+ bots.main.openSearchView();
+ bots.main.assertSearchTextFiledAndIcon(true, false);
}
public void testSearchView_CollapsesOnBack() throws Exception {
- mEnv.bot().openSearchView();
+ bots.main.openSearchView();
- mEnv.device().pressBack();
+ device.pressBack();
- mEnv.bot().assertSearchTextFiledAndIcon(false, true);
+ bots.main.assertSearchTextFiledAndIcon(false, true);
}
public void testSearchView_ClearsTextOnBack() throws Exception {
String query = "file2";
- mEnv.bot().openSearchView();
- mEnv.bot().setSearchQuery(query);
+ bots.main.openSearchView();
+ bots.main.setSearchQuery(query);
- mEnv.device().pressBack();
+ device.pressBack();
- mEnv.bot().assertSearchTextFiledAndIcon(false, true);
+ bots.main.assertSearchTextFiledAndIcon(false, true);
}
public void testSearch_ResultsFound() throws Exception {
- mEnv.initTestFiles();
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.assertDefaultContentOfTestDir0();
+ initTestFiles();
+ assertDefaultContentOfTestDir0();
String query = "file1";
- mEnv.bot().openSearchView();
- mEnv.bot().setSearchQuery(query);
- mEnv.bot().assertSearchTextField(true, query);
+ bots.main.openSearchView();
+ bots.main.setSearchQuery(query);
+ bots.main.assertSearchTextField(true, query);
- mEnv.device().pressEnter();
+ device.pressEnter();
- mEnv.bot().assertDocumentsCountOnList(true, 2);
- mEnv.bot().assertHasDocuments(UiTestEnvironment.fileName1, UiTestEnvironment.fileName2);
- mEnv.bot().assertSearchTextField(false, query);
+ bots.directory.assertDocumentsCountOnList(true, 2);
+ bots.directory.assertDocumentsPresent(fileName1, fileName2);
+
+ bots.main.assertSearchTextField(false, query);
}
public void testSearchResultsFound_ClearsOnBack() throws Exception {
- mEnv.initTestFiles();
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.assertDefaultContentOfTestDir0();
+ initTestFiles();
+ assertDefaultContentOfTestDir0();
+
+ String query = fileName1;
+ bots.main.openSearchView();
+ bots.main.setSearchQuery(query);
- String query = UiTestEnvironment.fileName1;
- mEnv.bot().openSearchView();
- mEnv.bot().setSearchQuery(query);
+ device.pressEnter();
+ device.pressBack();
- mEnv.device().pressEnter();
- mEnv.device().pressBack();
- mEnv.assertDefaultContentOfTestDir0();
+ assertDefaultContentOfTestDir0();
}
public void testSearch_NoResults() throws Exception {
- mEnv.initTestFiles();
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.assertDefaultContentOfTestDir0();
+ initTestFiles();
+ assertDefaultContentOfTestDir0();
String query = "chocolate";
- mEnv.bot().openSearchView();
- mEnv.bot().setSearchQuery(query);
+ bots.main.openSearchView();
+ bots.main.setSearchQuery(query);
- mEnv.device().pressEnter();
+ device.pressEnter();
- mEnv.bot().assertDocumentsCountOnList(false, 0);
+ bots.directory.assertDocumentsCountOnList(false, 0);
- String msg = String.valueOf(mEnv.context().getString(R.string.no_results));
- mEnv.bot().assertMessageTextView(String.format(msg, "TEST_ROOT_0"));
- mEnv.bot().assertSearchTextField(false, query);
+ device.waitForIdle();
+ String msg = String.valueOf(context.getString(R.string.no_results));
+ bots.directory.assertMessageTextView(String.format(msg, "TEST_ROOT_0"));
+
+ bots.main.assertSearchTextField(false, query);
}
public void testSearchNoResults_ClearsOnBack() throws Exception {
- mEnv.initTestFiles();
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.assertDefaultContentOfTestDir0();
+ initTestFiles();
+ assertDefaultContentOfTestDir0();
String query = "chocolate";
- mEnv.bot().openSearchView();
- mEnv.bot().setSearchQuery(query);
+ bots.main.openSearchView();
+ bots.main.setSearchQuery(query);
+
+ device.pressEnter();
+ device.pressBack();
- mEnv.device().pressEnter();
- mEnv.device().pressBack();
- mEnv.assertDefaultContentOfTestDir0();
+ device.waitForIdle();
+ assertDefaultContentOfTestDir0();
}
public void testSearchResultsFound_ClearsOnDirectoryChange() throws Exception {
- mEnv.initTestFiles();
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.assertDefaultContentOfTestDir0();
+ initTestFiles();
+ assertDefaultContentOfTestDir0();
- String query = UiTestEnvironment.fileName1;
- mEnv.bot().openSearchView();
- mEnv.bot().setSearchQuery(query);
+ String query = fileName1;
+ bots.main.openSearchView();
+ bots.main.setSearchQuery(query);
- mEnv.device().pressEnter();
+ device.pressEnter();
- mEnv.bot().openRoot(ROOT_1_ID);
- mEnv.assertDefaultContentOfTestDir1();
+ bots.roots.openRoot(ROOT_1_ID);
+ assertDefaultContentOfTestDir1();
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.assertDefaultContentOfTestDir0();
+ bots.roots.openRoot(ROOT_0_ID);
+ assertDefaultContentOfTestDir0();
}
public void testSearchIconVisible_RootWithSearchSupport() throws Exception {
- mEnv.bot().openRoot(ROOT_0_ID);
- mEnv.bot().assertSearchTextFiledAndIcon(false, true);
+ bots.roots.openRoot(ROOT_0_ID);
+ bots.main.assertSearchTextFiledAndIcon(false, true);
}
public void testSearchIconHidden_RootNoSearchSupport() throws Exception {
- mEnv.bot().openRoot(ROOT_1_ID);
- mEnv.bot().assertSearchTextFiledAndIcon(false, false);
+ bots.roots.openRoot(ROOT_1_ID);
+ bots.main.assertSearchTextFiledAndIcon(false, false);
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
index b74b985a7d88..f057850ad655 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
@@ -23,18 +23,44 @@ import com.android.documentsui.model.DocumentInfo;
@SmallTest
public class StateTest extends AndroidTestCase {
- public void testPushDocument() {
- final State state = new State();
- final DocumentInfo infoFirst = new DocumentInfo();
- infoFirst.displayName = "firstDirectory";
- final DocumentInfo infoSecond = new DocumentInfo();
- infoSecond.displayName = "secondDirectory";
- assertFalse(state.hasLocationChanged());
- state.pushDocument(infoFirst);
- state.pushDocument(infoSecond);
- assertTrue(state.hasLocationChanged());
- assertEquals("secondDirectory", state.stack.getFirst().displayName);
- state.popDocument();
- assertEquals("firstDirectory", state.stack.getFirst().displayName);
+
+ private static final DocumentInfo DIR_1;
+ private static final DocumentInfo DIR_2;
+
+ private State mState;
+
+ static {
+ DIR_1 = new DocumentInfo();
+ DIR_1.displayName = "firstDirectory";
+ DIR_2 = new DocumentInfo();
+ DIR_2.displayName = "secondDirectory";
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ mState = new State();
+ }
+
+ public void testInitialStateEmpty() {
+ assertFalse(mState.hasLocationChanged());
+ }
+
+ public void testPushDocument_ChangesLocation() {
+ mState.pushDocument(DIR_1);
+ mState.pushDocument(DIR_2);
+ assertTrue(mState.hasLocationChanged());
+ }
+
+ public void testPushDocument_ModifiesStack() {
+ mState.pushDocument(DIR_1);
+ mState.pushDocument(DIR_2);
+ assertEquals(DIR_2, mState.stack.getFirst());
+ }
+
+ public void testPopDocument_ModifiesStack() {
+ mState.pushDocument(DIR_1);
+ mState.pushDocument(DIR_2);
+ mState.popDocument();
+ assertEquals(DIR_1, mState.stack.getFirst());
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
deleted file mode 100644
index d609fa846591..000000000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
+++ /dev/null
@@ -1,393 +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.documentsui;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
-
-import android.content.Context;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiScrollable;
-import android.support.test.uiautomator.UiSelector;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
-
-import junit.framework.Assert;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * A test helper class that provides support for controlling DocumentsUI activities
- * programmatically, and making assertions against the state of the UI.
- */
-class UiBot {
-
- private static final String TAG = "UiBot";
-
- private static final BySelector SNACK_DELETE =
- By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
-
- private UiDevice mDevice;
- private Context mContext;
- private int mTimeout;
-
- public UiBot(UiDevice device, Context context, int timeout) {
- mDevice = device;
- mContext = context;
- mTimeout = timeout;
- }
-
- UiObject findRoot(String label) throws UiObjectNotFoundException {
- final UiSelector rootsList = new UiSelector().resourceId(
- "com.android.documentsui:id/container_roots").childSelector(
- new UiSelector().resourceId("android:id/list"));
-
- // We might need to expand drawer if not visible
- if (!new UiObject(rootsList).waitForExists(mTimeout)) {
- Log.d(TAG, "Failed to find roots list; trying to expand");
- final UiSelector hamburger = new UiSelector().resourceId(
- "com.android.documentsui:id/toolbar").childSelector(
- new UiSelector().className("android.widget.ImageButton").clickable(true));
- new UiObject(hamburger).click();
- }
-
- // Wait for the first list item to appear
- new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
-
- // Now scroll around to find our item
- new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
- return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
- }
-
- void openRoot(String label) throws UiObjectNotFoundException {
- findRoot(label).click();
- mDevice.waitForIdle();
- }
-
- void assertWindowTitle(String expected) {
- // Turns out the title field on a window does not have
- // an id associated with it at runtime (which confuses the hell out of me)
- // In code we address this via "android.R.id.title".
- UiObject2 o = find(By.text(expected));
- // It's a bit of a conceit that we then *assert* that the title
- // is the value that we used to identify the UiObject2.
- // If the preceeding lookup fails, this'll choke with an NPE.
- // But given the issue described in the comment above, we're
- // going to do it anyway. Because we shouldn't be looking up
- // the uiobject by it's expected content :|
- assertEquals(expected, o.getText());
- }
-
- void assertHasRoots(String... labels) throws UiObjectNotFoundException {
- List<String> missing = new ArrayList<>();
- for (String label : labels) {
- if (!findRoot(label).exists()) {
- missing.add(label);
- }
- }
- if (!missing.isEmpty()) {
- Assert.fail(
- "Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
- }
- }
-
- void assertMenuEnabled(int id, boolean enabled) {
- UiObject2 menu= findMenuWithName(mContext.getString(id));
- assertNotNull(menu);
- assertEquals(enabled, menu.isEnabled());
- }
-
- void assertDocumentsCount(int count) throws UiObjectNotFoundException {
- UiObject docsList = findDocumentsList();
- assertEquals(count, docsList.getChildCount());
- }
-
- void assertDocumentsCount(String dir, int count) throws UiObjectNotFoundException {
- openRoot(dir);
- UiObject docsList = findDocumentsList();
- assertEquals(count, docsList.getChildCount());
- }
-
- void assertSearchTextField(boolean isFocused, String query)
- throws UiObjectNotFoundException {
- UiObject textField = findSearchViewTextField();
- UiObject searchIcon = findSearchViewIcon();
-
- assertFalse(searchIcon.exists());
- assertTrue(textField.exists());
- assertEquals(isFocused, textField.isFocused());
- if(query != null) {
- assertEquals(query, textField.getText());
- }
- }
-
- void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
- assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
- assertEquals(searchIconExists, findSearchViewIcon().exists());
- }
-
- void assertHasDocuments(String... labels) throws UiObjectNotFoundException {
- List<String> missing = new ArrayList<>();
- for (String label : labels) {
- if (!findDocument(label).exists()) {
- missing.add(label);
- }
- }
- if (!missing.isEmpty()) {
- Assert.fail(
- "Expected documents " + Arrays.asList(labels) + ", but missing " + missing);
- }
- }
-
- void assertDocument(String name, boolean exists) throws UiObjectNotFoundException {
- UiObject doc = findDocument(name);
- assertEquals(exists, doc.exists());
- }
-
- void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
- UiObject docsList = findDocumentsList();
- assertEquals(exists, docsList.exists());
- if(docsList.exists()) {
- assertEquals(count, docsList.getChildCount());
- }
- }
-
- void assertMessageTextView(String message) throws UiObjectNotFoundException {
- UiObject messageTextView = findMessageTextView();
- assertTrue(messageTextView.exists());
-
- String msg = String.valueOf(message);
- assertEquals(String.format(msg, "TEST_ROOT_0"), messageTextView.getText());
-
- }
- void assertSnackbar(int id) {
- assertNotNull(getSnackbar(mContext.getString(id)));
- }
-
- void clickDocument(String label) throws UiObjectNotFoundException {
- findDocument(label).click();
- }
-
- void openSearchView() throws UiObjectNotFoundException {
- UiObject searchView = findSearchView();
- searchView.click();
- assertTrue(searchView.exists());
- }
-
- void setSearchQuery(String query) throws UiObjectNotFoundException {
- UiObject searchView = findSearchView();
- assertTrue(searchView.exists());
- UiObject searchTextField = findSearchViewTextField();
- searchTextField.setText(query);
- assertSearchTextField(true, query);
- }
-
- UiObject openOverflowMenu() throws UiObjectNotFoundException {
- UiObject obj = findMenuMoreOptions();
- obj.click();
- mDevice.waitForIdle(mTimeout);
- return obj;
- }
-
- void openDialog(int id) {
- UiObject2 menu= findMenuWithName(mContext.getString(id));
- assertNotNull(menu);
- assertEquals(true, menu.isEnabled());
- menu.click();
- }
-
- void setDialogText(String text) throws UiObjectNotFoundException {
- findDialogEditText().setText(text);
- }
-
- UiObject selectDocument(String label) throws UiObjectNotFoundException {
- UiObject doc = findDocument(label);
- doc.longClick();
- return doc;
- }
-
- UiObject2 getSnackbar(String message) {
- return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
- }
-
- void waitForDeleteSnackbar() {
- mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
- }
-
- void waitForDeleteSnackbarGone() {
- // wait a little longer for snackbar to go away, as it disappears after a timeout.
- mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
- }
-
- void switchViewMode() {
- UiObject2 mode = menuGridMode();
- if (mode != null) {
- mode.click();
- } else {
- menuListMode().click();
- }
- }
-
- UiObject2 menuGridMode() {
- // Note that we're using By.desc rather than By.res, because of b/25285770
- return find(By.desc("Grid view"));
- }
-
- UiObject2 menuListMode() {
- // Note that we're using By.desc rather than By.res, because of b/25285770
- return find(By.desc("List view"));
- }
-
- UiObject2 menuDelete() {
- return find(By.res("com.android.documentsui:id/menu_delete"));
- }
-
- UiObject2 menuShare() {
- return find(By.res("com.android.documentsui:id/menu_share"));
- }
-
- private UiObject2 find(BySelector selector) {
- mDevice.wait(Until.findObject(selector), mTimeout);
- return mDevice.findObject(selector);
- }
-
- private UiObject findObject(String resourceId) {
- final UiSelector object = new UiSelector().resourceId(resourceId);
- return mDevice.findObject(object);
- }
-
- private UiObject findObject(String parentResourceId, String childResourceId) {
- final UiSelector selector = new UiSelector()
- .resourceId(parentResourceId)
- .childSelector(new UiSelector().resourceId(childResourceId));
- return mDevice.findObject(selector);
- }
-
- UiObject findDocument(String label) throws UiObjectNotFoundException {
- final UiSelector docList = new UiSelector().resourceId(
- "com.android.documentsui:id/container_directory").childSelector(
- new UiSelector().resourceId("com.android.documentsui:id/list"));
-
- // Wait for the first list item to appear
- new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
-
- // new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
- return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
- }
-
- boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
- for (String label : labels) {
- if (!findDocument(label).exists()) {
- return false;
- }
- }
- return true;
- }
-
- UiObject findDocumentsList() {
- return findObject(
- "com.android.documentsui:id/container_directory",
- "com.android.documentsui:id/list");
- }
-
- UiObject findSearchView() {
- return findObject("com.android.documentsui:id/menu_search");
- }
-
- UiObject findSearchViewTextField() {
- return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
- }
-
- UiObject findSearchViewIcon() {
- return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
- }
-
- UiObject findMessageTextView() {
- return findObject(
- "com.android.documentsui:id/container_directory",
- "com.android.documentsui:id/message");
- }
-
- UiObject findActionModeBar() {
- return findObject("android:id/action_mode_bar");
- }
-
- UiObject findDialogEditText() {
- return findObject("android:id/content", "android:id/text1");
- }
-
- UiObject findRenameDialogOkButton() {
- return findObject("android:id/content", "android:id/button1");
- }
-
- UiObject findRenameDialogCancelButton() {
- return findObject("android:id/content", "android:id/button2");
- }
-
- UiObject findMenuLabelWithName(String label) {
- UiSelector selector = new UiSelector().text(label);
- return mDevice.findObject(selector);
- }
-
- UiObject2 findMenuWithName(String label) {
- List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
- Iterator<UiObject2> it = menuItems.iterator();
-
- UiObject2 menuItem = null;
- while(it.hasNext()) {
- menuItem = it.next();
- UiObject2 text = menuItem.findObject(By.text(label));
- if(text != null) {
- break;
- }
- }
- return menuItem;
- }
-
- UiObject findMenuMoreOptions() {
- UiSelector selector = new UiSelector().className("android.widget.ImageButton")
- .descriptionContains("More options");
- //TODO: use the system string ? android.R.string.action_menu_overflow_description
- return mDevice.findObject(selector);
- }
-
- // Indirect way to detect the keyboard.
- boolean isKeyboardPresent() {
- InputMethodManager inputManager = (InputMethodManager) mContext
- .getSystemService(Context.INPUT_METHOD_SERVICE);
- return inputManager.isAcceptingText();
- }
-
- void dismissKeyboardIfPresent() {
- if(isKeyboardPresent()) {
- mDevice.pressBack();
- }
- }
-
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java
deleted file mode 100644
index 9e30589aa973..000000000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java
+++ /dev/null
@@ -1,177 +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.documentsui;
-
-import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY;
-import static com.android.documentsui.StubProvider.ROOT_0_ID;
-import static com.android.documentsui.StubProvider.ROOT_1_ID;
-
-import android.app.Instrumentation;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.RemoteException;
-import android.provider.DocumentsContract.Document;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.Configurator;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.Until;
-import android.view.MotionEvent;
-
-import com.android.documentsui.model.RootInfo;
-
-/**
- * Provides basic test environment for UI tests:
- * - Launches activity
- * - Creates and gives access to test root directories and test files
- * - Cleans up the test environment
- */
-class UiTestEnvironment {
-
- public static final int TIMEOUT = 5000;
- public static final String NO_RENAME = "NO_RENAME";
-
- public static final String dirName1 = "Dir1";
- public static final String fileName1 = "file1.log";
- public static final String fileName2 = "file12.png";
- public static final String fileName3 = "anotherFile0.log";
- public static final String fileName4 = "poodles.text";
- public static final String fileNameNoRename = NO_RENAME + "file.txt";
-
- private static final String TARGET_PKG = "com.android.documentsui";
- private static final String LAUNCHER_PKG = "com.android.launcher";
-
- private final UiBot mBot;
- private final UiDevice mDevice;
- private final Context mContext;
-
- private RootInfo mRootDir0;
- private RootInfo mRootDir1;
- private int mDocsCountDir0;
- private int mDocsCountDir1;
-
- private ContentResolver mResolver;
- private DocumentsProviderHelper mDocsHelper;
- private ContentProviderClient mClient;
-
- private final Instrumentation mInstrumentation;
-
- public UiTestEnvironment(Instrumentation instrumentation) {
- mInstrumentation = instrumentation;
- mDevice = UiDevice.getInstance(mInstrumentation);
- // NOTE: Must be the "target" context, else security checks in content provider will fail.
- mContext = mInstrumentation.getTargetContext();
- mBot = new UiBot(mDevice, mContext, TIMEOUT);
- }
-
-/**
- * Launches default activity and waits for the application to appear.
- * @throws Exception
- */
- public void launch() throws Exception {
- Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG);
- launch(intent);
- }
-
- /**
- * Launches activity specified by intent and waits for the application to appear.
- * @param intent Intent describing activity to launch.
- * @throws Exception
- */
- public void launch(Intent intent) throws Exception {
- Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
- // Start from the home screen.
- mDevice.pressHome();
- mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), TIMEOUT);
-
- mResolver = mContext.getContentResolver();
- mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
- mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
-
- // Launch app.
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- // Wait for the app to appear.
- mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT);
- mDevice.waitForIdle();
-
- resetStorage(); // Just incase a test failed and tearDown didn't happen.
- }
-
- public void cleanUp() throws Exception {
- resetStorage();
- mClient.release();
- }
-
- public void resetStorage() throws RemoteException {
- mClient.call("clear", null, null);
- mDevice.waitForIdle();
- }
-
- public void initTestFiles() throws RemoteException {
- mRootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
- mRootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
-
- mDocsHelper.createFolder(mRootDir0, dirName1);
- mDocsHelper.createDocument(mRootDir0, "text/plain", fileName1);
- mDocsHelper.createDocument(mRootDir0, "image/png", fileName2);
- mDocsHelper.createDocumentWithFlags(mRootDir0.documentId, "text/plain", fileNameNoRename,
- Document.FLAG_SUPPORTS_WRITE);
- mDocsCountDir0 = 4;
-
- mDocsHelper.createDocument(mRootDir1, "text/plain", fileName3);
- mDocsHelper.createDocument(mRootDir1, "text/plain", fileName4);
- mDocsCountDir1 = 2;
- }
-
- public void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException {
- bot().assertDocumentsCount(ROOT_0_ID, getDocumentsCountDir0());
- bot().assertHasDocuments(UiTestEnvironment.fileName1, UiTestEnvironment.fileName2,
- UiTestEnvironment.dirName1, UiTestEnvironment.fileNameNoRename);
- }
-
- public void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException {
- bot().assertDocumentsCount(ROOT_1_ID, getDocumentsCountDir1());
- bot().assertHasDocuments(UiTestEnvironment.fileName3, UiTestEnvironment.fileName4);
- }
-
- public UiBot bot() {
- return mBot;
- }
-
- public UiDevice device() {
- return mDevice;
- }
-
- public Context context() {
- return mContext;
- }
-
- public RootInfo getRootDir0() {
- return mRootDir0;
- }
-
- public int getDocumentsCountDir0() {
- return mDocsCountDir0;
- }
-
- public int getDocumentsCountDir1() {
- return mDocsCountDir1;
- }
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java
new file mode 100644
index 000000000000..1d2b47f2f286
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/BaseBot.java
@@ -0,0 +1,74 @@
+/*
+ * 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.documentsui.bots;
+
+import static junit.framework.Assert.assertNotNull;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+
+/**
+ * A test helper class that provides support for controlling directory list
+ * and making assertions against the state of it.
+ */
+abstract class BaseBot {
+ final UiDevice mDevice;
+ final Context mContext;
+ final int mTimeout;
+
+ BaseBot(UiDevice device, Context context, int timeout) {
+ mDevice = device;
+ mContext = context;
+ mTimeout = timeout;
+ }
+
+ /**
+ * Asserts that the specified view or one of its descendents has focus.
+ */
+ protected void assertHasFocus(String resourceName) {
+ UiObject2 candidate = mDevice.findObject(By.res(resourceName));
+ assertNotNull("Expected " + resourceName + " to have focus, but it didn't.",
+ candidate.findObject(By.focused(true)));
+ }
+
+ protected UiObject2 find(BySelector selector) {
+ mDevice.wait(Until.findObject(selector), mTimeout);
+ return mDevice.findObject(selector);
+ }
+
+ protected UiObject findObject(String resourceId) {
+ final UiSelector object = new UiSelector().resourceId(resourceId);
+ return mDevice.findObject(object);
+ }
+
+ protected UiObject findObject(String parentResourceId, String childResourceId) {
+ final UiSelector selector = new UiSelector()
+ .resourceId(parentResourceId)
+ .childSelector(new UiSelector().resourceId(childResourceId));
+ return mDevice.findObject(selector);
+ }
+
+ protected void waitForIdle() {
+ mDevice.waitForIdle(mTimeout);
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
new file mode 100644
index 000000000000..da9f9c30261a
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/DirectoryListBot.java
@@ -0,0 +1,179 @@
+/*
+ * 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.documentsui.bots;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.view.MotionEvent;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * A test helper class that provides support for controlling directory list
+ * and making assertions against the state of it.
+ */
+public class DirectoryListBot extends BaseBot {
+ private static final String DIR_LIST_ID = "com.android.documentsui:id/dir_list";
+
+ private static final BySelector SNACK_DELETE =
+ By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
+
+ public DirectoryListBot(UiDevice device, Context context, int timeout) {
+ super(device, context, timeout);
+ }
+
+ public void assertDocumentsCount(int count) throws UiObjectNotFoundException {
+ UiObject docsList = findDocumentsList();
+ assertEquals(count, docsList.getChildCount());
+ }
+
+ public void assertDocumentsPresent(String... labels) throws UiObjectNotFoundException {
+ List<String> absent = new ArrayList<>();
+ for (String label : labels) {
+ if (!findDocument(label).exists()) {
+ absent.add(label);
+ }
+ }
+ if (!absent.isEmpty()) {
+ Assert.fail("Expected documents " + Arrays.asList(labels)
+ + ", but missing " + absent);
+ }
+ }
+
+ public void assertDocumentsAbsent(String... labels) throws UiObjectNotFoundException {
+ List<String> found = new ArrayList<>();
+ for (String label : labels) {
+ if (findDocument(label).exists()) {
+ found.add(label);
+ }
+ }
+ if (!found.isEmpty()) {
+ Assert.fail("Expected documents not present" + Arrays.asList(labels)
+ + ", but present " + found);
+ }
+ }
+
+ public void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
+ UiObject docsList = findDocumentsList();
+ assertEquals(exists, docsList.exists());
+ if(docsList.exists()) {
+ assertEquals(count, docsList.getChildCount());
+ }
+ }
+
+ public void assertMessageTextView(String message) throws UiObjectNotFoundException {
+ UiObject messageTextView = findMessageTextView();
+ assertTrue(messageTextView.exists());
+
+ String msg = String.valueOf(message);
+ assertEquals(String.format(msg, "TEST_ROOT_0"), messageTextView.getText());
+
+ }
+
+ private UiObject findMessageTextView() {
+ return findObject(
+ "com.android.documentsui:id/container_directory",
+ "com.android.documentsui:id/message");
+ }
+
+ public void assertSnackbar(int id) {
+ assertNotNull(getSnackbar(mContext.getString(id)));
+ }
+
+ public void openDocument(String label) throws UiObjectNotFoundException {
+ int toolType = Configurator.getInstance().getToolType();
+ Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+ UiObject doc = findDocument(label);
+ doc.click();
+ Configurator.getInstance().setToolType(toolType);
+ }
+
+ public void clickDocument(String label) throws UiObjectNotFoundException {
+ findDocument(label).click();
+ }
+
+ public UiObject selectDocument(String label) throws UiObjectNotFoundException {
+ UiObject doc = findDocument(label);
+ doc.longClick();
+ return doc;
+ }
+
+ public UiObject2 getSnackbar(String message) {
+ return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
+ }
+
+ public void waitForDeleteSnackbar() {
+ mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
+ }
+
+ public void waitForDeleteSnackbarGone() {
+ // wait a little longer for snackbar to go away, as it disappears after a timeout.
+ mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
+ }
+
+ public void waitForDocument(String label) throws UiObjectNotFoundException {
+ findDocument(label).waitForExists(mTimeout);
+ }
+
+ public UiObject findDocument(String label) throws UiObjectNotFoundException {
+ final UiSelector docList = new UiSelector().resourceId(
+ "com.android.documentsui:id/container_directory").childSelector(
+ new UiSelector().resourceId(DIR_LIST_ID));
+
+ // Wait for the first list item to appear
+ new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
+
+ // new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
+ return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
+ }
+
+ public boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
+ for (String label : labels) {
+ if (!findDocument(label).exists()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private UiObject findDocumentsList() {
+ return findObject(
+ "com.android.documentsui:id/container_directory",
+ DIR_LIST_ID);
+ }
+
+ public void assertHasFocus() {
+ assertHasFocus(DIR_LIST_ID);
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java
new file mode 100644
index 000000000000..4c47cfacac72
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/KeyboardBot.java
@@ -0,0 +1,50 @@
+/*
+ * 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.documentsui.bots;
+
+import android.content.Context;
+import android.support.test.uiautomator.UiDevice;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * A test helper class that provides support for keyboard manipulation.
+ */
+public class KeyboardBot extends BaseBot {
+
+ public KeyboardBot(UiDevice device, Context context, int timeout) {
+ super(device, context, timeout);
+ }
+
+ public void dismissKeyboardIfPresent() {
+ if(isKeyboardPresent()) {
+ mDevice.pressBack();
+ }
+ }
+
+ // Indirect way to detect the keyboard.
+ private boolean isKeyboardPresent() {
+ InputMethodManager inputManager = (InputMethodManager) mContext
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ return inputManager.isAcceptingText();
+ }
+
+ public void pressEnter() {
+ waitForIdle();
+ mDevice.pressEnter();
+ waitForIdle();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java
new file mode 100644
index 000000000000..356fd01957e6
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/RootsListBot.java
@@ -0,0 +1,88 @@
+/*
+ * 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.documentsui.bots;
+
+import android.content.Context;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A test helper class that provides support for controlling and asserting against
+ * the roots list drawer.
+ */
+public class RootsListBot extends BaseBot {
+ private static final String ROOTS_LIST_ID = "com.android.documentsui:id/roots_list";
+ private static final String TAG = "RootsListBot";
+
+ public RootsListBot(UiDevice device, Context context, int timeout) {
+ super(device, context, timeout);
+ }
+
+ private UiObject findRoot(String label) throws UiObjectNotFoundException {
+ final UiSelector rootsList = new UiSelector().resourceId(
+ "com.android.documentsui:id/container_roots").childSelector(
+ new UiSelector().resourceId(ROOTS_LIST_ID));
+
+ // We might need to expand drawer if not visible
+ if (!new UiObject(rootsList).waitForExists(mTimeout)) {
+ Log.d(TAG, "Failed to find roots list; trying to expand");
+ final UiSelector hamburger = new UiSelector().resourceId(
+ "com.android.documentsui:id/toolbar").childSelector(
+ new UiSelector().className("android.widget.ImageButton").clickable(true));
+ new UiObject(hamburger).click();
+ }
+
+ // Wait for the first list item to appear
+ new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
+
+ // Now scroll around to find our item
+ new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
+ return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
+ }
+
+ public void openRoot(String label) throws UiObjectNotFoundException {
+ findRoot(label).click();
+ mDevice.waitForIdle();
+ }
+
+ public void assertHasRoots(String... labels) throws UiObjectNotFoundException {
+ List<String> missing = new ArrayList<>();
+ for (String label : labels) {
+ if (!findRoot(label).exists()) {
+ missing.add(label);
+ }
+ }
+ if (!missing.isEmpty()) {
+ Assert.fail(
+ "Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
+ }
+ }
+
+ public void assertHasFocus() {
+ assertHasFocus(ROOTS_LIST_ID);
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
new file mode 100644
index 000000000000..a112081dda26
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
@@ -0,0 +1,228 @@
+/*
+ * 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.documentsui.bots;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+
+import com.android.documentsui.R;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A test helper class that provides support for controlling DocumentsUI activities
+ * programmatically, and making assertions against the state of the UI.
+ *
+ * <p>Support for working directly with Roots and Directory view can be found
+ * in the respective bots.
+ */
+public class UiBot extends BaseBot {
+ public static final String TARGET_PKG = "com.android.documentsui";
+ private static final String LAUNCHER_PKG = "com.android.launcher";
+
+ public UiBot(UiDevice device, Context context, int timeout) {
+ super(device, context, timeout);
+ }
+
+ public void assertWindowTitle(String expected) {
+ // Turns out the title field on a window does not have
+ // an id associated with it at runtime (which confuses the hell out of me)
+ // In code we address this via "android.R.id.title".
+ UiObject2 o = find(By.text(expected));
+ // It's a bit of a conceit that we then *assert* that the title
+ // is the value that we used to identify the UiObject2.
+ // If the preceeding lookup fails, this'll choke with an NPE.
+ // But given the issue described in the comment above, we're
+ // going to do it anyway. Because we shouldn't be looking up
+ // the uiobject by it's expected content :|
+ assertEquals(expected, o.getText());
+ }
+
+ public void assertMenuEnabled(int id, boolean enabled) {
+ UiObject2 menu= findMenuWithName(mContext.getString(id));
+ assertNotNull(menu);
+ assertEquals(enabled, menu.isEnabled());
+ }
+
+ public void assertSearchTextField(boolean isFocused, String query)
+ throws UiObjectNotFoundException {
+ UiObject textField = findSearchViewTextField();
+ UiObject searchIcon = findSearchViewIcon();
+
+ assertFalse(searchIcon.exists());
+ assertTrue(textField.exists());
+ assertEquals(isFocused, textField.isFocused());
+ if(query != null) {
+ assertEquals(query, textField.getText());
+ }
+ }
+
+ public void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
+ assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
+ assertEquals(searchIconExists, findSearchViewIcon().exists());
+ }
+
+ public void assertInActionMode(boolean inActionMode) {
+ UiObject actionModeBar = findActionModeBar();
+ assertEquals(inActionMode, actionModeBar.exists());
+ }
+
+ public void openSearchView() throws UiObjectNotFoundException {
+ UiObject searchView = findSearchView();
+ searchView.click();
+ assertTrue(searchView.exists());
+ }
+
+ public void setSearchQuery(String query) throws UiObjectNotFoundException {
+ UiObject searchView = findSearchView();
+ assertTrue(searchView.exists());
+ UiObject searchTextField = findSearchViewTextField();
+ searchTextField.setText(query);
+ assertSearchTextField(true, query);
+ }
+
+ public UiObject openOverflowMenu() throws UiObjectNotFoundException {
+ UiObject obj = findMenuMoreOptions();
+ obj.click();
+ mDevice.waitForIdle(mTimeout);
+ return obj;
+ }
+
+ public void setDialogText(String text) throws UiObjectNotFoundException {
+ findDialogEditText().setText(text);
+ }
+
+ void switchViewMode() {
+ UiObject2 mode = menuGridMode();
+ if (mode != null) {
+ mode.click();
+ } else {
+ menuListMode().click();
+ }
+ }
+
+ UiObject2 menuGridMode() {
+ // Note that we're using By.desc rather than By.res, because of b/25285770
+ return find(By.desc("Grid view"));
+ }
+
+ UiObject2 menuListMode() {
+ // Note that we're using By.desc rather than By.res, because of b/25285770
+ return find(By.desc("List view"));
+ }
+
+ public UiObject2 menuDelete() {
+ return find(By.res("com.android.documentsui:id/menu_delete"));
+ }
+
+ public UiObject2 menuShare() {
+ return find(By.res("com.android.documentsui:id/menu_share"));
+ }
+
+ public UiObject2 menuRename() {
+ return findMenuWithName(mContext.getString(R.string.menu_rename));
+ }
+
+ public UiObject2 menuNewFolder() {
+ return findMenuWithName(mContext.getString(R.string.menu_create_dir));
+ }
+
+ UiObject findSearchView() {
+ return findObject("com.android.documentsui:id/menu_search");
+ }
+
+ UiObject findSearchViewTextField() {
+ return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
+ }
+
+ UiObject findSearchViewIcon() {
+ return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
+ }
+
+ UiObject findActionModeBar() {
+ return findObject("android:id/action_mode_bar");
+ }
+
+ public UiObject findDialogEditText() {
+ return findObject("android:id/content", "android:id/text1");
+ }
+
+ public UiObject findDialogOkButton() {
+ UiObject object = findObject("android:id/content", "android:id/button1");
+ object.waitForExists(mTimeout);
+ return object;
+ }
+
+ public UiObject findDialogCancelButton() {
+ UiObject object = findObject("android:id/content", "android:id/button2");
+ object.waitForExists(mTimeout);
+ return object;
+ }
+
+ UiObject findMenuLabelWithName(String label) {
+ UiSelector selector = new UiSelector().text(label);
+ return mDevice.findObject(selector);
+ }
+
+ UiObject2 findMenuWithName(String label) {
+ List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
+ Iterator<UiObject2> it = menuItems.iterator();
+
+ UiObject2 menuItem = null;
+ while(it.hasNext()) {
+ menuItem = it.next();
+ UiObject2 text = menuItem.findObject(By.text(label));
+ if(text != null) {
+ break;
+ }
+ }
+ return menuItem;
+ }
+
+ UiObject findMenuMoreOptions() {
+ UiSelector selector = new UiSelector().className("android.widget.ImageButton")
+ .descriptionContains("More options");
+ //TODO: use the system string ? android.R.string.action_menu_overflow_description
+ return mDevice.findObject(selector);
+ }
+
+ public void revealLauncher() {
+ mDevice.pressHome();
+ mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), mTimeout);
+ }
+
+ public void revealApp() {
+ mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), mTimeout);
+ mDevice.waitForIdle();
+ }
+
+ public void pressKey(int keyCode) {
+ mDevice.pressKeyCode(keyCode);
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 83299f0677cf..4b0bc41f19fe 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -28,6 +28,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
import com.android.documentsui.State;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
@@ -190,7 +191,7 @@ public class ModelTest extends AndroidTestCase {
assertEquals(ITEM_COUNT, seen.cardinality());
for (int i = 0; i < names.size()-1; ++i) {
- assertTrue(DocumentInfo.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
+ assertTrue(Shared.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index b1cb29e775b5..9447d9c18a83 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -50,7 +50,7 @@ public class MultiSelectManagerTest extends AndroidTestCase {
mCallback = new TestCallback();
mEnv = new TestSelectionEnvironment(items);
mAdapter = new TestDocumentsAdapter(items);
- mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE, null);
mManager.addCallback(mCallback);
}
@@ -174,7 +174,7 @@ public class MultiSelectManagerTest extends AndroidTestCase {
}
public void testSingleSelectMode() {
- mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
mManager.addCallback(mCallback);
longPress(20);
tap(13);
@@ -182,13 +182,61 @@ public class MultiSelectManagerTest extends AndroidTestCase {
}
public void testSingleSelectMode_ShiftTap() {
- mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
mManager.addCallback(mCallback);
longPress(13);
shiftTap(20);
assertSelection(items.get(20));
}
+ public void testRangeSelection() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(19);
+ assertRangeSelection(15, 19);
+ }
+
+ public void testRangeSelection_snapExpand() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(19);
+ mManager.snapRangeSelection(27);
+ assertRangeSelection(15, 27);
+ }
+
+ public void testRangeSelection_snapContract() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(27);
+ mManager.snapRangeSelection(19);
+ assertRangeSelection(15, 19);
+ }
+
+ public void testRangeSelection_snapInvert() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(27);
+ mManager.snapRangeSelection(3);
+ assertRangeSelection(3, 15);
+ }
+
+ public void testRangeSelection_multiple() {
+ mManager.startRangeSelection(15);
+ mManager.snapRangeSelection(27);
+ mManager.endRangeSelection();
+ mManager.startRangeSelection(42);
+ mManager.snapRangeSelection(57);
+ assertSelectionSize(29);
+ assertRangeSelected(15, 27);
+ assertRangeSelected(42, 57);
+
+ }
+
+ public void testRangeSelection_singleSelect() {
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE, null);
+ mManager.addCallback(mCallback);
+ mManager.startRangeSelection(11);
+ mManager.snapRangeSelection(19);
+ assertSelectionSize(1);
+ assertSelection(items.get(19));
+ }
+
public void testProvisionalSelection() {
Selection s = mManager.getSelection();
assertSelection();
@@ -198,24 +246,73 @@ public class MultiSelectManagerTest extends AndroidTestCase {
provisional.append(2, true);
s.setProvisionalSelection(getItemIds(provisional));
assertSelection(items.get(1), items.get(2));
+ }
- provisional.delete(1);
+ public void testProvisionalSelection_Replace() {
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(1, true);
+ provisional.append(2, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+
+ provisional.clear();
provisional.append(3, true);
+ provisional.append(4, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(2), items.get(3));
+ assertSelection(items.get(3), items.get(4));
+ }
- s.applyProvisionalSelection();
- assertSelection(items.get(2), items.get(3));
+ public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(1, true);
+ provisional.append(2, true);
+ s.setProvisionalSelection(getItemIds(provisional));
provisional.clear();
+ provisional.append(1, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(1));
+ }
+
+ public void testProvisionalSelection_Apply() {
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(1, true);
+ provisional.append(2, true);
+ s.setProvisionalSelection(getItemIds(provisional));
+ s.applyProvisionalSelection();
+ assertSelection(items.get(1), items.get(2));
+ }
+
+ public void testProvisionalSelection_Cancel() {
+ mManager.toggleSelection(items.get(1));
+ mManager.toggleSelection(items.get(2));
+ Selection s = mManager.getSelection();
+
+ SparseBooleanArray provisional = new SparseBooleanArray();
provisional.append(3, true);
provisional.append(4, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(2), items.get(3), items.get(4));
+ s.cancelProvisionalSelection();
+
+ // Original selection should remain.
+ assertSelection(items.get(1), items.get(2));
+ }
+
+ public void testProvisionalSelection_IntersectsAppliedSelection() {
+ mManager.toggleSelection(items.get(1));
+ mManager.toggleSelection(items.get(2));
+ Selection s = mManager.getSelection();
- provisional.delete(3);
+ SparseBooleanArray provisional = new SparseBooleanArray();
+ provisional.append(2, true);
+ provisional.append(3, true);
s.setProvisionalSelection(getItemIds(provisional));
- assertSelection(items.get(2), items.get(3), items.get(4));
+ assertSelection(items.get(1), items.get(2), items.get(3));
}
private static Set<String> getItemIds(SparseBooleanArray selection) {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java
index a6aba7b06816..2481dc39ed7f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java
@@ -22,30 +22,36 @@ import android.test.suitebuilder.annotation.SmallTest;
@SmallTest
public class DocumentInfoTest extends AndroidTestCase {
+ private static final DocumentInfo TEST_DOC
+ = createDocInfo("authority.a", "doc.1", "text/plain");
+
public void testEquals() throws Exception {
- DocumentInfo doc = createDocInfo("authority.a", "doc.1", "text/plain");
- assertEquals(doc, doc);
+ assertEquals(TEST_DOC, TEST_DOC);
+ assertEquals(TEST_DOC, createDocInfo("authority.a", "doc.1", "text/plain"));
+ }
+
+ public void testEquals_HandlesNulls() throws Exception {
+ assertFalse(TEST_DOC.equals(null));
+ }
+
+ public void testEquals_HandlesNullFields() throws Exception {
+ assertFalse(TEST_DOC.equals(new DocumentInfo()));
+ assertFalse(new DocumentInfo().equals(TEST_DOC));
}
public void testNotEquals_differentAuthority() throws Exception {
- DocumentInfo docA = createDocInfo("authority.a", "doc.1", "text/plain");
- DocumentInfo docB = createDocInfo("authority.b", "doc.1", "text/plain");
- assertFalse(docA.equals(docB));
+ assertFalse(TEST_DOC.equals(createDocInfo("authority.b", "doc.1", "text/plain")));
}
public void testNotEquals_differentDocId() throws Exception {
- DocumentInfo docA = createDocInfo("authority.a", "doc.1", "text/plain");
- DocumentInfo docB = createDocInfo("authority.a", "doc.2", "text/plain");
- assertFalse(docA.equals(docB));
+ assertFalse(TEST_DOC.equals(createDocInfo("authority.a", "doc.2", "text/plain")));
}
public void testNotEquals_differentMimetype() throws Exception {
- DocumentInfo docA = createDocInfo("authority.a", "doc.1", "text/plain");
- DocumentInfo docB = createDocInfo("authority.a", "doc.1", "image/png");
- assertFalse(docA.equals(docB));
+ assertFalse(TEST_DOC.equals(createDocInfo("authority.a", "doc.1", "image/png")));
}
- private DocumentInfo createDocInfo(String authority, String docId, String mimeType) {
+ private static DocumentInfo createDocInfo(String authority, String docId, String mimeType) {
DocumentInfo doc = new DocumentInfo();
doc.authority = authority;
doc.documentId = docId;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
index a1c6dabca55c..9147a578f8e1 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
@@ -21,7 +21,6 @@ import static junit.framework.Assert.assertTrue;
import android.app.Notification;
import android.app.Notification.Builder;
import android.content.Context;
-import android.os.RemoteException;
import com.android.documentsui.R;
import com.android.documentsui.model.DocumentInfo;
@@ -38,7 +37,7 @@ public class TestJob extends Job {
}
@Override
- void start() throws RemoteException {
+ void start() {
mStarted = true;
}
diff --git a/packages/ExternalStorageProvider/res/values-af/strings.xml b/packages/ExternalStorageProvider/res/values-af/strings.xml
index b5a159d27211..1de881d92627 100644
--- a/packages/ExternalStorageProvider/res/values-af/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-af/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Eksterne berging"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interne berging"</string>
- <string name="root_home" msgid="7931555396767513359">"Tuis"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-am/strings.xml b/packages/ExternalStorageProvider/res/values-am/strings.xml
index f4f296d5c314..230fb066e783 100644
--- a/packages/ExternalStorageProvider/res/values-am/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-am/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ውጫዊ ማከማቻ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ውስጣዊ ማከማቻ"</string>
- <string name="root_home" msgid="7931555396767513359">"መነሻ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ሰነዶች"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ar/strings.xml b/packages/ExternalStorageProvider/res/values-ar/strings.xml
index 4eee3e8e5de4..b20a0563bd01 100644
--- a/packages/ExternalStorageProvider/res/values-ar/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ar/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"وحدة تخزين خارجية"</string>
<string name="root_internal_storage" msgid="827844243068584127">"وحدة تخزين داخلية"</string>
- <string name="root_home" msgid="7931555396767513359">"الرئيسية"</string>
+ <string name="root_documents" msgid="4051252304075469250">"مستندات"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml b/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml
index f7e5f8b78a79..cd5ba2fe63d1 100644
--- a/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-az-rAZ/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Xarici Yaddaş"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Daxili yaddaş"</string>
- <string name="root_home" msgid="7931555396767513359">"Əsas səhifə"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Sənədlər"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml b/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
index b280d4f66a2f..fefbc282d6b3 100644
--- a/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Spoljna memorija"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interna memorija"</string>
- <string name="root_home" msgid="7931555396767513359">"Početni"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-bg/strings.xml b/packages/ExternalStorageProvider/res/values-bg/strings.xml
index 7081b172b36e..f5dce3189393 100644
--- a/packages/ExternalStorageProvider/res/values-bg/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bg/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Външно хранилище"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Вътрешно хранилище"</string>
- <string name="root_home" msgid="7931555396767513359">"Начална директория"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml b/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml
index 842aed448655..36680658fb9f 100644
--- a/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bn-rBD/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"বাহ্যিক সঞ্চয়স্থান"</string>
<string name="root_internal_storage" msgid="827844243068584127">"অভ্যন্তরীণ সঞ্চয়স্থান"</string>
- <string name="root_home" msgid="7931555396767513359">"হোম"</string>
+ <string name="root_documents" msgid="4051252304075469250">"দস্তাবেজগুলি"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-ar/config.xml b/packages/ExternalStorageProvider/res/values-bs-rBA/strings.xml
index 843a8aad4051..20177f05d5f2 100644
--- a/packages/DocumentsUI/res/values-ar/config.xml
+++ b/packages/ExternalStorageProvider/res/values-bs-rBA/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -16,5 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+ <string name="app_label" msgid="7123375275748530234">"Aplikacija za vanjsku pohranu"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Interna pohrana"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ca/strings.xml b/packages/ExternalStorageProvider/res/values-ca/strings.xml
index b3fd9f77d9ec..15e9d4604a8b 100644
--- a/packages/ExternalStorageProvider/res/values-ca/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ca/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Emmagatzematge extern"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Emmagatzematge intern"</string>
- <string name="root_home" msgid="7931555396767513359">"Inici"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-cs/strings.xml b/packages/ExternalStorageProvider/res/values-cs/strings.xml
index 2eab59673aa8..b68a928e8a6c 100644
--- a/packages/ExternalStorageProvider/res/values-cs/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-cs/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externí úložiště"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interní úložiště"</string>
- <string name="root_home" msgid="7931555396767513359">"Výchozí adresář"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-da/strings.xml b/packages/ExternalStorageProvider/res/values-da/strings.xml
index d008f0ea16ec..dc565aeca851 100644
--- a/packages/ExternalStorageProvider/res/values-da/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-da/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ekstern lagerplads"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagerplads"</string>
- <string name="root_home" msgid="7931555396767513359">"Hjem"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-de/strings.xml b/packages/ExternalStorageProvider/res/values-de/strings.xml
index 50fc6800dd24..318634a2ee22 100644
--- a/packages/ExternalStorageProvider/res/values-de/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-de/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externer Speicher"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interner Speicher"</string>
- <string name="root_home" msgid="7931555396767513359">"Zuhause"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-el/strings.xml b/packages/ExternalStorageProvider/res/values-el/strings.xml
index 9537afdeef2d..b3aa792521bc 100644
--- a/packages/ExternalStorageProvider/res/values-el/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-el/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Εξωτερικός αποθηκευτικός χώρος"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Εσωτερικός αποθηκευτικός χώρος"</string>
- <string name="root_home" msgid="7931555396767513359">"Αρχική οθόνη"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Έγγραφα"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml b/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml
index be7aebc8af14..f88eb9e32044 100644
--- a/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rAU/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
- <string name="root_home" msgid="7931555396767513359">"Home"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
index be7aebc8af14..f88eb9e32044 100644
--- a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
- <string name="root_home" msgid="7931555396767513359">"Home"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
index be7aebc8af14..f88eb9e32044 100644
--- a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
- <string name="root_home" msgid="7931555396767513359">"Home"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
index 64a042d1dd36..e7e38b56e1b2 100644
--- a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
- <string name="root_home" msgid="7931555396767513359">"Casa"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-es/strings.xml b/packages/ExternalStorageProvider/res/values-es/strings.xml
index d59755e8a269..e7e38b56e1b2 100644
--- a/packages/ExternalStorageProvider/res/values-es/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
- <string name="root_home" msgid="7931555396767513359">"Inicio"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
index 7ea2caa0ee73..6824e9d7d637 100644
--- a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Väline talletusruum"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Sisemine salvestusruum"</string>
- <string name="root_home" msgid="7931555396767513359">"Kodu"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumendid"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml b/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml
index 2f94acbbcac0..5881bf2cf05a 100644
--- a/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-eu-rES/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Kanpoko memoria"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Barneko memoria"</string>
- <string name="root_home" msgid="7931555396767513359">"Etxea"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentuak"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fa/strings.xml b/packages/ExternalStorageProvider/res/values-fa/strings.xml
index c8c49a5475be..9ae8a479604f 100644
--- a/packages/ExternalStorageProvider/res/values-fa/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"حافظه خارجی"</string>
<string name="root_internal_storage" msgid="827844243068584127">"حافظهٔ داخلی"</string>
- <string name="root_home" msgid="7931555396767513359">"صفحه اصلی"</string>
+ <string name="root_documents" msgid="4051252304075469250">"اسناد"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fi/strings.xml b/packages/ExternalStorageProvider/res/values-fi/strings.xml
index 660228ae18dd..9d1fbaac24c2 100644
--- a/packages/ExternalStorageProvider/res/values-fi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fi/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ulkoinen tallennustila"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Sisäinen tallennustila"</string>
- <string name="root_home" msgid="7931555396767513359">"Koti"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentit"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
index b94682f49cae..b3fdd48416e7 100644
--- a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
- <string name="root_home" msgid="7931555396767513359">"Accueil"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr/strings.xml b/packages/ExternalStorageProvider/res/values-fr/strings.xml
index 6a84bb4a3c08..b3fdd48416e7 100644
--- a/packages/ExternalStorageProvider/res/values-fr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
- <string name="root_home" msgid="7931555396767513359">"Répertoire de base"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml b/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml
index d51eae950d83..780213fa6df6 100644
--- a/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-gl-rES/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamento interno"</string>
- <string name="root_home" msgid="7931555396767513359">"Inicio"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml
index 3bcc72dd1282..ec8a0bd4923b 100644
--- a/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-gu-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"બાહ્ય સંગ્રહ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"આંતરિક સંગ્રહ"</string>
- <string name="root_home" msgid="7931555396767513359">"હોમ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"દસ્તાવેજો"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hi/strings.xml b/packages/ExternalStorageProvider/res/values-hi/strings.xml
index 93cc7126a83a..853808136715 100644
--- a/packages/ExternalStorageProvider/res/values-hi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hi/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"बाहरी मेमोरी"</string>
<string name="root_internal_storage" msgid="827844243068584127">"मोबाइल मेमोरी"</string>
- <string name="root_home" msgid="7931555396767513359">"होम"</string>
+ <string name="root_documents" msgid="4051252304075469250">"दस्तावेज़"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hr/strings.xml b/packages/ExternalStorageProvider/res/values-hr/strings.xml
index c866351c6c92..a74f8e87288d 100644
--- a/packages/ExternalStorageProvider/res/values-hr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hr/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Vanjska pohrana"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Unutarnja pohrana"</string>
- <string name="root_home" msgid="7931555396767513359">"Početna"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hu/strings.xml b/packages/ExternalStorageProvider/res/values-hu/strings.xml
index db1c7db050a6..3f72b418f289 100644
--- a/packages/ExternalStorageProvider/res/values-hu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hu/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Külső tárhely"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Belső tárhely"</string>
- <string name="root_home" msgid="7931555396767513359">"Otthon"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentumok"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
index 0e1de49c3dc5..5360124566ae 100644
--- a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Արտաքին պահոց"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Ներքին պահոց"</string>
- <string name="root_home" msgid="7931555396767513359">"Գլխավոր էջ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Փաստաթղթեր"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-in/strings.xml b/packages/ExternalStorageProvider/res/values-in/strings.xml
index ca7f823b6832..42acde7b8e32 100644
--- a/packages/ExternalStorageProvider/res/values-in/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-in/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Penyimpanan Eksternal"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Penyimpanan internal"</string>
- <string name="root_home" msgid="7931555396767513359">"Rumah"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumen"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml b/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml
index ad0400264de7..03061650b103 100644
--- a/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-is-rIS/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ytri geymsla"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Innbyggð geymsla"</string>
- <string name="root_home" msgid="7931555396767513359">"Heim"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Skjöl"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-it/strings.xml b/packages/ExternalStorageProvider/res/values-it/strings.xml
index 686ee1a6d829..957b5ffe22e7 100644
--- a/packages/ExternalStorageProvider/res/values-it/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-it/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Archivio esterno"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Memoria interna"</string>
- <string name="root_home" msgid="7931555396767513359">"Home"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-iw/strings.xml b/packages/ExternalStorageProvider/res/values-iw/strings.xml
index b45fb5c60784..775506a79df2 100644
--- a/packages/ExternalStorageProvider/res/values-iw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-iw/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"אחסון חיצוני"</string>
<string name="root_internal_storage" msgid="827844243068584127">"אחסון פנימי"</string>
- <string name="root_home" msgid="7931555396767513359">"דף הבית"</string>
+ <string name="root_documents" msgid="4051252304075469250">"מסמכים"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ja/strings.xml b/packages/ExternalStorageProvider/res/values-ja/strings.xml
index 5c09bf4f242b..188fca29a4c8 100644
--- a/packages/ExternalStorageProvider/res/values-ja/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ja/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部ストレージ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"内部ストレージ"</string>
- <string name="root_home" msgid="7931555396767513359">"ホーム"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ドキュメント"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
index c1bc5c74dfd7..cc04860036d5 100644
--- a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"გარე მეხსიერება"</string>
<string name="root_internal_storage" msgid="827844243068584127">"შიდა მეხსიერება"</string>
- <string name="root_home" msgid="7931555396767513359">"მთავარი"</string>
+ <string name="root_documents" msgid="4051252304075469250">"დოკუმენტები"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml b/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml
index cf0578210c81..ad49036c9d99 100644
--- a/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-kk-rKZ/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Сыртқы жад"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Ішкі жад"</string>
- <string name="root_home" msgid="7931555396767513359">"Негізгі бет"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Құжаттар"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
index a2e926fa6315..9cf76d4053e4 100644
--- a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ឧបករណ៍​​ផ្ទុក​ខាងក្រៅ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ឧបករណ៍​ផ្ទុក​ខាង​ក្នុង"</string>
- <string name="root_home" msgid="7931555396767513359">"ដើម"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ឯកសារ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml
index 1f0cfbf58290..e32b1d3f978b 100644
--- a/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-kn-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆ"</string>
- <string name="root_home" msgid="7931555396767513359">"ಮುಖಪುಟ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ಡಾಕ್ಯುಮೆಂಟ್‌ಗಳು"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ko/strings.xml b/packages/ExternalStorageProvider/res/values-ko/strings.xml
index 365648d33938..849d37e602f5 100644
--- a/packages/ExternalStorageProvider/res/values-ko/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ko/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"외부 저장소"</string>
<string name="root_internal_storage" msgid="827844243068584127">"내부 저장소"</string>
- <string name="root_home" msgid="7931555396767513359">"홈"</string>
+ <string name="root_documents" msgid="4051252304075469250">"문서"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml b/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml
index 4a0f211e3ca8..d3ccf7f14449 100644
--- a/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ky-rKG/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Тышкы сактагыч"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Ички сактагыч"</string>
- <string name="root_home" msgid="7931555396767513359">"Башкы бет"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документтер"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
index 9de6519f1211..cecd9f5683a9 100644
--- a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍນອກ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍໃນ"</string>
- <string name="root_home" msgid="7931555396767513359">"​ໜ້າຫຼັກ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ເອ​ກະ​ສານ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lt/strings.xml b/packages/ExternalStorageProvider/res/values-lt/strings.xml
index 84ca2d4a4f4d..240ea8900089 100644
--- a/packages/ExternalStorageProvider/res/values-lt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lt/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Išorinė atmintinė"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Vidinė atmintinė"</string>
- <string name="root_home" msgid="7931555396767513359">"Pagrindinis katalogas"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentai"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lv/strings.xml b/packages/ExternalStorageProvider/res/values-lv/strings.xml
index 7eff0b9408e1..d308fe830798 100644
--- a/packages/ExternalStorageProvider/res/values-lv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lv/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ārējā krātuve"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Iekšējā atmiņa"</string>
- <string name="root_home" msgid="7931555396767513359">"Sākumdirektorijs"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml b/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml
index fe6b753c125c..8943d23d1e2d 100644
--- a/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mk-rMK/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Надворешна меморија"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внатрешна меморија"</string>
- <string name="root_home" msgid="7931555396767513359">"Почетна страница"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
index 5369ec9ba0f9..08e6dae52b53 100644
--- a/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ml-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ബാഹ്യ സ്റ്റോറേജ്"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ആന്തരിക സ്റ്റോറേജ്"</string>
- <string name="root_home" msgid="7931555396767513359">"വീട്"</string>
+ <string name="root_documents" msgid="4051252304075469250">"പ്രമാണങ്ങൾ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
index 4604f327bc07..3d7b7f73881b 100644
--- a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Гадаад сан"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Дотоод сан"</string>
- <string name="root_home" msgid="7931555396767513359">"Нүүр хуудас"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документүүд"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml
index 1310b0e361f8..a7e7fbbceb38 100644
--- a/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mr-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"बाह्य संचयन"</string>
<string name="root_internal_storage" msgid="827844243068584127">"अंतर्गत संचयन"</string>
- <string name="root_home" msgid="7931555396767513359">"निवास"</string>
+ <string name="root_documents" msgid="4051252304075469250">"दस्तऐवज"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
index 007a1be73c3e..cb4d73653148 100644
--- a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Storan Luaran"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Storan dalaman"</string>
- <string name="root_home" msgid="7931555396767513359">"Rumah"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumen"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml b/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml
index 2df9a3322370..dc9d684b1919 100644
--- a/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-my-rMM/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ပြင်ပသိုလှောင်ရာပစ္စည်း"</string>
<string name="root_internal_storage" msgid="827844243068584127">"စက်တွင်း သိုလှောင်ထားမှု"</string>
- <string name="root_home" msgid="7931555396767513359">"ပင်မ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"စာရွက်စာတန်းများ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-nb/strings.xml b/packages/ExternalStorageProvider/res/values-nb/strings.xml
index 315d9325ba66..a9ecb691d727 100644
--- a/packages/ExternalStorageProvider/res/values-nb/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nb/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
- <string name="root_home" msgid="7931555396767513359">"Hjem"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml b/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml
index 4a9a8cdf8018..52940438cfd3 100644
--- a/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ne-rNP/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"बाह्य भण्डारण"</string>
<string name="root_internal_storage" msgid="827844243068584127">"आन्तरिक भण्डारण"</string>
- <string name="root_home" msgid="7931555396767513359">"गृह"</string>
+ <string name="root_documents" msgid="4051252304075469250">"कागजातहरू"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-nl/strings.xml b/packages/ExternalStorageProvider/res/values-nl/strings.xml
index 0ae88ceb5a0f..bde61665d971 100644
--- a/packages/ExternalStorageProvider/res/values-nl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nl/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externe opslag"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interne opslag"</string>
- <string name="root_home" msgid="7931555396767513359">"Startscherm"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documenten"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml
index a805dd861663..0e91589adc74 100644
--- a/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pa-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ਬਾਹਰੀ ਸਟੋਰੇਜ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ"</string>
- <string name="root_home" msgid="7931555396767513359">"ਘਰ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ਦਸਤਾਵੇਜ਼"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pl/strings.xml b/packages/ExternalStorageProvider/res/values-pl/strings.xml
index 66d83c744a92..6c5e7d78b0db 100644
--- a/packages/ExternalStorageProvider/res/values-pl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pl/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Pamięć zewnętrzna"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Pamięć wewnętrzna"</string>
- <string name="root_home" msgid="7931555396767513359">"Katalog domowy"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml
index 958eef48529d..77c89b8bee83 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rBR/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
- <string name="root_home" msgid="7931555396767513359">"Página inicial"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
index c8865e1bfe4a..77c89b8bee83 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
- <string name="root_home" msgid="7931555396767513359">"Casa"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt/strings.xml b/packages/ExternalStorageProvider/res/values-pt/strings.xml
index 958eef48529d..77c89b8bee83 100644
--- a/packages/ExternalStorageProvider/res/values-pt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
- <string name="root_home" msgid="7931555396767513359">"Página inicial"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ro/strings.xml b/packages/ExternalStorageProvider/res/values-ro/strings.xml
index 5bb4a7c9edb1..abd0b98a1f0e 100644
--- a/packages/ExternalStorageProvider/res/values-ro/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ro/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stocare externă"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Stocare internă"</string>
- <string name="root_home" msgid="7931555396767513359">"Director principal"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ru/strings.xml b/packages/ExternalStorageProvider/res/values-ru/strings.xml
index a6513713bf49..740272f7b5cd 100644
--- a/packages/ExternalStorageProvider/res/values-ru/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ru/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Внешний накопитель"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внутренний накопитель"</string>
- <string name="root_home" msgid="7931555396767513359">"Мои файлы"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документы"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml b/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml
index 5292403b87bd..15334bbee626 100644
--- a/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-si-rLK/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"බාහිර ආචයනය"</string>
<string name="root_internal_storage" msgid="827844243068584127">"අභ්‍යන්තර ආචයනය"</string>
- <string name="root_home" msgid="7931555396767513359">"මුල් පිටුව"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ලේඛන"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sk/strings.xml b/packages/ExternalStorageProvider/res/values-sk/strings.xml
index 515788875ed8..9be7b79d022b 100644
--- a/packages/ExternalStorageProvider/res/values-sk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sk/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externý ukladací priestor"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interné úložisko"</string>
- <string name="root_home" msgid="7931555396767513359">"Predvolený adresár"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sl/strings.xml b/packages/ExternalStorageProvider/res/values-sl/strings.xml
index dd2cc241ab0f..6ffa6987ebf4 100644
--- a/packages/ExternalStorageProvider/res/values-sl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sl/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Zunanja shramba"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Notranja shramba"</string>
- <string name="root_home" msgid="7931555396767513359">"Korenska mapa"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml b/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml
index 3aafd1c69f5a..dc346ea93aa8 100644
--- a/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sq-rAL/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Hapësirë e jashtme ruajtjeje"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Hapësira e brendshme ruajtëse"</string>
- <string name="root_home" msgid="7931555396767513359">"Kreu"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sr/strings.xml b/packages/ExternalStorageProvider/res/values-sr/strings.xml
index 2d987efcfc4a..54238a43080d 100644
--- a/packages/ExternalStorageProvider/res/values-sr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sr/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Спољна меморија"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Интерна меморија"</string>
- <string name="root_home" msgid="7931555396767513359">"Почетни"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sv/strings.xml b/packages/ExternalStorageProvider/res/values-sv/strings.xml
index bc4788afb863..6eac11ec1d37 100644
--- a/packages/ExternalStorageProvider/res/values-sv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sv/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Extern lagring"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
- <string name="root_home" msgid="7931555396767513359">"Hem"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokument"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sw/strings.xml b/packages/ExternalStorageProvider/res/values-sw/strings.xml
index dcca92a70192..0d0e4835c6e5 100644
--- a/packages/ExternalStorageProvider/res/values-sw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sw/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Hifadhi ya Nje"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Hifadhi ya ndani"</string>
- <string name="root_home" msgid="7931555396767513359">"Mwanzo"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Hati"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml
index b859e7a25b24..d7bafbc021f9 100644
--- a/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ta-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"வெளிப்புறச் சேமிப்பிடம்"</string>
<string name="root_internal_storage" msgid="827844243068584127">"அகச் சேமிப்பிடம்"</string>
- <string name="root_home" msgid="7931555396767513359">"முகப்பு"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ஆவணங்கள்"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml
index 934877ed76c9..800d18eed80a 100644
--- a/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-te-rIN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"బాహ్య నిల్వ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"అంతర్గత నిల్వ"</string>
- <string name="root_home" msgid="7931555396767513359">"హోమ్"</string>
+ <string name="root_documents" msgid="4051252304075469250">"పత్రాలు"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-th/strings.xml b/packages/ExternalStorageProvider/res/values-th/strings.xml
index 957d6b79ed70..796635ee3522 100644
--- a/packages/ExternalStorageProvider/res/values-th/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-th/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ที่จัดเก็บข้อมูลภายนอก"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ที่จัดเก็บข้อมูลภายใน"</string>
- <string name="root_home" msgid="7931555396767513359">"Home"</string>
+ <string name="root_documents" msgid="4051252304075469250">"เอกสาร"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-tl/strings.xml b/packages/ExternalStorageProvider/res/values-tl/strings.xml
index be7aebc8af14..529cdc2c8924 100644
--- a/packages/ExternalStorageProvider/res/values-tl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tl/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
- <string name="root_home" msgid="7931555396767513359">"Home"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Mga Dokumento"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-tr/strings.xml b/packages/ExternalStorageProvider/res/values-tr/strings.xml
index 2ce1411e286b..d6bd52a8a8fa 100644
--- a/packages/ExternalStorageProvider/res/values-tr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tr/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Harici Depolama"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Dahili depolama"</string>
- <string name="root_home" msgid="7931555396767513359">"Ev"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokümanlar"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-uk/strings.xml b/packages/ExternalStorageProvider/res/values-uk/strings.xml
index 0033bca5c0ee..b8206e0684a2 100644
--- a/packages/ExternalStorageProvider/res/values-uk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uk/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Зовнішня пам’ять"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внутрішня пам’ять"</string>
- <string name="root_home" msgid="7931555396767513359">"Головний екран"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml b/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml
index df46fb08c0d1..02454bc3817c 100644
--- a/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ur-rPK/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"بیرونی اسٹوریج"</string>
<string name="root_internal_storage" msgid="827844243068584127">"داخلی اسٹوریج"</string>
- <string name="root_home" msgid="7931555396767513359">"ہوم"</string>
+ <string name="root_documents" msgid="4051252304075469250">"دستاویزات"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml b/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml
index 069e137f8cd2..07cc14c4cbca 100644
--- a/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uz-rUZ/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Tashqi xotira"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Ichki xotira"</string>
- <string name="root_home" msgid="7931555396767513359">"Mening fayllarim"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Hujjatlar"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-vi/strings.xml b/packages/ExternalStorageProvider/res/values-vi/strings.xml
index 39e9c6c5bdfe..b171c933fed4 100644
--- a/packages/ExternalStorageProvider/res/values-vi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-vi/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Bộ nhớ ngoài"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Bộ nhớ trong"</string>
- <string name="root_home" msgid="7931555396767513359">"Nhà riêng"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Tài liệu"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
index ea20dce6b58c..7df77dd8a919 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部存储设备"</string>
<string name="root_internal_storage" msgid="827844243068584127">"内部存储空间"</string>
- <string name="root_home" msgid="7931555396767513359">"主目录"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文档"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
index 27f1f0a39be0..62d8afb372fb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
<string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
- <string name="root_home" msgid="7931555396767513359">"主目錄"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文件"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
index b2d764ac674a..62d8afb372fb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
<string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
- <string name="root_home" msgid="7931555396767513359">"主畫面"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文件"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zu/strings.xml b/packages/ExternalStorageProvider/res/values-zu/strings.xml
index 8a7c7df6cc55..4a0a845eac20 100644
--- a/packages/ExternalStorageProvider/res/values-zu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zu/strings.xml
@@ -18,5 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Isitoreji sangaphandle"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Isitoreji sangaphakathi"</string>
- <string name="root_home" msgid="7931555396767513359">"Ekhaya"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Amadokhumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values/strings.xml b/packages/ExternalStorageProvider/res/values/strings.xml
index e48436ecb8ba..8b16d3c3b9d4 100644
--- a/packages/ExternalStorageProvider/res/values/strings.xml
+++ b/packages/ExternalStorageProvider/res/values/strings.xml
@@ -20,6 +20,6 @@
<!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
<string name="root_internal_storage">Internal storage</string>
- <!-- Title for user home dir. [CHAR LIMIT=24] -->
- <string name="root_home">Home</string>
+ <!-- Title for directory in which a user may store their own documents and files. [CHAR LIMIT=24] -->
+ <string name="root_documents">Documents</string>
</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index f89934dc50e4..97dfd47aea9f 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -199,7 +199,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
final RootInfo root = new RootInfo();
root.rootId = ROOT_ID_HOME;
mRoots.put(root.rootId, root);
- root.title = getContext().getString(R.string.root_home);
+ root.title = getContext().getString(R.string.root_documents);
// Only report bytes on *volumes*...as a matter of policy.
root.reportAvailableBytes = false;
@@ -214,9 +214,9 @@ public class ExternalStorageProvider extends DocumentsProvider {
// Create the "Home" directory on disk, but don't the localized root.title
// since the directories shouldn't be localized.
root.visiblePath = new File(
- primaryVolume.getPathForUser(userId), Environment.DIRECTORY_HOME);
+ primaryVolume.getPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
root.path = new File(
- primaryVolume.getInternalPathForUser(userId), root.rootId);
+ primaryVolume.getInternalPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
try {
root.docId = getDocIdForFile(root.path);
} catch (FileNotFoundException e) {
diff --git a/packages/Keyguard/res/values-h560dp/dimens.xml b/packages/Keyguard/res/values-h560dp/dimens.xml
index 16831133c325..469ce520133e 100644
--- a/packages/Keyguard/res/values-h560dp/dimens.xml
+++ b/packages/Keyguard/res/values-h560dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">96dp</dimen>
+ <dimen name="widget_big_font_size">84dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/Keyguard/res/values-h650dp/dimens.xml b/packages/Keyguard/res/values-h650dp/dimens.xml
index 1cd216285c73..cb89cb46fc3e 100644
--- a/packages/Keyguard/res/values-h650dp/dimens.xml
+++ b/packages/Keyguard/res/values-h650dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">100dp</dimen>
+ <dimen name="widget_big_font_size">88dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index a487644e2de1..c34012dc85a8 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -20,5 +20,5 @@
<resources>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_big_font_size">100dp</dimen>
+ <dimen name="widget_big_font_size">88dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index b181682f90ba..a3b01b6acfe4 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -26,9 +26,9 @@
<dimen name="keyguard_security_view_margin">12dp</dimen>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_big_font_size">125dp</dimen>
+ <dimen name="widget_big_font_size">110dp</dimen>
<dimen name="widget_label_font_size">16sp</dimen>
- <dimen name="bottom_text_spacing_digital">-16dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-1dp</dimen>
<!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
index 08ab791f856e..210c7eb61908 100644
--- a/packages/Keyguard/res/values-sw720dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -24,5 +24,5 @@
<!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
<dimen name="keyguard_security_height">420dp</dimen>
- <dimen name="widget_big_font_size">138dp</dimen>
+ <dimen name="widget_big_font_size">122dp</dimen>
</resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 18d893a7b3f1..7b952be2f7f3 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -39,9 +39,9 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Default clock parameters -->
- <dimen name="bottom_text_spacing_digital">-10dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-1dp</dimen>
<dimen name="widget_label_font_size">14sp</dimen>
- <dimen name="widget_big_font_size">88dp</dimen>
+ <dimen name="widget_big_font_size">78dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
<dimen name="appear_y_translation_start">32dp</dimen>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index ec2a173d52ea..434631e1c0fd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -413,7 +413,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
* @return true if the menu key should be enabled
*/
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
- private boolean shouldEnableMenuKey() {
+ public boolean shouldEnableMenuKey() {
final Resources res = getResources();
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
@@ -421,15 +421,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
return !configDisabled || isTestHarness || fileOverride;
}
- public boolean handleMenuKey() {
- // The following enables the MENU key to work for testing automation
- if (shouldEnableMenuKey()) {
- dismiss();
- return true;
- }
- return false;
- }
-
public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
// Update ViewMediator with the current input method requirements
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index cedd88d44807..fe98cb876854 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -89,7 +89,12 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
return true;
}
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
- int number = keyCode - KeyEvent.KEYCODE_0 ;
+ int number = keyCode - KeyEvent.KEYCODE_0;
+ performNumberClick(number);
+ return true;
+ }
+ if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 && keyCode <= KeyEvent.KEYCODE_NUMPAD_9) {
+ int number = keyCode - KeyEvent.KEYCODE_NUMPAD_0;
performNumberClick(number);
return true;
}
diff --git a/packages/MtpDocumentsProvider/res/values/strings.xml b/packages/MtpDocumentsProvider/res/values/strings.xml
index 43a420cf6d97..f3a3fcf0563c 100644
--- a/packages/MtpDocumentsProvider/res/values/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values/strings.xml
@@ -25,4 +25,8 @@
<string name="accessing_notification_title">Accessing files from <xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g></string>
<!-- Description of notification showing Files app is accessing files in a MTP device. [CHAR LIMIT=60]-->
<string name="accessing_notification_description">Don\'t disconnect the device</string>
+ <!-- Error message shown in Files app when the connected MTP device is busy. [CHAR LIMIT=150]-->
+ <string name="error_busy_device">The other device is busy. You can\'t transfer files until it\'s available.</string>
+ <!-- Error message shown in Files app when the connected MTP device may be locked. [CHAR LIMIT=150]-->
+ <string name="error_locked_device">No files found. The other device may be locked. If so, unlock it and try again.</string>
</resources>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
index 6a98405d5026..38435f4afa47 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -133,6 +133,8 @@ public class AppFuse {
return mCallback.readObjectBytes(inode, offset, size, mBuffer);
} catch (IOException e) {
return -OsConstants.EIO;
+ } catch (UnsupportedOperationException e) {
+ return -OsConstants.ENOTSUP;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index ef1e8e20aaff..044a061ee8b2 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -16,9 +16,10 @@
package com.android.mtp;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
import android.content.ContentResolver;
import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -26,6 +27,8 @@ import android.os.Process;
import android.provider.DocumentsContract;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
@@ -39,60 +42,46 @@ import java.util.LinkedList;
* background thread to load the rest documents and caches its result for next requests.
* TODO: Rename this class to ObjectInfoLoader
*/
-class DocumentLoader {
+class DocumentLoader implements AutoCloseable {
static final int NUM_INITIAL_ENTRIES = 10;
static final int NUM_LOADING_ENTRIES = 20;
static final int NOTIFY_PERIOD_MS = 500;
+ private final MtpDeviceRecord mDevice;
private final MtpManager mMtpManager;
private final ContentResolver mResolver;
private final MtpDatabase mDatabase;
private final TaskList mTaskList = new TaskList();
- private boolean mHasBackgroundThread = false;
+ private Thread mBackgroundThread;
- DocumentLoader(MtpManager mtpManager, ContentResolver resolver, MtpDatabase database) {
+ DocumentLoader(MtpDeviceRecord device, MtpManager mtpManager, ContentResolver resolver,
+ MtpDatabase database) {
+ mDevice = device;
mMtpManager = mtpManager;
mResolver = resolver;
mDatabase = database;
}
- private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
- throws IOException {
- final ArrayList<MtpObjectInfo> objects = new ArrayList<>();
- for (int i = 0; i < handles.length; i++) {
- final MtpObjectInfo info = manager.getObjectInfo(deviceId, handles[i]);
- if (info == null) {
- Log.e(MtpDocumentsProvider.TAG,
- "Failed to obtain object info handle=" + handles[i]);
- continue;
- }
- objects.add(info);
- }
- return objects.toArray(new MtpObjectInfo[objects.size()]);
- }
-
+ /**
+ * Queries the child documents of given parent.
+ * It loads the first NUM_INITIAL_ENTRIES of object info, then launches the background thread
+ * to load the rest.
+ */
synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
throws IOException {
+ Preconditions.checkArgument(parent.mDeviceId == mDevice.deviceId);
LoaderTask task = mTaskList.findTask(parent);
if (task == null) {
if (parent.mDocumentId == null) {
throw new FileNotFoundException("Parent not found.");
}
-
- int parentHandle = parent.mObjectHandle;
- // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
- // getObjectHandles if we would like to obtain children under the root.
- if (parent.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
- parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
- }
// TODO: Handle nit race around here.
// 1. getObjectHandles.
// 2. putNewDocument.
// 3. startAddingChildDocuemnts.
// 4. stopAddingChildDocuments - It removes the new document added at the step 2,
// because it is not updated between start/stopAddingChildDocuments.
- task = new LoaderTask(mDatabase, parent, mMtpManager.getObjectHandles(
- parent.mDeviceId, parent.mStorageId, parentHandle));
+ task = LoaderTask.create(mDatabase, mMtpManager, mDevice.operationsSupported, parent);
task.fillDocuments(loadDocuments(
mMtpManager,
parent.mDeviceId,
@@ -103,15 +92,73 @@ class DocumentLoader {
}
mTaskList.addFirst(task);
- if (task.getState() == LoaderTask.STATE_LOADING && !mHasBackgroundThread) {
- mHasBackgroundThread = true;
- new BackgroundLoaderThread().start();
+ if (task.getState() == LoaderTask.STATE_LOADING) {
+ resume();
}
return task.createCursor(mResolver, columnNames);
}
- synchronized void clearTasks() {
- mTaskList.clear();
+ /**
+ * Resumes a background thread.
+ */
+ synchronized void resume() {
+ if (mBackgroundThread == null) {
+ mBackgroundThread = new BackgroundLoaderThread();
+ mBackgroundThread.start();
+ }
+ }
+
+ /**
+ * Obtains next task to be run in background thread, or release the reference to background
+ * thread.
+ *
+ * Worker thread that receives null task needs to exit.
+ */
+ @WorkerThread
+ synchronized @Nullable LoaderTask getNextTaskOrReleaseBackgroundThread() {
+ Preconditions.checkState(mBackgroundThread != null);
+
+ final LoaderTask task = mTaskList.findRunningTask();
+ if (task != null) {
+ return task;
+ }
+
+ final Identifier identifier = mDatabase.getUnmappedDocumentsParent(mDevice.deviceId);
+ if (identifier != null) {
+ final LoaderTask existingTask = mTaskList.findTask(identifier);
+ if (existingTask != null) {
+ Preconditions.checkState(existingTask.getState() != LoaderTask.STATE_LOADING);
+ mTaskList.remove(existingTask);
+ }
+ try {
+ final LoaderTask newTask = LoaderTask.create(
+ mDatabase, mMtpManager, mDevice.operationsSupported, identifier);
+ mTaskList.addFirst(newTask);
+ return newTask;
+ } catch (IOException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Failed to create a task for mapping", exception);
+ // Continue to release the background thread.
+ }
+ }
+
+ mBackgroundThread = null;
+ return null;
+ }
+
+ /**
+ * Terminates background thread.
+ */
+ @Override
+ public void close() throws InterruptedException {
+ final Thread thread;
+ synchronized (this) {
+ mTaskList.clear();
+ thread = mBackgroundThread;
+ }
+ if (thread != null) {
+ thread.interrupt();
+ thread.join();
+ }
}
synchronized void clearCompletedTasks() {
@@ -122,27 +169,45 @@ class DocumentLoader {
mTaskList.clearTask(parentIdentifier);
}
+ /**
+ * Helper method to loads multiple object info.
+ */
+ private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
+ throws IOException {
+ final ArrayList<MtpObjectInfo> objects = new ArrayList<>();
+ for (int i = 0; i < handles.length; i++) {
+ final MtpObjectInfo info = manager.getObjectInfo(deviceId, handles[i]);
+ if (info == null) {
+ Log.e(MtpDocumentsProvider.TAG,
+ "Failed to obtain object info handle=" + handles[i]);
+ continue;
+ }
+ objects.add(info);
+ }
+ return objects.toArray(new MtpObjectInfo[objects.size()]);
+ }
+
+ /**
+ * Background thread to fetch object info.
+ */
private class BackgroundLoaderThread extends Thread {
+ /**
+ * Finds task that needs to be processed, then loads NUM_LOADING_ENTRIES of object info and
+ * store them to the database. If it does not find a task, exits the thread.
+ */
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- while (true) {
- LoaderTask task;
- int deviceId;
- int[] handles;
- synchronized (DocumentLoader.this) {
- task = mTaskList.findRunningTask();
- if (task == null) {
- mHasBackgroundThread = false;
- return;
- }
- deviceId = task.mIdentifier.mDeviceId;
- handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
+ while (!Thread.interrupted()) {
+ final LoaderTask task = getNextTaskOrReleaseBackgroundThread();
+ if (task == null) {
+ return;
}
-
try {
- final MtpObjectInfo[] objectInfos =
- loadDocuments(mMtpManager, deviceId, handles);
+ final MtpObjectInfo[] objectInfos = loadDocuments(
+ mMtpManager,
+ task.mIdentifier.mDeviceId,
+ task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES));
task.fillDocuments(objectInfos);
final boolean shouldNotify =
task.mLastNotified.getTime() <
@@ -158,6 +223,9 @@ class DocumentLoader {
}
}
+ /**
+ * Task list that has helper methods to search/clear tasks.
+ */
private static class TaskList extends LinkedList<LoaderTask> {
LoaderTask findTask(Identifier parent) {
for (int i = 0; i < size(); i++) {
@@ -198,26 +266,38 @@ class DocumentLoader {
}
}
+ /**
+ * Loader task.
+ * Each task is responsible for fetching child documents for the given parent document.
+ */
private static class LoaderTask {
static final int STATE_LOADING = 0;
static final int STATE_COMPLETED = 1;
static final int STATE_ERROR = 2;
final MtpDatabase mDatabase;
+ int[] mOperationsSupported;
final Identifier mIdentifier;
final int[] mObjectHandles;
Date mLastNotified;
int mNumLoaded;
Exception mError;
- LoaderTask(MtpDatabase database, Identifier identifier, int[] objectHandles) {
+ LoaderTask(MtpDatabase database, int[] operationsSupported, Identifier identifier,
+ int[] objectHandles) {
mDatabase = database;
+ mOperationsSupported = operationsSupported;
mIdentifier = identifier;
mObjectHandles = objectHandles;
mNumLoaded = 0;
mLastNotified = new Date();
}
+ /**
+ * Returns a cursor that traverses the child document of the parent document handled by the
+ * task.
+ * The returned task may have a EXTRA_LOADING flag.
+ */
Cursor createCursor(ContentResolver resolver, String[] columnNames) throws IOException {
final Bundle extras = new Bundle();
switch (getState()) {
@@ -236,6 +316,9 @@ class DocumentLoader {
return cursor;
}
+ /**
+ * Returns a state of the task.
+ */
int getState() {
if (mError != null) {
return STATE_ERROR;
@@ -246,6 +329,9 @@ class DocumentLoader {
}
}
+ /**
+ * Obtains object handles that have not been loaded yet.
+ */
int[] getUnloadedObjectHandles(int count) {
return Arrays.copyOfRange(
mObjectHandles,
@@ -253,43 +339,77 @@ class DocumentLoader {
Math.min(mNumLoaded + count, mObjectHandles.length));
}
+ /**
+ * Notifies a change of child list of the document.
+ */
void notify(ContentResolver resolver) {
resolver.notifyChange(createUri(), null, false);
mLastNotified = new Date();
}
+ /**
+ * Stores object information into database.
+ */
void fillDocuments(MtpObjectInfo[] objectInfoList) {
if (objectInfoList.length == 0 || getState() != STATE_LOADING) {
return;
}
- if (mNumLoaded == 0) {
- mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
- }
- try {
+ try{
+ if (mNumLoaded == 0) {
+ mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
+ }
mDatabase.getMapper().putChildDocuments(
- mIdentifier.mDeviceId, mIdentifier.mDocumentId, objectInfoList);
+ mIdentifier.mDeviceId, mIdentifier.mDocumentId, mOperationsSupported,
+ objectInfoList);
mNumLoaded += objectInfoList.length;
- } catch (SQLiteException exp) {
- mError = exp;
- mNumLoaded = 0;
- }
- if (getState() != STATE_LOADING) {
- mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ if (getState() != STATE_LOADING) {
+ mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ }
+ } catch (FileNotFoundException exception) {
+ setErrorInternal(exception);
}
}
- void setError(Exception message) {
+ /**
+ * Marks the loading task as error.
+ */
+ void setError(Exception error) {
final int lastState = getState();
- mError = message;
- mNumLoaded = 0;
+ setErrorInternal(error);
if (lastState == STATE_LOADING) {
- mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ try {
+ mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
+ } catch (FileNotFoundException exception) {
+ setErrorInternal(exception);
+ }
}
}
+ private void setErrorInternal(Exception error) {
+ Log.e(MtpDocumentsProvider.TAG, "Error in DocumentLoader thread", error);
+ mError = error;
+ mNumLoaded = 0;
+ }
+
private Uri createUri() {
return DocumentsContract.buildChildDocumentsUri(
MtpDocumentsProvider.AUTHORITY, mIdentifier.mDocumentId);
}
+
+ /**
+ * Creates a LoaderTask that loads children of the given document.
+ */
+ static LoaderTask create(MtpDatabase database, MtpManager manager,
+ int[] operationsSupported, Identifier parent)
+ throws IOException {
+ int parentHandle = parent.mObjectHandle;
+ // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
+ // getObjectHandles if we would like to obtain children under the root.
+ if (parent.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
+ parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
+ }
+ return new LoaderTask(database, operationsSupported, parent, manager.getObjectHandles(
+ parent.mDeviceId, parent.mStorageId, parentHandle));
+ }
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index 3faa8f4394f7..8058183f161c 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -16,8 +16,6 @@
package com.android.mtp;
-import static com.android.mtp.MtpDatabaseConstants.*;
-
import android.annotation.Nullable;
import android.content.ContentValues;
import android.database.Cursor;
@@ -26,13 +24,15 @@ import android.database.sqlite.SQLiteDatabase;
import android.mtp.MtpObjectInfo;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.util.ArraySet;
+import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import java.util.HashMap;
-import java.util.Map;
+import java.io.FileNotFoundException;
+import java.util.Set;
+import static com.android.mtp.MtpDatabaseConstants.*;
import static com.android.mtp.MtpDatabase.strings;
/**
@@ -44,11 +44,9 @@ class Mapper {
private final MtpDatabase mDatabase;
/**
- * Mapping mode for a parent. The key is document ID of parent, or null for root documents.
- * Methods operate the state needs to be synchronized.
- * TODO: Replace this with unboxing int map.
+ * IDs which currently Mapper operates mapping for.
*/
- private final Map<String, Integer> mMappingMode = new HashMap<>();
+ private final Set<String> mInMappingIds = new ArraySet<>();
Mapper(MtpDatabase database) {
mDatabase = database;
@@ -56,11 +54,12 @@ class Mapper {
/**
* Puts device information to database.
+ *
* @return If device is added to the database.
+ * @throws FileNotFoundException
*/
- synchronized boolean putDeviceDocument(MtpDeviceRecord device) {
+ synchronized boolean putDeviceDocument(MtpDeviceRecord device) throws FileNotFoundException {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
- Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null));
database.beginTransaction();
try {
final ContentValues[] valuesList = new ContentValues[1];
@@ -69,12 +68,12 @@ class Mapper {
extraValuesList[0] = new ContentValues();
MtpDatabase.getDeviceDocumentValues(valuesList[0], extraValuesList[0], device);
final boolean changed = putDocuments(
+ null,
valuesList,
extraValuesList,
COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
EMPTY_ARGS,
- /* heuristic */ false,
- COLUMN_DEVICE_ID);
+ strings(COLUMN_DEVICE_ID, COLUMN_MAPPING_KEY));
database.setTransactionSuccessful();
return changed;
} finally {
@@ -84,44 +83,37 @@ class Mapper {
/**
* Puts root information to database.
+ *
* @param parentDocumentId Document ID of device document.
* @param roots List of root information.
* @return If roots are added or removed from the database.
+ * @throws FileNotFoundException
*/
- synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots) {
+ synchronized boolean putStorageDocuments(
+ String parentDocumentId, int[] operationsSupported, MtpRoot[] roots)
+ throws FileNotFoundException {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- final boolean heuristic;
- final String mapColumn;
- Preconditions.checkState(mMappingMode.containsKey(parentDocumentId));
- switch (mMappingMode.get(parentDocumentId)) {
- case MAP_BY_MTP_IDENTIFIER:
- heuristic = false;
- mapColumn = COLUMN_STORAGE_ID;
- break;
- case MAP_BY_NAME:
- heuristic = true;
- mapColumn = Document.COLUMN_DISPLAY_NAME;
- break;
- default:
- throw new Error("Unexpected map mode.");
- }
final ContentValues[] valuesList = new ContentValues[roots.length];
final ContentValues[] extraValuesList = new ContentValues[roots.length];
for (int i = 0; i < roots.length; i++) {
valuesList[i] = new ContentValues();
extraValuesList[i] = new ContentValues();
MtpDatabase.getStorageDocumentValues(
- valuesList[i], extraValuesList[i], parentDocumentId, roots[i]);
+ valuesList[i],
+ extraValuesList[i],
+ parentDocumentId,
+ operationsSupported,
+ roots[i]);
}
final boolean changed = putDocuments(
+ parentDocumentId,
valuesList,
extraValuesList,
- COLUMN_PARENT_DOCUMENT_ID + "=?",
+ COLUMN_PARENT_DOCUMENT_ID + " = ?",
strings(parentDocumentId),
- heuristic,
- mapColumn);
+ strings(COLUMN_STORAGE_ID, Document.COLUMN_DISPLAY_NAME));
database.setTransactionSuccessful();
return changed;
@@ -132,55 +124,44 @@ class Mapper {
/**
* Puts document information to database.
+ *
* @param deviceId Device ID
* @param parentId Parent document ID.
* @param documents List of document information.
+ * @throws FileNotFoundException
*/
- synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents) {
- final boolean heuristic;
- final String mapColumn;
- Preconditions.checkState(mMappingMode.containsKey(parentId));
- switch (mMappingMode.get(parentId)) {
- case MAP_BY_MTP_IDENTIFIER:
- heuristic = false;
- mapColumn = COLUMN_OBJECT_HANDLE;
- break;
- case MAP_BY_NAME:
- heuristic = true;
- mapColumn = Document.COLUMN_DISPLAY_NAME;
- break;
- default:
- throw new Error("Unexpected map mode.");
- }
+ synchronized void putChildDocuments(
+ int deviceId, String parentId, int[] operationsSupported, MtpObjectInfo[] documents)
+ throws FileNotFoundException {
final ContentValues[] valuesList = new ContentValues[documents.length];
for (int i = 0; i < documents.length; i++) {
valuesList[i] = new ContentValues();
MtpDatabase.getObjectDocumentValues(
- valuesList[i], deviceId, parentId, documents[i]);
+ valuesList[i], deviceId, parentId, operationsSupported, documents[i]);
}
putDocuments(
+ parentId,
valuesList,
null,
- COLUMN_PARENT_DOCUMENT_ID + "=?",
+ COLUMN_PARENT_DOCUMENT_ID + " = ?",
strings(parentId),
- heuristic,
- mapColumn);
+ strings(COLUMN_OBJECT_HANDLE, Document.COLUMN_DISPLAY_NAME));
}
- @VisibleForTesting
void clearMapping() {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- mDatabase.deleteDocumentsAndRootsRecursively(
- COLUMN_ROW_STATE + " = ?", strings(ROW_STATE_PENDING));
- final ContentValues values = new ContentValues();
- values.putNull(COLUMN_OBJECT_HANDLE);
- values.putNull(COLUMN_STORAGE_ID);
- values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
- database.update(TABLE_DOCUMENTS, values, null, null);
+ mInMappingIds.clear();
+ // Disconnect all device rows.
+ try {
+ startAddingDocuments(null);
+ stopAddingDocuments(null);
+ } catch (FileNotFoundException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Unexpected FileNotFoundException.", exception);
+ throw new RuntimeException(exception);
+ }
database.setTransactionSuccessful();
- mMappingMode.clear();
} finally {
database.endTransaction();
}
@@ -188,14 +169,13 @@ class Mapper {
/**
* Starts adding new documents.
- * The methods decides mapping mode depends on if all documents under the given parent have MTP
- * identifier or not. If all the documents have MTP identifier, it uses the identifier to find
- * a corresponding existing row. Otherwise it does heuristic.
+ * It changes the direct child documents of the given document from VALID to INVALIDATED.
+ * Note that it keeps DISCONNECTED documents as they are.
*
* @param parentDocumentId Parent document ID or NULL for root documents.
+ * @throws FileNotFoundException
*/
- void startAddingDocuments(@Nullable String parentDocumentId) {
- Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId));
+ void startAddingDocuments(@Nullable String parentDocumentId) throws FileNotFoundException {
final String selection;
final String[] args;
if (parentDocumentId != null) {
@@ -209,25 +189,20 @@ class Mapper {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- // Delete all pending rows.
- mDatabase.deleteDocumentsAndRootsRecursively(
- selection + " AND " + COLUMN_ROW_STATE + "=?",
- DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_PENDING)));
+ getParentOrHaltMapping(parentDocumentId);
+ Preconditions.checkState(!mInMappingIds.contains(parentDocumentId));
- // Set all documents as invalidated.
+ // Set all valid documents as invalidated.
final ContentValues values = new ContentValues();
values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
- database.update(TABLE_DOCUMENTS, values, selection, args);
-
- // If we have rows that does not have MTP identifier, do heuristic mapping by name.
- final boolean useNameForResolving = DatabaseUtils.queryNumEntries(
- database,
+ database.update(
TABLE_DOCUMENTS,
- selection + " AND " + COLUMN_STORAGE_ID + " IS NULL",
- args) > 0;
+ values,
+ selection + " AND " + COLUMN_ROW_STATE + " = ?",
+ DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_VALID)));
+
database.setTransactionSuccessful();
- mMappingMode.put(
- parentDocumentId, useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER);
+ mInMappingIds.add(parentDocumentId);
} finally {
database.endTransaction();
}
@@ -241,24 +216,29 @@ class Mapper {
* {@link #stopAddingDocuments(String)} turns the pending rows into 'valid'
* rows. If the methods adds rows to database, it updates valueList with correct document ID.
*
+ * @param parentId Parent document ID.
* @param valuesList Values for documents to be stored in the database.
* @param rootExtraValuesList Values for root extra to be stored in the database.
* @param selection SQL where closure to select rows that shares the same parent.
* @param args Argument for selection SQL.
- * @param heuristic Whether the mapping mode is heuristic.
- * @return Whether the method adds new rows.
+ * @return Whether the database content is changed.
+ * @throws FileNotFoundException When parentId is not registered in the database.
*/
private boolean putDocuments(
+ String parentId,
ContentValues[] valuesList,
@Nullable ContentValues[] rootExtraValuesList,
String selection,
String[] args,
- boolean heuristic,
- String mappingKey) {
+ String[] mappingKeys) throws FileNotFoundException {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
- boolean added = false;
+ boolean changed = false;
database.beginTransaction();
try {
+ getParentOrHaltMapping(parentId);
+ Preconditions.checkState(mInMappingIds.contains(parentId));
+ final ContentValues oldRowSnapshot = new ContentValues();
+ final ContentValues newRowSnapshot = new ContentValues();
for (int i = 0; i < valuesList.length; i++) {
final ContentValues values = valuesList[i];
final ContentValues rootExtraValues;
@@ -267,35 +247,23 @@ class Mapper {
} else {
rootExtraValues = null;
}
- final Cursor candidateCursor = database.query(
- TABLE_DOCUMENTS,
- strings(Document.COLUMN_DOCUMENT_ID),
- selection + " AND " +
- COLUMN_ROW_STATE + "=? AND " +
- mappingKey + "=?",
- DatabaseUtils.appendSelectionArgs(
- args,
- strings(ROW_STATE_INVALIDATED, values.getAsString(mappingKey))),
- null,
- null,
- null,
- "1");
- try {
+ try (final Cursor candidateCursor =
+ queryCandidate(selection, args, mappingKeys, values)) {
final long rowId;
- if (candidateCursor.getCount() == 0) {
+ if (candidateCursor == null) {
rowId = database.insert(TABLE_DOCUMENTS, null, values);
- added = true;
- } else if (!heuristic) {
+ changed = true;
+ } else {
candidateCursor.moveToNext();
rowId = candidateCursor.getLong(0);
+ if (!changed) {
+ mDatabase.writeRowSnapshot(String.valueOf(rowId), oldRowSnapshot);
+ }
database.update(
TABLE_DOCUMENTS,
values,
SELECTION_DOCUMENT_ID,
strings(rowId));
- } else {
- values.put(COLUMN_ROW_STATE, ROW_STATE_PENDING);
- rowId = database.insertOrThrow(TABLE_DOCUMENTS, null, values);
}
// Document ID is a primary integer key of the table. So the returned row
// IDs should be same with the document ID.
@@ -304,135 +272,78 @@ class Mapper {
rootExtraValues.put(Root.COLUMN_ROOT_ID, rowId);
database.replace(TABLE_ROOT_EXTRA, null, rootExtraValues);
}
- } finally {
- candidateCursor.close();
+
+ if (!changed) {
+ mDatabase.writeRowSnapshot(String.valueOf(rowId), newRowSnapshot);
+ // Put row state as string because SQLite returns snapshot values as string.
+ oldRowSnapshot.put(COLUMN_ROW_STATE, String.valueOf(ROW_STATE_VALID));
+ if (!oldRowSnapshot.equals(newRowSnapshot)) {
+ changed = true;
+ }
+ }
}
}
database.setTransactionSuccessful();
- return added;
+ return changed;
} finally {
database.endTransaction();
}
}
/**
- * Maps 'pending' document and 'invalidated' document that shares the same column of groupKey.
- * If the database does not find corresponding 'invalidated' document, it just removes
- * 'invalidated' document from the database.
+ * Stops adding documents.
+ * It handles 'invalidated' and 'disconnected' documents which we don't put corresponding
+ * documents so far.
+ * If the type adding document is 'device' or 'storage', the document may appear again
+ * afterward. The method marks such documents as 'disconnected'. If the type of adding document
+ * is 'object', it seems the documents are really removed from the remote MTP device. So the
+ * method deletes the metadata from the database.
+ *
* @param parentId Parent document ID or null for root documents.
- * @return Whether the methods adds or removed visible rows.
+ * @return Whether the methods changes file metadata in database.
+ * @throws FileNotFoundException
*/
- boolean stopAddingDocuments(@Nullable String parentId) {
- Preconditions.checkState(mMappingMode.containsKey(parentId));
+ boolean stopAddingDocuments(@Nullable String parentId) throws FileNotFoundException {
final String selection;
final String[] args;
if (parentId != null) {
- selection = COLUMN_PARENT_DOCUMENT_ID + "=?";
+ selection = COLUMN_PARENT_DOCUMENT_ID + " = ?";
args = strings(parentId);
} else {
selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
args = EMPTY_ARGS;
}
- final String groupKey;
- switch (mMappingMode.get(parentId)) {
- case MAP_BY_MTP_IDENTIFIER:
- groupKey = parentId != null ? COLUMN_OBJECT_HANDLE : COLUMN_STORAGE_ID;
- break;
- case MAP_BY_NAME:
- groupKey = Document.COLUMN_DISPLAY_NAME;
- break;
- default:
- throw new Error("Unexpected mapping state.");
- }
- mMappingMode.remove(parentId);
+
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
- // Get 1-to-1 mapping of invalidated document and pending document.
- final String invalidatedIdQuery = createStateFilter(
- ROW_STATE_INVALIDATED, Document.COLUMN_DOCUMENT_ID);
- final String pendingIdQuery = createStateFilter(
- ROW_STATE_PENDING, Document.COLUMN_DOCUMENT_ID);
- // SQL should be like:
- // SELECT group_concat(CASE WHEN raw_state = 1 THEN document_id ELSE NULL END),
- // group_concat(CASE WHEN raw_state = 2 THEN document_id ELSE NULL END)
- // WHERE device_id = ? AND parent_document_id IS NULL
- // GROUP BY display_name
- // HAVING count(CASE WHEN raw_state = 1 THEN document_id ELSE NULL END) = 1 AND
- // count(CASE WHEN raw_state = 2 THEN document_id ELSE NULL END) = 1
- final Cursor mergingCursor = database.query(
- TABLE_DOCUMENTS,
- new String[] {
- "group_concat(" + invalidatedIdQuery + ")",
- "group_concat(" + pendingIdQuery + ")"
- },
- selection,
- args,
- groupKey,
- "count(" + invalidatedIdQuery + ") = 1 AND count(" + pendingIdQuery + ") = 1",
- null);
-
- final ContentValues values = new ContentValues();
- while (mergingCursor.moveToNext()) {
- final String invalidatedId = mergingCursor.getString(0);
- final String pendingId = mergingCursor.getString(1);
-
- // Obtain the new values including the latest object handle from mapping row.
- getFirstRow(
- TABLE_DOCUMENTS,
- SELECTION_DOCUMENT_ID,
- new String[] { pendingId },
- values);
- values.remove(Document.COLUMN_DOCUMENT_ID);
- values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
- database.update(
- TABLE_DOCUMENTS,
- values,
- SELECTION_DOCUMENT_ID,
- new String[] { invalidatedId });
-
- getFirstRow(
- TABLE_ROOT_EXTRA,
- SELECTION_ROOT_ID,
- new String[] { pendingId },
- values);
- if (values.size() > 0) {
- values.remove(Root.COLUMN_ROOT_ID);
- database.update(
- TABLE_ROOT_EXTRA,
- values,
- SELECTION_ROOT_ID,
- new String[] { invalidatedId });
- }
-
- // Delete 'pending' row.
- mDatabase.deleteDocumentsAndRootsRecursively(
- SELECTION_DOCUMENT_ID, new String[] { pendingId });
- }
- mergingCursor.close();
+ final Identifier parentIdentifier = getParentOrHaltMapping(parentId);
+ Preconditions.checkState(mInMappingIds.contains(parentId));
+ mInMappingIds.remove(parentId);
boolean changed = false;
-
- // Delete all invalidated rows that cannot be mapped.
- if (mDatabase.deleteDocumentsAndRootsRecursively(
- COLUMN_ROW_STATE + " = ? AND " + selection,
- DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
- changed = true;
+ // Delete/disconnect all invalidated/disconnected rows that cannot be mapped.
+ // If parentIdentifier is null, added documents are devices.
+ // if parentIdentifier is DOCUMENT_TYPE_DEVICE, added documents are storages.
+ final boolean keepUnmatchedDocument =
+ parentIdentifier == null ||
+ parentIdentifier.mDocumentType == DOCUMENT_TYPE_DEVICE;
+ if (keepUnmatchedDocument) {
+ if (mDatabase.disconnectDocumentsRecursively(
+ COLUMN_ROW_STATE + " = ? AND " + selection,
+ DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
+ changed = true;
+ }
+ } else {
+ if (mDatabase.deleteDocumentsAndRootsRecursively(
+ COLUMN_ROW_STATE + " IN (?, ?) AND " + selection,
+ DatabaseUtils.appendSelectionArgs(
+ strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED), args))) {
+ changed = true;
+ }
}
- // The database cannot find old document ID for the pending rows.
- // Turn the all pending rows into valid state, which means the rows become to be
- // valid with new document ID.
- values.clear();
- values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
- if (database.update(
- TABLE_DOCUMENTS,
- values,
- COLUMN_ROW_STATE + " = ? AND " + selection,
- DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_PENDING), args)) != 0) {
- changed = true;
- }
database.setTransactionSuccessful();
return changed;
} finally {
@@ -441,38 +352,75 @@ class Mapper {
}
/**
- * Obtains values of the first row for the query.
- * @param values ContentValues that the values are stored to.
- * @param table Target table.
- * @param selection Query to select rows.
- * @param args Argument for query.
+ * Queries candidate for each mappingKey, and returns the first cursor that includes a
+ * candidate.
+ *
+ * @param selection Pre-selection for candidate.
+ * @param args Arguments for selection.
+ * @param mappingKeys List of mapping key columns.
+ * @param values Values of document that Mapper tries to map.
+ * @return Cursor for mapping candidate or null when Mapper does not find any candidate.
*/
- private void getFirstRow(String table, String selection, String[] args, ContentValues values) {
- final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
- values.clear();
- final Cursor cursor = database.query(table, null, selection, args, null, null, null, "1");
- try {
- if (cursor.getCount() == 0) {
- return;
+ private @Nullable Cursor queryCandidate(
+ String selection, String[] args, String[] mappingKeys, ContentValues values) {
+ for (final String mappingKey : mappingKeys) {
+ final Cursor candidateCursor = queryCandidate(selection, args, mappingKey, values);
+ if (candidateCursor.getCount() == 0) {
+ candidateCursor.close();
+ continue;
}
- cursor.moveToNext();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- } finally {
- cursor.close();
+ return candidateCursor;
}
+ return null;
+ }
+
+ /**
+ * Looks for mapping candidate with given mappingKey.
+ *
+ * @param selection Pre-selection for candidate.
+ * @param args Arguments for selection.
+ * @param mappingKey Column name of mapping key.
+ * @param values Values of document that Mapper tries to map.
+ * @return Cursor for mapping candidate.
+ */
+ private Cursor queryCandidate(
+ String selection, String[] args, String mappingKey, ContentValues values) {
+ final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
+ return database.query(
+ TABLE_DOCUMENTS,
+ strings(Document.COLUMN_DOCUMENT_ID),
+ selection + " AND " +
+ COLUMN_ROW_STATE + " IN (?, ?) AND " +
+ mappingKey + " = ?",
+ DatabaseUtils.appendSelectionArgs(
+ args,
+ strings(ROW_STATE_INVALIDATED,
+ ROW_STATE_DISCONNECTED,
+ values.getAsString(mappingKey))),
+ null,
+ null,
+ null,
+ "1");
}
/**
- * Gets SQL expression that represents the given value or NULL depends on the row state.
- * You must pass static constants to this methods otherwise you may be suffered from SQL
- * injections.
- * @param state Expected row state.
- * @param a SQL value.
- * @return Expression that represents a if the row state is expected one, and represents NULL
- * otherwise.
+ * Returns the parent identifier from parent document ID if the parent ID is found in the
+ * database. Otherwise it halts mapping and throws FileNotFoundException.
+ *
+ * @param parentId Parent document ID
+ * @return Parent identifier
+ * @throws FileNotFoundException
*/
- private static String createStateFilter(int state, String a) {
- return "CASE WHEN " + COLUMN_ROW_STATE + " = " + Integer.toString(state) +
- " THEN " + a + " ELSE NULL END";
+ private @Nullable Identifier getParentOrHaltMapping(
+ @Nullable String parentId) throws FileNotFoundException {
+ if (parentId == null) {
+ return null;
+ }
+ try {
+ return mDatabase.createIdentifier(parentId);
+ } catch (FileNotFoundException error) {
+ mInMappingIds.remove(parentId);
+ throw error;
+ }
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 8a3ebefa127f..203d6dc64d41 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -37,8 +37,10 @@ import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.Objects;
/**
@@ -219,7 +221,7 @@ class MtpDatabase {
return mDatabase.query(
TABLE_DOCUMENTS,
columnNames,
- COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + "=?",
+ COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?",
strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
null,
null,
@@ -244,15 +246,16 @@ class MtpDatabase {
}
/**
- * Returns identifier of single storage if given document points device and it has only one
- * storage. Otherwise null.
+ * Returns document IDs of storages under the given device document.
*
- * @param documentId Document ID that may point a device.
- * @return Identifier for single storage or null.
+ * @param documentId Document ID that points a device.
+ * @return Storage document IDs.
* @throws FileNotFoundException The given document ID is not registered in database.
*/
- @Nullable Identifier getSingleStorageIdentifier(String documentId)
+ String[] getStorageDocumentIds(String documentId)
throws FileNotFoundException {
+ Preconditions.checkArgument(createIdentifier(documentId).mDocumentType ==
+ DOCUMENT_TYPE_DEVICE);
// Check if the parent document is device that has single storage.
try (final Cursor cursor = mDatabase.query(
TABLE_DOCUMENTS,
@@ -267,12 +270,11 @@ class MtpDatabase {
null,
null,
null)) {
- if (cursor.getCount() == 1) {
- cursor.moveToNext();
- return createIdentifier(cursor.getString(0));
- } else {
- return null;
+ final String[] ids = new String[cursor.getCount()];
+ for (int i = 0; cursor.moveToNext(); i++) {
+ ids[i] = cursor.getString(0);
}
+ return ids;
}
}
@@ -294,15 +296,6 @@ class MtpDatabase {
"1");
}
- /**
- * Remove all rows belong to a device.
- * @param deviceId Device ID.
- */
- void removeDeviceRows(int deviceId) {
- // Call non-recursive version because it anyway deletes all rows in the devices.
- deleteDocumentsAndRoots(COLUMN_DEVICE_ID + "=?", strings(deviceId));
- }
-
@Nullable String getDocumentIdForDevice(int deviceId) {
final Cursor cursor = mDatabase.query(
TABLE_DOCUMENTS,
@@ -344,13 +337,33 @@ class MtpDatabase {
if (cursor.moveToNext()) {
return createIdentifier(cursor.getString(0));
} else {
- throw new FileNotFoundException("Cannot find a row having ID=" + documentId);
+ throw new FileNotFoundException("Cannot find a row having ID = " + documentId);
}
} finally {
cursor.close();
}
}
+ String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(Document.COLUMN_DOCUMENT_ID),
+ COLUMN_DEVICE_ID + " = ? AND " + COLUMN_DOCUMENT_TYPE + " = ? AND " +
+ COLUMN_ROW_STATE + " != ?",
+ strings(deviceId, DOCUMENT_TYPE_DEVICE, ROW_STATE_DISCONNECTED),
+ null,
+ null,
+ null,
+ "1")) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToNext();
+ return cursor.getString(0);
+ } else {
+ throw new FileNotFoundException("The device ID not found: " + deviceId);
+ }
+ }
+ }
+
/**
* Adds new document under the parent.
* The method does not affect invalidated and pending documents because we know the document is
@@ -359,9 +372,10 @@ class MtpDatabase {
* @param info
* @return Document ID of added document.
*/
- String putNewDocument(int deviceId, String parentDocumentId, MtpObjectInfo info) {
+ String putNewDocument(
+ int deviceId, String parentDocumentId, int[] operationsSupported, MtpObjectInfo info) {
final ContentValues values = new ContentValues();
- getObjectDocumentValues(values, deviceId, parentDocumentId, info);
+ getObjectDocumentValues(values, deviceId, parentDocumentId, operationsSupported, info);
mDatabase.beginTransaction();
try {
final long id = mDatabase.insert(TABLE_DOCUMENTS, null, values);
@@ -394,15 +408,15 @@ class MtpDatabase {
COLUMN_STORAGE_ID,
COLUMN_OBJECT_HANDLE,
COLUMN_DOCUMENT_TYPE),
- SELECTION_DOCUMENT_ID,
- strings(documentId),
+ SELECTION_DOCUMENT_ID + " AND " + COLUMN_ROW_STATE + " IN (?, ?)",
+ strings(documentId, ROW_STATE_VALID, ROW_STATE_INVALIDATED),
null,
null,
null,
"1");
try {
if (cursor.getCount() == 0) {
- throw new FileNotFoundException("ID is not found.");
+ throw new FileNotFoundException("ID \"" + documentId + "\" is not found.");
} else {
cursor.moveToNext();
return new Identifier(
@@ -438,7 +452,7 @@ class MtpDatabase {
try {
while (cursor.moveToNext()) {
if (deleteDocumentsAndRootsRecursively(
- COLUMN_PARENT_DOCUMENT_ID + "=?",
+ COLUMN_PARENT_DOCUMENT_ID + " = ?",
strings(cursor.getString(0)))) {
changed = true;
}
@@ -456,7 +470,43 @@ class MtpDatabase {
}
}
- private boolean deleteDocumentsAndRoots(String selection, String[] args) {
+ /**
+ * Marks the documents and their child as disconnected documents.
+ * @param selection
+ * @param args
+ * @return True if at least one row is updated.
+ */
+ boolean disconnectDocumentsRecursively(String selection, String[] args) {
+ mDatabase.beginTransaction();
+ try {
+ boolean changed = false;
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(Document.COLUMN_DOCUMENT_ID),
+ selection,
+ args,
+ null,
+ null,
+ null)) {
+ while (cursor.moveToNext()) {
+ if (disconnectDocumentsRecursively(
+ COLUMN_PARENT_DOCUMENT_ID + " = ?",
+ strings(cursor.getString(0)))) {
+ changed = true;
+ }
+ }
+ }
+ if (disconnectDocuments(selection, args)) {
+ changed = true;
+ }
+ mDatabase.setTransactionSuccessful();
+ return changed;
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ boolean deleteDocumentsAndRoots(String selection, String[] args) {
mDatabase.beginTransaction();
try {
int deleted = 0;
@@ -481,6 +531,118 @@ class MtpDatabase {
}
}
+ boolean disconnectDocuments(String selection, String[] args) {
+ mDatabase.beginTransaction();
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(COLUMN_ROW_STATE, ROW_STATE_DISCONNECTED);
+ values.putNull(COLUMN_DEVICE_ID);
+ values.putNull(COLUMN_STORAGE_ID);
+ values.putNull(COLUMN_OBJECT_HANDLE);
+ final boolean updated = mDatabase.update(TABLE_DOCUMENTS, values, selection, args) != 0;
+ mDatabase.setTransactionSuccessful();
+ return updated;
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ int getRowState(String documentId) throws FileNotFoundException {
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(COLUMN_ROW_STATE),
+ SELECTION_DOCUMENT_ID,
+ strings(documentId),
+ null,
+ null,
+ null)) {
+ if (cursor.getCount() == 0) {
+ throw new FileNotFoundException();
+ }
+ cursor.moveToNext();
+ return cursor.getInt(0);
+ }
+ }
+
+ void writeRowSnapshot(String documentId, ContentValues values) throws FileNotFoundException {
+ try (final Cursor cursor = mDatabase.query(
+ JOIN_ROOTS,
+ strings("*"),
+ SELECTION_DOCUMENT_ID,
+ strings(documentId),
+ null,
+ null,
+ null,
+ "1")) {
+ if (cursor.getCount() == 0) {
+ throw new FileNotFoundException();
+ }
+ cursor.moveToNext();
+ values.clear();
+ DatabaseUtils.cursorRowToContentValues(cursor, values);
+ }
+ }
+
+ void updateObject(String documentId, int deviceId, String parentId, int[] operationsSupported,
+ MtpObjectInfo info) {
+ final ContentValues values = new ContentValues();
+ getObjectDocumentValues(values, deviceId, parentId, operationsSupported, info);
+
+ mDatabase.beginTransaction();
+ try {
+ mDatabase.update(
+ TABLE_DOCUMENTS,
+ values,
+ Document.COLUMN_DOCUMENT_ID + " = ?",
+ strings(documentId));
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ /**
+ * Obtains a document that has already mapped but has unmapped children.
+ * @param deviceId Device to find documents.
+ * @return Identifier of found document or null.
+ */
+ public @Nullable Identifier getUnmappedDocumentsParent(int deviceId) {
+ final String fromClosure =
+ TABLE_DOCUMENTS + " AS child INNER JOIN " +
+ TABLE_DOCUMENTS + " AS parent ON " +
+ "child." + COLUMN_PARENT_DOCUMENT_ID + " = " +
+ "parent." + Document.COLUMN_DOCUMENT_ID;
+ final String whereClosure =
+ "parent." + COLUMN_DEVICE_ID + " = ? AND " +
+ "parent." + COLUMN_ROW_STATE + " IN (?, ?) AND " +
+ "child." + COLUMN_ROW_STATE + " = ?";
+ try (final Cursor cursor = mDatabase.query(
+ fromClosure,
+ strings("parent." + COLUMN_DEVICE_ID,
+ "parent." + COLUMN_STORAGE_ID,
+ "parent." + COLUMN_OBJECT_HANDLE,
+ "parent." + Document.COLUMN_DOCUMENT_ID,
+ "parent." + COLUMN_DOCUMENT_TYPE),
+ whereClosure,
+ strings(deviceId, ROW_STATE_VALID, ROW_STATE_INVALIDATED,
+ ROW_STATE_DISCONNECTED),
+ null,
+ null,
+ null,
+ "1")) {
+ if (cursor.getCount() == 0) {
+ return null;
+ }
+ cursor.moveToNext();
+ return new Identifier(
+ cursor.getInt(0),
+ cursor.getInt(1),
+ cursor.getInt(2),
+ cursor.getString(3),
+ cursor.getInt(4));
+ }
+ }
+
private static class OpenHelper extends SQLiteOpenHelper {
public OpenHelper(Context context, int flags) {
super(context,
@@ -497,7 +659,9 @@ class MtpDatabase {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- throw new UnsupportedOperationException();
+ db.execSQL("DROP TABLE " + TABLE_DOCUMENTS);
+ db.execSQL("DROP TABLE " + TABLE_ROOT_EXTRA);
+ onCreate(db);
}
}
@@ -517,6 +681,7 @@ class MtpDatabase {
values.putNull(COLUMN_PARENT_DOCUMENT_ID);
values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE);
+ values.put(COLUMN_MAPPING_KEY, device.deviceKey);
values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
values.put(Document.COLUMN_DISPLAY_NAME, device.name);
values.putNull(Document.COLUMN_SUMMARY);
@@ -526,9 +691,7 @@ class MtpDatabase {
values.putNull(Document.COLUMN_SIZE);
extraValues.clear();
- extraValues.put(
- Root.COLUMN_FLAGS,
- Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+ extraValues.put(Root.COLUMN_FLAGS, getRootFlags(device.operationsSupported));
extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES);
extraValues.putNull(Root.COLUMN_CAPACITY_BYTES);
extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -537,12 +700,16 @@ class MtpDatabase {
/**
* Gets {@link ContentValues} for the given root.
* @param values {@link ContentValues} that receives values.
+ * @param extraValues {@link ContentValues} that receives extra values for roots.
+ * @param parentDocumentId Parent document ID.
+ * @param supportedOperations Array of Operation code supported by the device.
* @param root Root to be converted {@link ContentValues}.
*/
static void getStorageDocumentValues(
ContentValues values,
ContentValues extraValues,
String parentDocumentId,
+ int[] operationsSupported,
MtpRoot root) {
values.clear();
values.put(COLUMN_DEVICE_ID, root.mDeviceId);
@@ -559,9 +726,7 @@ class MtpDatabase {
values.put(Document.COLUMN_FLAGS, 0);
values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace);
- extraValues.put(
- Root.COLUMN_FLAGS,
- Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+ extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported));
extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -575,20 +740,10 @@ class MtpDatabase {
* @param info MTP object info.
*/
static void getObjectDocumentValues(
- ContentValues values, int deviceId, String parentId, MtpObjectInfo info) {
+ ContentValues values, int deviceId, String parentId, int[] operationsSupported,
+ MtpObjectInfo info) {
values.clear();
final String mimeType = getMimeType(info);
- int flag = 0;
- if (info.getProtectionStatus() == 0) {
- flag |= Document.FLAG_SUPPORTS_DELETE |
- Document.FLAG_SUPPORTS_WRITE;
- if (mimeType == Document.MIME_TYPE_DIR) {
- flag |= Document.FLAG_DIR_SUPPORTS_CREATE;
- }
- }
- if (info.getThumbCompressedSize() > 0) {
- flag |= Document.FLAG_SUPPORTS_THUMBNAIL;
- }
values.put(COLUMN_DEVICE_ID, deviceId);
values.put(COLUMN_STORAGE_ID, info.getStorageId());
values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
@@ -602,8 +757,10 @@ class MtpDatabase {
Document.COLUMN_LAST_MODIFIED,
info.getDateModified() != 0 ? info.getDateModified() : null);
values.putNull(Document.COLUMN_ICON);
- values.put(Document.COLUMN_FLAGS, flag);
- values.put(Document.COLUMN_SIZE, info.getCompressedSize());
+ values.put(Document.COLUMN_FLAGS, getDocumentFlags(
+ operationsSupported, mimeType, info.getThumbCompressedSizeLong(),
+ info.getProtectionStatus()));
+ values.put(Document.COLUMN_SIZE, info.getCompressedSizeLong());
}
private static String getMimeType(MtpObjectInfo info) {
@@ -614,7 +771,44 @@ class MtpDatabase {
if (formatCodeMimeType != null) {
return formatCodeMimeType;
}
- return MediaFile.getMimeTypeForFile(info.getName());
+ final String mediaFileMimeType = MediaFile.getMimeTypeForFile(info.getName());
+ if (mediaFileMimeType != null) {
+ return mediaFileMimeType;
+ }
+ // We don't know the file type.
+ return "application/octet-stream";
+ }
+
+ private static int getRootFlags(int[] operationsSupported) {
+ int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
+ if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
+ rootFlag |= Root.FLAG_SUPPORTS_CREATE;
+ }
+ return rootFlag;
+ }
+
+ private static int getDocumentFlags(
+ int[] operationsSupported, String mimeType, long thumbnailSize, int protectionState) {
+ int flag = 0;
+ if (MtpDeviceRecord.isWritingSupported(operationsSupported) &&
+ protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
+ flag |= Document.FLAG_SUPPORTS_WRITE;
+ }
+ if (MtpDeviceRecord.isSupported(
+ operationsSupported, MtpConstants.OPERATION_DELETE_OBJECT) &&
+ (protectionState == MtpConstants.PROTECTION_STATUS_NONE ||
+ protectionState == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA)) {
+ flag |= Document.FLAG_SUPPORTS_DELETE;
+ }
+ if (mimeType.equals(Document.MIME_TYPE_DIR) &&
+ MtpDeviceRecord.isWritingSupported(operationsSupported) &&
+ protectionState == MtpConstants.PROTECTION_STATUS_NONE) {
+ flag |= Document.FLAG_DIR_SUPPORTS_CREATE;
+ }
+ if (thumbnailSize > 0) {
+ flag |= Document.FLAG_SUPPORTS_THUMBNAIL;
+ }
+ return flag;
}
static String[] strings(Object... args) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index 3cfb82f24746..ff4b89f99e12 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -30,7 +30,7 @@ import java.util.Map;
* Class containing MtpDatabase constants.
*/
class MtpDatabaseConstants {
- static final int DATABASE_VERSION = 1;
+ static final int DATABASE_VERSION = 4;
static final String DATABASE_NAME = "database";
static final int FLAG_DATABASE_IN_MEMORY = 1;
@@ -62,6 +62,7 @@ class MtpDatabaseConstants {
static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
static final String COLUMN_DOCUMENT_TYPE = "document_type";
static final String COLUMN_ROW_STATE = "row_state";
+ static final String COLUMN_MAPPING_KEY = "column_mapping_key";
/**
* The state represents that the row has a valid object handle.
@@ -78,22 +79,10 @@ class MtpDatabaseConstants {
static final int ROW_STATE_INVALIDATED = 1;
/**
- * The state represents the raw has a valid object handle but it may be going to be mapped with
- * another rows invalidated. After fetching all documents under the parent, the database tries
- * to map the pending documents and the invalidated documents in order to keep old document ID
- * alive.
+ * The documents are of device/storage that are disconnected now. The documents are invisible
+ * but their document ID will be reuse when the device/storage is connected again.
*/
- static final int ROW_STATE_PENDING = 2;
-
- /**
- * Mapping mode that uses MTP identifier to find corresponding rows.
- */
- static final int MAP_BY_MTP_IDENTIFIER = 0;
-
- /**
- * Mapping mode that uses name to find corresponding rows.
- */
- static final int MAP_BY_NAME = 1;
+ static final int ROW_STATE_DISCONNECTED = 2;
@IntDef(value = { DOCUMENT_TYPE_DEVICE, DOCUMENT_TYPE_STORAGE, DOCUMENT_TYPE_OBJECT })
@Retention(RetentionPolicy.SOURCE)
@@ -121,13 +110,14 @@ class MtpDatabaseConstants {
"CREATE TABLE " + TABLE_DOCUMENTS + " (" +
Document.COLUMN_DOCUMENT_ID +
" INTEGER PRIMARY KEY AUTOINCREMENT," +
- COLUMN_DEVICE_ID + " INTEGER NOT NULL," +
+ COLUMN_DEVICE_ID + " INTEGER," +
COLUMN_STORAGE_ID + " INTEGER," +
COLUMN_OBJECT_HANDLE + " INTEGER," +
COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
COLUMN_ROW_STATE + " INTEGER NOT NULL," +
COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," +
- Document.COLUMN_MIME_TYPE + " TEXT," +
+ COLUMN_MAPPING_KEY + " STRING," +
+ Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," +
Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
Document.COLUMN_SUMMARY + " TEXT," +
Document.COLUMN_LAST_MODIFIED + " INTEGER," +
@@ -176,7 +166,7 @@ class MtpDatabaseConstants {
private static String createJoinFromClosure(
String table1, String table2, String column1, String column2) {
- return table1 + " INNER JOIN " + table2 +
+ return table1 + " LEFT JOIN " + table2 +
" ON " + table1 + "." + column1 + " = " + table2 + "." + column2;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
index fa99a3883c58..393c4de89ea4 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
@@ -17,22 +17,51 @@
package com.android.mtp;
import android.annotation.Nullable;
+import android.mtp.MtpConstants;
class MtpDeviceRecord {
public final int deviceId;
public final String name;
+ public final @Nullable String deviceKey;
public final boolean opened;
public final MtpRoot[] roots;
public final @Nullable int[] operationsSupported;
public final @Nullable int[] eventsSupported;
- MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots,
- @Nullable int[] operationsSupported, @Nullable int[] eventsSupported) {
+ MtpDeviceRecord(int deviceId, String name, @Nullable String deviceKey, boolean opened,
+ MtpRoot[] roots, @Nullable int[] operationsSupported,
+ @Nullable int[] eventsSupported) {
this.deviceId = deviceId;
this.name = name;
this.opened = opened;
this.roots = roots;
+ this.deviceKey = deviceKey;
this.operationsSupported = operationsSupported;
this.eventsSupported = eventsSupported;
}
+
+ /**
+ * Helper method to check operations/events are supported by the device or not.
+ */
+ static boolean isSupported(@Nullable int[] supportedList, int code) {
+ if (supportedList == null) {
+ return false;
+ }
+ for (int i = 0; i < supportedList.length; i++) {
+ if (supportedList[i] == code) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static boolean isPartialReadSupported(@Nullable int[] supportedList, long fileSize) {
+ return fileSize <= 0xffffffffl &&
+ isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT);
+ }
+
+ static boolean isWritingSupported(@Nullable int[] supportedList) {
+ return isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT_INFO) &&
+ isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT);
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 033845401b4b..63c4ef8bb8c4 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -20,10 +20,12 @@ import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
+import android.database.MatrixCursor;
import android.graphics.Point;
import android.media.MediaFile;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
@@ -35,6 +37,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -163,17 +166,25 @@ public class MtpDocumentsProvider extends DocumentsProvider {
try {
openDevice(parentIdentifier.mDeviceId);
if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
- final Identifier singleStorageIdentifier =
- mDatabase.getSingleStorageIdentifier(parentDocumentId);
- if (singleStorageIdentifier == null) {
+ final String[] storageDocIds = mDatabase.getStorageDocumentIds(parentDocumentId);
+ if (storageDocIds.length == 0) {
+ // Remote device does not provide storages. Maybe it is locked.
+ return createErrorCursor(projection, R.string.error_locked_device);
+ } else if (storageDocIds.length > 1) {
// Returns storage list from database.
return mDatabase.queryChildDocuments(projection, parentDocumentId);
}
- parentIdentifier = singleStorageIdentifier;
+
+ // Exact one storage is found. Skip storage and returns object in the single
+ // storage.
+ parentIdentifier = mDatabase.createIdentifier(storageDocIds[0]);
}
+
// Returns object list from document loader.
return getDocumentLoader(parentIdentifier).queryChildDocuments(
projection, parentIdentifier);
+ } catch (BusyDeviceException exception) {
+ return createErrorCursor(projection, R.string.error_busy_device);
} catch (IOException exception) {
Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception);
throw new FileNotFoundException(exception.getMessage());
@@ -190,6 +201,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final Identifier identifier = mDatabase.createIdentifier(documentId);
try {
openDevice(identifier.mDeviceId);
+ final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
switch (mode) {
case "r":
final long fileSize = getFileSize(documentId);
@@ -197,7 +209,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
// 4GB. Fallback to non-seekable file descriptor.
// TODO: Use getPartialObject64 for MTP devices that support Android vendor
// extension.
- if (fileSize <= 0xffffffffl) {
+ if (MtpDeviceRecord.isPartialReadSupported(
+ device.operationsSupported, fileSize)) {
return mAppFuse.openFile(Integer.parseInt(documentId));
} else {
return getPipeManager(identifier).readDocument(mMtpManager, identifier);
@@ -205,8 +218,13 @@ public class MtpDocumentsProvider extends DocumentsProvider {
case "w":
// TODO: Clear the parent document loader task (if exists) and call notify
// when writing is completed.
- return getPipeManager(identifier).writeDocument(
- getContext(), mMtpManager, identifier);
+ if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
+ return getPipeManager(identifier).writeDocument(
+ getContext(), mMtpManager, identifier, device.operationsSupported);
+ } else {
+ throw new UnsupportedOperationException(
+ "The device does not support writing operation.");
+ }
case "rw":
// TODO: Add support for "rw" mode.
throw new UnsupportedOperationException(
@@ -279,6 +297,10 @@ public class MtpDocumentsProvider extends DocumentsProvider {
try {
final Identifier parentId = mDatabase.createIdentifier(parentDocumentId);
openDevice(parentId.mDeviceId);
+ final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
+ if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) {
+ throw new UnsupportedOperationException();
+ }
final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
pipe[0].close(); // 0 bytes for a new document.
final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
@@ -294,7 +316,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final MtpObjectInfo infoWithHandle =
new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build();
final String documentId = mDatabase.putNewDocument(
- parentId.mDeviceId, parentDocumentId, infoWithHandle);
+ parentId.mDeviceId, parentDocumentId, record.operationsSupported,
+ infoWithHandle);
getDocumentLoader(parentId).clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
@@ -312,15 +335,19 @@ public class MtpDocumentsProvider extends DocumentsProvider {
if (DEBUG) {
Log.d(TAG, "Open device " + deviceId);
}
- mMtpManager.openDevice(deviceId);
- mDeviceToolkits.put(
- deviceId, new DeviceToolkit(mMtpManager, mResolver, mDatabase));
+ final MtpDeviceRecord device = mMtpManager.openDevice(deviceId);
+ final DeviceToolkit toolkit =
+ new DeviceToolkit(mMtpManager, mResolver, mDatabase, device);
+ mDeviceToolkits.put(deviceId, toolkit);
mIntentSender.sendUpdateNotificationIntent();
try {
mRootScanner.resume().await();
} catch (InterruptedException error) {
Log.e(TAG, "openDevice", error);
}
+ // Resume document loader to remap disconnected document ID. Must be invoked after the
+ // root scanner resumes.
+ toolkit.mDocumentLoader.resume();
}
}
@@ -332,27 +359,35 @@ public class MtpDocumentsProvider extends DocumentsProvider {
mIntentSender.sendUpdateNotificationIntent();
}
- int[] getOpenedDeviceIds() {
+ MtpDeviceRecord[] getOpenedDeviceRecordsCache() {
synchronized (mDeviceListLock) {
- return mMtpManager.getOpenedDeviceIds();
+ final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()];
+ int i = 0;
+ for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
+ records[i] = toolkit.mDeviceRecord;
+ i++;
+ }
+ return records;
}
}
- String getDeviceName(int deviceId) throws IOException {
- synchronized (mDeviceListLock) {
- for (final MtpDeviceRecord device : mMtpManager.getDevices()) {
- if (device.deviceId == deviceId) {
- return device.name;
- }
- }
- throw new IOException("Not found the device: " + Integer.toString(deviceId));
- }
+ /**
+ * Obtains document ID for the given device ID.
+ * @param deviceId
+ * @return document ID
+ * @throws FileNotFoundException device ID has not been build.
+ */
+ public String getDeviceDocumentId(int deviceId) throws FileNotFoundException {
+ return mDatabase.getDeviceDocumentId(deviceId);
}
/**
* Resumes root scanner to handle the update of device list.
*/
void resumeRootScanner() {
+ if (DEBUG) {
+ Log.d(MtpDocumentsProvider.TAG, "resumeRootScanner");
+ }
mRootScanner.resume();
}
@@ -363,7 +398,10 @@ public class MtpDocumentsProvider extends DocumentsProvider {
public void shutdown() {
synchronized (mDeviceListLock) {
try {
- for (final int id : mMtpManager.getOpenedDeviceIds()) {
+ // Copy the opened key set because it will be modified when closing devices.
+ final Integer[] keySet =
+ mDeviceToolkits.keySet().toArray(new Integer[mDeviceToolkits.size()]);
+ for (final int id : keySet) {
closeDeviceInternal(id);
}
} catch (InterruptedException|IOException e) {
@@ -401,10 +439,10 @@ public class MtpDocumentsProvider extends DocumentsProvider {
if (DEBUG) {
Log.d(TAG, "Close device " + deviceId);
}
- getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
+ getDeviceToolkit(deviceId).mDocumentLoader.close();
mDeviceToolkits.remove(deviceId);
mMtpManager.closeDevice(deviceId);
- if (getOpenedDeviceIds().length == 0) {
+ if (mDeviceToolkits.size() == 0) {
mRootScanner.pause();
}
}
@@ -442,13 +480,33 @@ public class MtpDocumentsProvider extends DocumentsProvider {
}
}
+ /**
+ * Creates empty cursor with specific error message.
+ *
+ * @param projection Column names.
+ * @param stringResId String resource ID of error message.
+ * @return Empty cursor with error message.
+ */
+ private Cursor createErrorCursor(String[] projection, int stringResId) {
+ final Bundle bundle = new Bundle();
+ bundle.putString(DocumentsContract.EXTRA_ERROR, mResources.getString(stringResId));
+ final Cursor cursor = new MatrixCursor(projection);
+ cursor.setExtras(bundle);
+ return cursor;
+ }
+
private static class DeviceToolkit {
public final PipeManager mPipeManager;
public final DocumentLoader mDocumentLoader;
-
- public DeviceToolkit(MtpManager manager, ContentResolver resolver, MtpDatabase database) {
- mPipeManager = new PipeManager();
- mDocumentLoader = new DocumentLoader(manager, resolver, database);
+ public final MtpDeviceRecord mDeviceRecord;
+
+ public DeviceToolkit(MtpManager manager,
+ ContentResolver resolver,
+ MtpDatabase database,
+ MtpDeviceRecord record) {
+ mPipeManager = new PipeManager(database);
+ mDocumentLoader = new DocumentLoader(record, manager, resolver, database);
+ mDeviceRecord = record;
}
}
@@ -457,8 +515,13 @@ public class MtpDocumentsProvider extends DocumentsProvider {
public long readObjectBytes(
int inode, long offset, long size, byte[] buffer) throws IOException {
final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
- return mMtpManager.getPartialObject(
- identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
+ final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
+ if (MtpDeviceRecord.isPartialReadSupported(record.operationsSupported, offset)) {
+ return mMtpManager.getPartialObject(
+ identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
+ } else {
+ throw new UnsupportedOperationException();
+ }
}
@Override
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
index 9c4952bc5759..9b42b7828893 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
@@ -67,38 +67,25 @@ public class MtpDocumentsService extends Service {
*/
private boolean updateForegroundState() {
final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
- final int[] deviceIds = provider.getOpenedDeviceIds();
int notificationId = 0;
Notification notification = null;
// TODO: Hide notification if the device has already been removed.
- for (final int deviceId : deviceIds) {
- try {
- final String title = getResources().getString(
- R.string.accessing_notification_title,
- provider.getDeviceName(deviceIds[0]));
- final String description = getResources().getString(
- R.string.accessing_notification_description);
- notificationId = deviceId;
- notification = new Notification.Builder(this)
- .setLocalOnly(true)
- .setContentTitle(title)
- .setContentText(description)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .build();
- mNotificationManager.notify(deviceId, notification);
- } catch (IOException exp) {
- logErrorMessage(exp);
- // If we failed to obtain device name, it looks the device is unusable.
- // Because this is the last device we opened, we should hide the notification
- // for the case.
- try {
- provider.closeDevice(deviceIds[0]);
- } catch (IOException | InterruptedException closeError) {
- logErrorMessage(closeError);
- }
- }
+ for (final MtpDeviceRecord record : provider.getOpenedDeviceRecordsCache()) {
+ final String title = getResources().getString(
+ R.string.accessing_notification_title,
+ record.name);
+ final String description = getResources().getString(
+ R.string.accessing_notification_description);
+ notificationId = record.deviceId;
+ notification = new Notification.Builder(this)
+ .setLocalOnly(true)
+ .setContentTitle(title)
+ .setContentText(description)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_LOW)
+ .build();
+ mNotificationManager.notify(record.deviceId, notification);
}
if (notification != null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 5519efd5a323..1966e61fbc53 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -33,6 +33,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -64,16 +65,14 @@ class MtpManager {
*/
private static final int PROTOCOL_MTP = 0;
-
private final UsbManager mManager;
- // TODO: Save and restore the set of opened device.
private final SparseArray<MtpDevice> mDevices = new SparseArray<>();
MtpManager(Context context) {
mManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
}
- synchronized void openDevice(int deviceId) throws IOException {
+ synchronized MtpDeviceRecord openDevice(int deviceId) throws IOException {
UsbDevice rawDevice = null;
for (final UsbDevice candidate : mManager.getDeviceList().values()) {
if (candidate.getDeviceId() == deviceId) {
@@ -101,7 +100,8 @@ class MtpManager {
}
if (!device.open(connection)) {
- throw new IOException("Failed to open a MTP device.");
+ // We cannot open connection when another application use the device.
+ throw new BusyDeviceException();
}
// Handle devices that fail to obtain storages just after opening a MTP session.
@@ -111,6 +111,8 @@ class MtpManager {
}
mDevices.put(deviceId, device);
+
+ return createDeviceRecord(rawDevice);
}
synchronized void closeDevice(int deviceId) throws IOException {
@@ -124,45 +126,11 @@ class MtpManager {
if (!isMtpDevice(device)) {
continue;
}
- final MtpDevice mtpDevice = mDevices.get(device.getDeviceId());
- final boolean opened = mtpDevice != null;
- final String name = device.getProductName();
- MtpRoot[] roots;
- int[] operationsSupported = null;
- int[] eventsSupported = null;
- if (opened) {
- try {
- roots = getRoots(device.getDeviceId());
- } catch (IOException exp) {
- Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
- // If we failed to fetch roots for the device, we still returns device model
- // with an empty set of roots so that the device is shown DocumentsUI as long as
- // the device is physically connected.
- roots = new MtpRoot[0];
- }
- final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
- if (info != null) {
- operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
- eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
- }
- } else {
- roots = new MtpRoot[0];
- }
- devices.add(new MtpDeviceRecord(
- device.getDeviceId(), name, opened, roots, operationsSupported,
- eventsSupported));
+ devices.add(createDeviceRecord(device));
}
return devices.toArray(new MtpDeviceRecord[devices.size()]);
}
- synchronized int[] getOpenedDeviceIds() {
- final int[] result = new int[mDevices.size()];
- for (int i = 0; i < result.length; i++) {
- result[i] = mDevices.keyAt(i);
- }
- return result;
- }
-
MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
@@ -187,7 +155,6 @@ class MtpManager {
}
}
- @VisibleForTesting
long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
throws IOException {
final MtpDevice device = getDevice(deviceId);
@@ -279,6 +246,36 @@ class MtpManager {
}
}
+ private MtpDeviceRecord createDeviceRecord(UsbDevice device) {
+ final MtpDevice mtpDevice = mDevices.get(device.getDeviceId());
+ final boolean opened = mtpDevice != null;
+ final String name = device.getProductName();
+ MtpRoot[] roots;
+ int[] operationsSupported = null;
+ int[] eventsSupported = null;
+ if (opened) {
+ try {
+ roots = getRoots(device.getDeviceId());
+ } catch (IOException exp) {
+ Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exp);
+ // If we failed to fetch roots for the device, we still returns device model
+ // with an empty set of roots so that the device is shown DocumentsUI as long as
+ // the device is physically connected.
+ roots = new MtpRoot[0];
+ }
+ final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
+ if (info != null) {
+ operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
+ eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
+ }
+ } else {
+ roots = new MtpRoot[0];
+ }
+ return new MtpDeviceRecord(
+ device.getDeviceId(), name, device.getSerialNumber(), opened, roots,
+ operationsSupported, eventsSupported);
+ }
+
static boolean isMtpDevice(UsbDevice device) {
for (int i = 0; i < device.getInterfaceCount(); i++) {
final UsbInterface usbInterface = device.getInterface(i);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 16523bca454c..73042c4d7b36 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -29,12 +29,14 @@ import java.util.concurrent.Executors;
class PipeManager {
final ExecutorService mExecutor;
+ final MtpDatabase mDatabase;
- PipeManager() {
- this(Executors.newSingleThreadExecutor());
+ PipeManager(MtpDatabase database) {
+ this(database, Executors.newSingleThreadExecutor());
}
- PipeManager(ExecutorService executor) {
+ PipeManager(MtpDatabase database, ExecutorService executor) {
+ this.mDatabase = database;
this.mExecutor = executor;
}
@@ -44,9 +46,11 @@ class PipeManager {
return task.getReadingFileDescriptor();
}
- ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier)
+ ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier,
+ int[] operationsSupported)
throws IOException {
- final Task task = new WriteDocumentTask(context, model, identifier);
+ final Task task = new WriteDocumentTask(
+ context, model, identifier, operationsSupported, mDatabase);
mExecutor.execute(task);
return task.getWritingFileDescriptor();
}
@@ -100,11 +104,19 @@ class PipeManager {
private static class WriteDocumentTask extends Task {
private final Context mContext;
-
- WriteDocumentTask(Context context, MtpManager model, Identifier identifier)
+ private final MtpDatabase mDatabase;
+ private final int[] mOperationsSupported;
+
+ WriteDocumentTask(Context context,
+ MtpManager model,
+ Identifier identifier,
+ int[] supportedOperations,
+ MtpDatabase database)
throws IOException {
super(model, identifier);
mContext = context;
+ mDatabase = database;
+ mOperationsSupported = supportedOperations;
}
@Override
@@ -112,7 +124,7 @@ class PipeManager {
File tempFile = null;
try {
// Obtain a temporary file and copy the data to it.
- tempFile = mContext.getCacheDir().createTempFile("mtp", "tmp");
+ tempFile = File.createTempFile("mtp", "tmp", mContext.getCacheDir());
try (
final FileOutputStream tempOutputStream =
new ParcelFileDescriptor.AutoCloseOutputStream(
@@ -140,12 +152,23 @@ class PipeManager {
// Create the target object info with a correct file size and upload the file.
final MtpObjectInfo targetObjectInfo =
new MtpObjectInfo.Builder(placeholderObjectInfo)
- .setCompressedSize((int) tempFile.length())
+ .setCompressedSize(tempFile.length())
.build();
final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
- mManager.createDocument(mIdentifier.mDeviceId,
- targetObjectInfo, tempInputDescriptor);
+ final int newObjectHandle = mManager.createDocument(
+ mIdentifier.mDeviceId, targetObjectInfo, tempInputDescriptor);
+
+ final MtpObjectInfo newObjectInfo = mManager.getObjectInfo(
+ mIdentifier.mDeviceId, newObjectHandle);
+ final Identifier parentIdentifier =
+ mDatabase.getParentIdentifier(mIdentifier.mDocumentId);
+ mDatabase.updateObject(
+ mIdentifier.mDocumentId,
+ mIdentifier.mDeviceId,
+ parentIdentifier.mDocumentId,
+ mOperationsSupported,
+ newObjectInfo);
} catch (IOException error) {
Log.w(MtpDocumentsProvider.TAG,
"Failed to send a file because of: " + error.getMessage());
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
index c7206a7929e0..84745b29e428 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ReceiverActivity.java
@@ -17,10 +17,15 @@
package com.android.mtp;
import android.app.Activity;
-import android.content.ComponentName;
import android.content.Intent;
+import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import java.io.IOException;
/**
* Invisible activity to receive intents.
@@ -33,14 +38,21 @@ public class ReceiverActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {
- // TODO: To obtain data URI for the attached device, we need to wait until RootScanner
- // found the device and add it to database. Set correct root URI, and use ACTION_BROWSE
- // to launch Documents UI.
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(new ComponentName(
- "com.android.documentsui", "com.android.documentsui.LauncherActivity"));
- this.startActivity(intent);
+ final UsbDevice device = getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ try {
+ final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
+ provider.openDevice(device.getDeviceId());
+ final String deviceRootId = provider.getDeviceDocumentId(device.getDeviceId());
+ final Uri uri = DocumentsContract.buildRootUri(
+ MtpDocumentsProvider.AUTHORITY, deviceRootId);
+
+ final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
+ intent.setData(uri);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ this.startActivity(intent);
+ } catch (IOException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Failed to open device", exception);
+ }
}
finish();
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index a4c3cf4fa5b4..82ba21f659d1 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -22,6 +22,7 @@ import android.os.Process;
import android.provider.DocumentsContract;
import android.util.Log;
+import java.io.FileNotFoundException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -70,8 +71,7 @@ final class RootScanner {
* Notifies a change of the roots list via ContentResolver.
*/
void notifyChange() {
- final Uri uri =
- DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
+ final Uri uri = DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
mResolver.notifyChange(uri, null, false);
}
@@ -123,14 +123,22 @@ final class RootScanner {
// Update devices.
final MtpDeviceRecord[] devices = mManager.getDevices();
- mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
- for (final MtpDeviceRecord device : devices) {
- if (mDatabase.getMapper().putDeviceDocument(device)) {
+ try {
+ mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
+ for (final MtpDeviceRecord device : devices) {
+ if (mDatabase.getMapper().putDeviceDocument(device)) {
+ changed = true;
+ }
+ }
+ if (mDatabase.getMapper().stopAddingDocuments(
+ null /* parentDocumentId */)) {
changed = true;
}
- }
- if (mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */)) {
- changed = true;
+ } catch (FileNotFoundException exception) {
+ // The top root (ID is null) must exist always.
+ // FileNotFoundException is unexpected.
+ Log.e(MtpDocumentsProvider.TAG, "Unexpected FileNotFoundException", exception);
+ throw new AssertionError("Unexpected exception for the top parent", exception);
}
// Update roots.
@@ -139,12 +147,18 @@ final class RootScanner {
if (documentId == null) {
continue;
}
- mDatabase.getMapper().startAddingDocuments(documentId);
- if (mDatabase.getMapper().putStorageDocuments(documentId, device.roots)) {
- changed = true;
- }
- if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
- changed = true;
+ try {
+ mDatabase.getMapper().startAddingDocuments(documentId);
+ if (mDatabase.getMapper().putStorageDocuments(
+ documentId, device.eventsSupported, device.roots)) {
+ changed = true;
+ }
+ if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
+ changed = true;
+ }
+ } catch (FileNotFoundException exception) {
+ Log.e(MtpDocumentsProvider.TAG, "Parent document is gone.", exception);
+ continue;
}
}
diff --git a/media/mca/effect/java/android/media/effect/package-info.java b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
index b2c14ff3ab3e..55f55b0edbc3 100644
--- a/media/mca/effect/java/android/media/effect/package-info.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,12 @@
* limitations under the License.
*/
+package com.android.mtp.exceptions;
-package android.media.effect;
+import java.io.IOException;
/**
- * <h1>Effect Framework</h1>
- *
- * This package includes a collection of high-performance visual effects that make use of the
- * mobile filter framework subsystem.
- *
- * TODO: More Documentation
- *
+ * Exception thrown when the device is busy and the requested operation cannon be completed.
*/
+public class BusyDeviceException extends IOException {
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index af1fed49f272..db25421afab0 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -36,23 +36,37 @@ public class DocumentLoaderTest extends AndroidTestCase {
private TestContentResolver mResolver;
private DocumentLoader mLoader;
final private Identifier mParentIdentifier = new Identifier(
- 0, 0, 0, "1", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE);
+ 0, 0, 0, "2", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE);
@Override
- public void setUp() {
+ public void setUp() throws Exception {
mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device", null, true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", new int[0], new MtpRoot[] {
new MtpRoot(0, 0, "Storage", 1000, 1000, "")
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
+
mManager = new BlockableTestMtpManager(getContext());
mResolver = new TestContentResolver();
- mLoader = new DocumentLoader(mManager, mResolver, mDatabase);
+ mLoader = new DocumentLoader(
+ new MtpDeviceRecord(
+ 0, "Device", "Key", true, new MtpRoot[0],
+ TestUtil.OPERATIONS_SUPPORTED, new int[0]),
+ mManager,
+ mResolver,
+ mDatabase);
}
@Override
- public void tearDown() {
+ public void tearDown() throws Exception {
+ mLoader.close();
mDatabase.close();
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index a49dc6784af4..f9e8225dcb24 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -30,10 +30,11 @@ import java.io.FileNotFoundException;
import static android.provider.DocumentsContract.Document.*;
import static com.android.mtp.MtpDatabase.strings;
import static com.android.mtp.MtpDatabaseConstants.*;
+import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED;
@SmallTest
public class MtpDatabaseTest extends AndroidTestCase {
- private final String[] COLUMN_NAMES = new String[] {
+ private static final String[] COLUMN_NAMES = new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
MtpDatabaseConstants.COLUMN_DEVICE_ID,
MtpDatabaseConstants.COLUMN_STORAGE_ID,
@@ -75,13 +76,10 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
public void testPutSingleStorageDocuments() throws Exception {
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 1, "Storage", 1000, 2000, "")
});
mDatabase.getMapper().stopAddingDocuments("1");
@@ -95,7 +93,8 @@ public class MtpDatabaseTest extends AndroidTestCase {
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
+ assertEquals(
+ DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
assertTrue(isNull(cursor, COLUMN_SUMMARY));
assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
@@ -103,7 +102,8 @@ public class MtpDatabaseTest extends AndroidTestCase {
assertEquals(0, getInt(cursor, COLUMN_FLAGS));
assertEquals(1000, getInt(cursor, COLUMN_SIZE));
assertEquals(
- MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
+ MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE,
+ getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.close();
}
@@ -138,8 +138,10 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
public void testPutStorageDocuments() throws Exception {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ addTestDevice();
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 1, "Storage", 1000, 2000, ""),
new MtpRoot(0, 2, "Storage", 2000, 4000, ""),
new MtpRoot(0, 3, "/@#%&<>Storage", 3000, 6000,"")
@@ -150,7 +152,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
assertEquals(3, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
@@ -165,11 +167,11 @@ public class MtpDatabaseTest extends AndroidTestCase {
MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals("/@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
@@ -186,18 +188,21 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
public void testPutChildDocuments() throws Exception {
- mDatabase.getMapper().startAddingDocuments("parentId");
- mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
});
- final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "parentId");
+ final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "2");
assertEquals(3, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals(100, getInt(cursor, COLUMN_OBJECT_HANDLE));
@@ -216,7 +221,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals(101, getInt(cursor, COLUMN_OBJECT_HANDLE));
@@ -235,7 +240,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals(102, getInt(cursor, COLUMN_OBJECT_HANDLE));
@@ -256,6 +261,58 @@ public class MtpDatabaseTest extends AndroidTestCase {
cursor.close();
}
+ public void testPutChildDocuments_operationsSupported() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
+
+ // Put a document with empty supported operations.
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new int[0], new MtpObjectInfo[] {
+ createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ try (final Cursor cursor =
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(0, cursor.getInt(0));
+ }
+
+ // Put a document with writable operations.
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new int[] {
+ MtpConstants.OPERATION_SEND_OBJECT,
+ MtpConstants.OPERATION_SEND_OBJECT_INFO,
+ }, new MtpObjectInfo[] {
+ createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ try (final Cursor cursor =
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(Document.FLAG_SUPPORTS_WRITE, cursor.getInt(0));
+ }
+
+ // Put a document with deletable operations.
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new int[] {
+ MtpConstants.OPERATION_DELETE_OBJECT
+ }, new MtpObjectInfo[] {
+ createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024)
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ try (final Cursor cursor =
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(Document.FLAG_SUPPORTS_DELETE, cursor.getInt(0));
+ }
+ }
+
public void testRestoreIdForRootDocuments() throws Exception {
final String[] columns = new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
@@ -263,8 +320,10 @@ public class MtpDatabaseTest extends AndroidTestCase {
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ // Add device and two storages.
+ addTestDevice();
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 1000, 0, ""),
new MtpRoot(0, 101, "Storage B", 1001, 0, "")
});
@@ -273,63 +332,40 @@ public class MtpDatabaseTest extends AndroidTestCase {
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(101, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
}
+ // Clear mapping and add a device.
mDatabase.getMapper().clearMapping();
+ addTestDevice();
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
- assertEquals(2, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
+ assertEquals(0, cursor.getCount());
cursor.close();
}
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ // Add two storages, but one's name is different from previous one.
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 200, "Storage A", 2000, 0, ""),
new MtpRoot(0, 202, "Storage C", 2002, 0, "")
});
+ mDatabase.getMapper().stopAddingDocuments("1");
{
- final Cursor cursor = mDatabase.queryRootDocuments(columns);
- assertEquals(3, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.moveToNext();
- assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID));
- assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
- cursor.close();
- }
-
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
-
- {
+ // After compeleting mapping, Storage A can be obtained with new storage ID.
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
@@ -346,69 +382,49 @@ public class MtpDatabaseTest extends AndroidTestCase {
MtpDatabaseConstants.COLUMN_OBJECT_HANDLE,
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- mDatabase.getMapper().startAddingDocuments("parentId");
- mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
+
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024)
});
mDatabase.getMapper().clearMapping();
- {
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
- assertEquals(3, cursor.getCount());
-
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
-
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("image.jpg", getString(cursor, COLUMN_DISPLAY_NAME));
-
- cursor.moveToNext();
- assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("music.mp3", getString(cursor, COLUMN_DISPLAY_NAME));
+ addTestDevice();
+ addTestStorage("1");
+ {
+ // Don't return objects that lost MTP object handles.
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "2");
+ assertEquals(0, cursor.getCount());
cursor.close();
}
- mDatabase.getMapper().startAddingDocuments("parentId");
- mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
createDocument(203, "video.mp4", MtpConstants.FORMAT_MP4_CONTAINER, 1024),
});
+ mDatabase.getMapper().stopAddingDocuments("2");
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
- assertEquals(4, cursor.getCount());
-
- cursor.moveToPosition(3);
- assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
- assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
-
- cursor.close();
- }
-
- mDatabase.getMapper().stopAddingDocuments("parentId");
-
- {
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "2");
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
+
cursor.close();
}
}
@@ -424,18 +440,18 @@ public class MtpDatabaseTest extends AndroidTestCase {
Root.COLUMN_AVAILABLE_BYTES
};
mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device A", "Device key A", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 1, "Device B", "Device key B", true, new MtpRoot[0], null, null));
mDatabase.getMapper().stopAddingDocuments(null);
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().startAddingDocuments("2");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage", 0, 0, "")
});
- mDatabase.getMapper().putStorageDocuments("2", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(1, 100, "Storage", 0, 0, "")
});
@@ -467,12 +483,19 @@ public class MtpDatabaseTest extends AndroidTestCase {
mDatabase.getMapper().clearMapping();
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device A", "Device key A", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 1, "Device B", "Device key B", true, new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
mDatabase.getMapper().startAddingDocuments("1");
mDatabase.getMapper().startAddingDocuments("2");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 200, "Storage", 2000, 0, "")
});
- mDatabase.getMapper().putStorageDocuments("2", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(1, 300, "Storage", 3000, 0, "")
});
mDatabase.getMapper().stopAddingDocuments("1");
@@ -511,45 +534,71 @@ public class MtpDatabaseTest extends AndroidTestCase {
MtpDatabaseConstants.COLUMN_OBJECT_HANDLE
};
- mDatabase.getMapper().startAddingDocuments("parentId1");
- mDatabase.getMapper().startAddingDocuments("parentId2");
- mDatabase.getMapper().putChildDocuments(0, "parentId1", new MtpObjectInfo[] {
+ // Add device, storage, and two directories.
+ addTestDevice();
+ addTestStorage("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
+ createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ // Put note.txt in each directory.
+ mDatabase.getMapper().startAddingDocuments("3");
+ mDatabase.getMapper().startAddingDocuments("4");
+ mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().putChildDocuments(0, "parentId2", new MtpObjectInfo[] {
+ mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(101, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
+
+ // Clear mapping.
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("parentId1");
- mDatabase.getMapper().startAddingDocuments("parentId2");
- mDatabase.getMapper().putChildDocuments(0, "parentId1", new MtpObjectInfo[] {
+ // Add device, storage, and two directories again.
+ addTestDevice();
+ addTestStorage("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0),
+ createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ // Add note.txt in each directory again.
+ mDatabase.getMapper().startAddingDocuments("3");
+ mDatabase.getMapper().startAddingDocuments("4");
+ mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().putChildDocuments(0, "parentId2", new MtpObjectInfo[] {
+ mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().stopAddingDocuments("parentId1");
+ mDatabase.getMapper().stopAddingDocuments("3");
+ mDatabase.getMapper().stopAddingDocuments("4");
+ // Check if the two note.txt are mapped correctly.
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId1");
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "3");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
cursor.close();
}
{
- final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId2");
+ final Cursor cursor = mDatabase.queryChildDocuments(columns, "4");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
- assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+ assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(201, getInt(cursor, COLUMN_OBJECT_HANDLE));
cursor.close();
}
}
- public void testClearMtpIdentifierBeforeResolveRootDocuments() {
+ public void testClearMtpIdentifierBeforeResolveRootDocuments() throws Exception {
final String[] columns = new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
MtpDatabaseConstants.COLUMN_STORAGE_ID,
@@ -560,25 +609,32 @@ public class MtpDatabaseTest extends AndroidTestCase {
Root.COLUMN_AVAILABLE_BYTES
};
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage", 0, 0, ""),
});
mDatabase.getMapper().clearMapping();
+ addTestDevice();
+
+ try (final Cursor cursor = mDatabase.queryRoots(resources, rootColumns)) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("1", getString(cursor, Root.COLUMN_ROOT_ID));
+ }
+
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 200, "Storage", 2000, 0, ""),
});
mDatabase.getMapper().clearMapping();
+ addTestDevice();
+
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 300, "Storage", 3000, 0, ""),
});
mDatabase.getMapper().stopAddingDocuments("1");
@@ -609,50 +665,56 @@ public class MtpDatabaseTest extends AndroidTestCase {
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage", 0, 0, ""),
- });
+ // Add a device and a storage.
+ addTestDevice();
+ addTestStorage("1");
+
+ // Disconnect devices.
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
+ // Add a device and two storages that has same name.
+ addTestDevice();
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 200, "Storage", 2000, 0, ""),
new MtpRoot(0, 201, "Storage", 2001, 0, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
+
+ // First storage reuse document ID of previous storage.
cursor.moveToNext();
+ // One reuses exisitng document ID 1.
assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+
+ // Second one has new document ID.
cursor.moveToNext();
assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(201, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+
cursor.close();
}
}
- public void testReplaceExistingRoots() {
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ public void testReplaceExistingRoots() throws Exception {
+ addTestDevice();
// The client code should be able to replace existing rows with new information.
// Add one.
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 0, 0, ""),
});
mDatabase.getMapper().stopAddingDocuments("1");
// Replace it.
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage B", 1000, 1000, ""),
});
mDatabase.getMapper().stopAddingDocuments("1");
@@ -686,67 +748,60 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
}
- public void testFailToReplaceExisitingUnmappedRoots() {
+ public void testFailToReplaceExisitingUnmappedRoots() throws Exception {
// The client code should not be able to replace rows before resolving 'unmapped' rows.
// Add one.
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
-
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 0, 0, ""),
});
mDatabase.getMapper().clearMapping();
- final Cursor oldCursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID));
- assertEquals(1, oldCursor.getCount());
-
- // Add one.
- mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
- new MtpRoot(0, 101, "Storage B", 1000, 1000, ""),
- });
- // Add one more before resolving unmapped documents.
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
- new MtpRoot(0, 102, "Storage B", 1000, 1000, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("1");
- // Because the roots shares the same name, the roots should have new IDs.
- final Cursor newCursor = mDatabase.queryChildDocuments(
- strings(Document.COLUMN_DOCUMENT_ID), "1");
- assertEquals(2, newCursor.getCount());
- oldCursor.moveToNext();
- newCursor.moveToNext();
- assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
- newCursor.moveToNext();
- assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
-
- oldCursor.close();
- newCursor.close();
+ addTestDevice();
+ try (final Cursor oldCursor =
+ mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID))) {
+ assertEquals(1, oldCursor.getCount());
+ oldCursor.moveToNext();
+ assertEquals("1", getString(oldCursor, Root.COLUMN_ROOT_ID));
+
+ // Add one.
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
+ new MtpRoot(0, 101, "Storage B", 1000, 1000, ""),
+ });
+ // Add one more before resolving unmapped documents.
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
+ new MtpRoot(0, 102, "Storage B", 1000, 1000, ""),
+ });
+ mDatabase.getMapper().stopAddingDocuments("1");
+
+ // Because the roots shares the same name, the roots should have new IDs.
+ try (final Cursor newCursor = mDatabase.queryChildDocuments(
+ strings(Document.COLUMN_DOCUMENT_ID), "1")) {
+ assertEquals(2, newCursor.getCount());
+ newCursor.moveToNext();
+ assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
+ newCursor.moveToNext();
+ assertFalse(oldCursor.getString(0).equals(newCursor.getString(0)));
+ }
+ }
}
- public void testQueryDocuments() {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ public void testQueryDocuments() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
- final Cursor cursor = mDatabase.queryDocument("1", strings(Document.COLUMN_DISPLAY_NAME));
+ final Cursor cursor = mDatabase.queryDocument("2", strings(Document.COLUMN_DISPLAY_NAME));
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals("Storage A", getString(cursor, Document.COLUMN_DISPLAY_NAME));
+ assertEquals("Storage", getString(cursor, Document.COLUMN_DISPLAY_NAME));
cursor.close();
}
- public void testQueryRoots() {
+ public void testQueryRoots() throws Exception {
// Add device document.
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ addTestDevice();
// It the device does not have storages, it shows a device root.
{
@@ -758,7 +813,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 0, 0, "")
});
mDatabase.getMapper().stopAddingDocuments("1");
@@ -773,7 +828,7 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
new MtpRoot(0, 100, "Storage A", 0, 0, ""),
new MtpRoot(0, 101, "Storage B", 0, 0, "")
});
@@ -790,55 +845,45 @@ public class MtpDatabaseTest extends AndroidTestCase {
}
public void testGetParentId() throws FileNotFoundException {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ addTestDevice();
mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putChildDocuments(
- 0,
- "1",
- new MtpObjectInfo[] {
- createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
- });
+ mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] {
+ new MtpRoot(0, 100, "Storage A", 0, 0, ""),
+ });
mDatabase.getMapper().stopAddingDocuments("1");
- assertEquals("1", mDatabase.getParentIdentifier("2").mDocumentId);
- }
-
- public void testDeleteDocument() {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("2");
- mDatabase.getMapper().startAddingDocuments("1");
- mDatabase.getMapper().putChildDocuments(
- 0,
- "1",
- new MtpObjectInfo[] {
- createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
- });
- mDatabase.getMapper().stopAddingDocuments("1");
+ assertEquals("2", mDatabase.getParentIdentifier("3").mDocumentId);
+ }
+
+ public void testDeleteDocument() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
mDatabase.getMapper().startAddingDocuments("2");
- mDatabase.getMapper().putChildDocuments(
- 0,
- "2",
- new MtpObjectInfo[] {
- createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
- });
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
+ });
mDatabase.getMapper().stopAddingDocuments("2");
- mDatabase.deleteDocument("2");
+ mDatabase.getMapper().startAddingDocuments("3");
+ mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
+ });
+ mDatabase.getMapper().stopAddingDocuments("3");
+
+ mDatabase.deleteDocument("3");
{
// Do not query deleted documents.
final Cursor cursor =
- mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "1");
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
assertEquals(0, cursor.getCount());
cursor.close();
}
@@ -846,64 +891,62 @@ public class MtpDatabaseTest extends AndroidTestCase {
{
// Child document should be deleted also.
final Cursor cursor =
- mDatabase.queryDocument("3", strings(Document.COLUMN_DOCUMENT_ID));
+ mDatabase.queryDocument("4", strings(Document.COLUMN_DOCUMENT_ID));
assertEquals(0, cursor.getCount());
cursor.close();
}
}
- public void testPutNewDocument() {
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] {
- new MtpRoot(0, 100, "Storage A", 0, 0, ""),
- });
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ public void testPutNewDocument() throws Exception {
+ addTestDevice();
+ addTestStorage("1");
assertEquals(
- "2",
+ "3",
mDatabase.putNewDocument(
- 0, "1", createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024)));
+ 0, "2", OPERATIONS_SUPPORTED,
+ createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024)));
{
final Cursor cursor =
- mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "1");
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals("2", cursor.getString(0));
+ assertEquals("3", cursor.getString(0));
cursor.close();
}
// The new document should not be mapped with existing invalidated document.
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("1");
+ addTestDevice();
+ addTestStorage("1");
+
+ mDatabase.getMapper().startAddingDocuments("2");
mDatabase.putNewDocument(
- 0,
- "1",
+ 0, "2", OPERATIONS_SUPPORTED,
createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024));
- mDatabase.getMapper().stopAddingDocuments("1");
+ mDatabase.getMapper().stopAddingDocuments("2");
{
final Cursor cursor =
- mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "1");
+ mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2");
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals("3", cursor.getString(0));
+ assertEquals("4", cursor.getString(0));
cursor.close();
}
}
- public void testGetDocumentIdForDevice() {
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(
- new MtpDeviceRecord(100, "Device", true, new MtpRoot[0], null, null));
- mDatabase.getMapper().stopAddingDocuments(null);
- assertEquals("1", mDatabase.getDocumentIdForDevice(100));
+ public void testGetDocumentIdForDevice() throws Exception {
+ addTestDevice();
+ assertEquals("1", mDatabase.getDocumentIdForDevice(0));
}
- public void testGetClosedDevice() {
+ public void testGetClosedDevice() throws Exception {
mDatabase.getMapper().startAddingDocuments(null);
mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
- 0, "Device", /* opened is */ false , new MtpRoot[0], null, null));
+ 0, "Device", null /* deviceKey */, /* opened is */ false, new MtpRoot[0], null,
+ null));
mDatabase.getMapper().stopAddingDocuments(null);
final String[] columns = new String [] {
@@ -919,4 +962,72 @@ public class MtpDatabaseTest extends AndroidTestCase {
assertTrue(cursor.isNull(2));
}
}
+
+ public void testMappingWithoutKey() throws FileNotFoundException {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
+ null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
+ null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ try (final Cursor cursor =
+ mDatabase.queryRoots(resources, strings(DocumentsContract.Root.COLUMN_ROOT_ID))) {
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(1, cursor.getLong(0));
+ }
+ }
+
+ public void testMappingFailsWithoutKey() throws FileNotFoundException {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
+ null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ // MTP identifier is cleared here. Mapping no longer works without device key.
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null,
+ null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ try (final Cursor cursor =
+ mDatabase.queryRoots(resources, strings(DocumentsContract.Root.COLUMN_ROOT_ID))) {
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(2, cursor.getLong(0));
+ }
+ }
+
+ public void testUpdateDocumentWithoutChange() throws FileNotFoundException {
+ mDatabase.getMapper().startAddingDocuments(null);
+ assertTrue(mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
+ null)));
+ assertFalse(mDatabase.getMapper().stopAddingDocuments(null));
+
+ mDatabase.getMapper().startAddingDocuments(null);
+ assertFalse(mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
+ null)));
+ assertFalse(mDatabase.getMapper().stopAddingDocuments(null));
+ }
+
+ private void addTestDevice() throws FileNotFoundException {
+ TestUtil.addTestDevice(mDatabase);
+ }
+
+ private void addTestStorage(String parentId) throws FileNotFoundException {
+ TestUtil.addTestStorage(mDatabase, parentId);
+ }
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 5b0f55703a2b..3dfa4ade6eb5 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -22,6 +22,7 @@ import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
+import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.system.Os;
import android.system.OsConstants;
@@ -29,12 +30,15 @@ import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
+import com.android.mtp.exceptions.BusyDeviceException;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeoutException;
import static com.android.mtp.MtpDatabase.strings;
+import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED;
@MediumTest
public class MtpDocumentsProviderTest extends AndroidTestCase {
@@ -63,6 +67,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
mMtpManager.addValidDevice(new MtpDeviceRecord(
0,
"Device A",
+ null /* deviceKey */,
false /* unopened */,
new MtpRoot[] {
new MtpRoot(
@@ -73,7 +78,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
2048 /* total space */,
"" /* no volume identifier */)
},
- null,
+ OPERATIONS_SUPPORTED,
null));
mProvider.resumeRootScanner();
@@ -94,12 +99,13 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
} catch (Throwable error) {
assertTrue(error instanceof IOException);
}
- assertEquals(0, mProvider.getOpenedDeviceIds().length);
+ assertEquals(0, mProvider.getOpenedDeviceRecordsCache().length);
// Check if the following notification is the first one or not.
mMtpManager.addValidDevice(new MtpDeviceRecord(
0,
"Device A",
+ null /* deviceKey */,
false /* unopened */,
new MtpRoot[] {
new MtpRoot(
@@ -110,7 +116,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
2048 /* total space */,
"" /* no volume identifier */)
},
- null,
+ OPERATIONS_SUPPORTED,
null));
mProvider.resumeRootScanner();
mResolver.waitForNotification(ROOTS_URI, 1);
@@ -123,6 +129,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
mMtpManager.addValidDevice(new MtpDeviceRecord(
0,
"Device A",
+ null /* deviceKey */,
false /* unopened */,
new MtpRoot[] {
new MtpRoot(
@@ -133,7 +140,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
2048 /* total space */,
"" /* no volume identifier */)
},
- null,
+ OPERATIONS_SUPPORTED,
null));
mMtpManager.setObjectHandles(0, 1, -1, new int[0]);
mProvider.resumeRootScanner();
@@ -149,16 +156,16 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
assertEquals(1, cursor.getLong(1));
}
{
- final int [] openedDevice = mProvider.getOpenedDeviceIds();
+ final MtpDeviceRecord[] openedDevice = mProvider.getOpenedDeviceRecordsCache();
assertEquals(0, openedDevice.length);
}
// Device is opened automatically when querying its children.
try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {}
{
- final int [] openedDevice = mProvider.getOpenedDeviceIds();
+ final MtpDeviceRecord[] openedDevice = mProvider.getOpenedDeviceRecordsCache();
assertEquals(1, openedDevice.length);
- assertEquals(0, openedDevice[0]);
+ assertEquals(0, openedDevice[0].deviceId);
}
}
@@ -167,6 +174,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
mMtpManager.addValidDevice(new MtpDeviceRecord(
0,
"Device A",
+ "Device key A",
false /* unopened */,
new MtpRoot[] {
new MtpRoot(
@@ -177,11 +185,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
2048 /* total space */,
"" /* no volume identifier */)
},
- null,
+ OPERATIONS_SUPPORTED,
null));
mMtpManager.addValidDevice(new MtpDeviceRecord(
1,
"Device B",
+ "Device key B",
false /* unopened */,
new MtpRoot[] {
new MtpRoot(
@@ -192,7 +201,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
4096 /* total space */,
"Identifier B" /* no volume identifier */)
},
- null,
+ new int[0] /* No operations supported */,
null));
{
@@ -217,7 +226,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
cursor.moveToNext();
cursor.moveToNext();
assertEquals("2", cursor.getString(0));
- assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+ assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device B Storage B", cursor.getString(3));
assertEquals("2", cursor.getString(4));
@@ -228,10 +237,17 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
public void testQueryRoots_error() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
mMtpManager.addValidDevice(new MtpDeviceRecord(
- 0, "Device A", false /* unopened */, new MtpRoot[0], null, null));
+ 0,
+ "Device A",
+ "Device key A",
+ false /* unopened */,
+ new MtpRoot[0],
+ OPERATIONS_SUPPORTED,
+ null));
mMtpManager.addValidDevice(new MtpDeviceRecord(
1,
"Device B",
+ "Device key B",
false /* unopened */,
new MtpRoot[] {
new MtpRoot(
@@ -242,7 +258,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
4096 /* total space */,
"Identifier B" /* no volume identifier */)
},
- null,
+ OPERATIONS_SUPPORTED,
null));
{
mProvider.openDevice(0);
@@ -396,7 +412,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
assertEquals("image/jpeg", cursor.getString(1));
assertEquals("image.jpg", cursor.getString(2));
assertEquals(0, cursor.getLong(3));
- assertEquals(DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL, cursor.getInt(4));
+ assertEquals(Document.FLAG_SUPPORTS_THUMBNAIL, cursor.getInt(4));
assertEquals(1024 * 1024 * 5, cursor.getInt(5));
cursor.close();
@@ -526,6 +542,181 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
}
+ public void testBusyDevice() throws Exception {
+ mMtpManager = new TestMtpManager(getContext()) {
+ @Override
+ MtpDeviceRecord openDevice(int deviceId) throws IOException {
+ throw new BusyDeviceException();
+ }
+ };
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0, "Device A", null /* deviceKey */, false /* unopened */, new MtpRoot[0],
+ OPERATIONS_SUPPORTED, null));
+
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+
+ try (final Cursor cursor = mProvider.queryRoots(null)) {
+ assertEquals(1, cursor.getCount());
+ }
+
+ try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+ assertEquals(0, cursor.getCount());
+ assertEquals(
+ "error_busy_device",
+ cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
+ }
+ }
+
+ public void testLockedDevice() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0, "Device A", null, false /* unopened */, new MtpRoot[0], OPERATIONS_SUPPORTED,
+ null));
+
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+
+ try (final Cursor cursor = mProvider.queryRoots(null)) {
+ assertEquals(1, cursor.getCount());
+ }
+
+ try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {
+ assertEquals(0, cursor.getCount());
+ assertEquals(
+ "error_locked_device",
+ cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR));
+ }
+ }
+
+ public void testMappingDisconnectedDocuments() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0,
+ "Device A",
+ "device key",
+ true /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 0 /* deviceId */,
+ 1 /* storageId */,
+ "Storage A" /* volume description */,
+ 1024 /* free space */,
+ 2048 /* total space */,
+ "" /* no volume identifier */)
+ },
+ null,
+ null));
+
+ final String[] names = strings("Directory A", "Directory B", "Directory C");
+ final int objectHandleOffset = 100;
+ for (int i = 0; i < names.length; i++) {
+ final int parentHandle = i == 0 ?
+ MtpManager.OBJECT_HANDLE_ROOT_CHILDREN : objectHandleOffset + i - 1;
+ final int objectHandle = i + objectHandleOffset;
+ mMtpManager.setObjectHandles(0, 1, parentHandle, new int[] { objectHandle });
+ mMtpManager.setObjectInfo(
+ 0,
+ new MtpObjectInfo.Builder()
+ .setName(names[i])
+ .setObjectHandle(objectHandle)
+ .setFormat(MtpConstants.FORMAT_ASSOCIATION)
+ .setStorageId(1)
+ .build());
+ }
+
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+
+ final int documentIdOffset = 2;
+ for (int i = 0; i < names.length; i++) {
+ try (final Cursor cursor = mProvider.queryChildDocuments(
+ String.valueOf(documentIdOffset + i),
+ strings(Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME),
+ null)) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(String.valueOf(documentIdOffset + i + 1), cursor.getString(0));
+ assertEquals(names[i], cursor.getString(1));
+ }
+ }
+
+ mProvider.closeDevice(0);
+ mResolver.waitForNotification(ROOTS_URI, 2);
+
+ mProvider.openDevice(0);
+ mResolver.waitForNotification(ROOTS_URI, 3);
+
+ for (int i = 0; i < names.length; i++) {
+ mResolver.waitForNotification(DocumentsContract.buildChildDocumentsUri(
+ MtpDocumentsProvider.AUTHORITY,
+ String.valueOf(documentIdOffset + i)), 1);
+ try (final Cursor cursor = mProvider.queryChildDocuments(
+ String.valueOf(documentIdOffset + i),
+ strings(Document.COLUMN_DOCUMENT_ID),
+ null)) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(String.valueOf(documentIdOffset + i + 1), cursor.getString(0));
+ }
+ }
+ }
+
+ public void testCreateDocument_noWritingSupport() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0, "Device A", null /* deviceKey */, false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 0 /* deviceId */,
+ 1 /* storageId */,
+ "Storage A" /* volume description */,
+ 1024 /* free space */,
+ 2048 /* total space */,
+ "" /* no volume identifier */)
+ },
+ new int[0] /* no operations supported */, null));
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+ try {
+ mProvider.createDocument("1", "text/palin", "note.txt");
+ fail();
+ } catch (UnsupportedOperationException exception) {}
+ }
+
+ public void testOpenDocument_noWritingSupport() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0, "Device A", null /* deviceKey */, false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 0 /* deviceId */,
+ 1 /* storageId */,
+ "Storage A" /* volume description */,
+ 1024 /* free space */,
+ 2048 /* total space */,
+ "" /* no volume identifier */)
+ },
+ new int[0] /* no operations supported */, null));
+ mMtpManager.setObjectHandles(
+ 0, 1, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, new int[] { 100 });
+ mMtpManager.setObjectInfo(
+ 0, new MtpObjectInfo.Builder().setObjectHandle(100).setName("note.txt").build());
+ mProvider.resumeRootScanner();
+ mResolver.waitForNotification(ROOTS_URI, 1);
+ try (final Cursor cursor = mProvider.queryChildDocuments(
+ "1", strings(Document.COLUMN_DOCUMENT_ID), null)) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("3", cursor.getString(0));
+ }
+ try {
+ mProvider.openDocument("3", "w", null);
+ fail();
+ } catch (UnsupportedOperationException exception) {}
+ }
+
private void setupProvider(int flag) {
mDatabase = new MtpDatabase(getContext(), flag);
mProvider = new MtpDocumentsProvider();
@@ -555,7 +746,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
throws InterruptedException, TimeoutException, IOException {
final int changeCount = mResolver.getChangeCount(ROOTS_URI);
mMtpManager.addValidDevice(
- new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots, null, null));
+ new MtpDeviceRecord(deviceId, "Device", null /* deviceKey */, false /* unopened */,
+ roots, OPERATIONS_SUPPORTED, null));
mProvider.openDevice(deviceId);
mResolver.waitForNotification(ROOTS_URI, changeCount + 1);
return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID)));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index 9ebe4d1e469e..2e172b1fadf5 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -94,6 +94,13 @@ public class MtpManagerTest extends InstrumentationTestCase {
getInstrumentation().show(Arrays.toString(records[0].eventsSupported));
}
+ public void testDeviceKey() {
+ final MtpDeviceRecord[] records = mManager.getDevices();
+ assertEquals(1, records.length);
+ assertNotNull(records[0].deviceKey);
+ getInstrumentation().show("deviceKey: " + records[0].deviceKey);
+ }
+
public void testEventObjectAdded() throws Exception {
while (true) {
getInstrumentation().show("Please take a photo by using connected MTP device.");
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index 4dfc785a54ec..919ac39c9d44 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,8 +16,10 @@
package com.android.mtp;
+import android.database.Cursor;
import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
@@ -33,12 +35,14 @@ public class PipeManagerTest extends AndroidTestCase {
private TestMtpManager mtpManager;
private ExecutorService mExecutor;
private PipeManager mPipeManager;
+ private MtpDatabase mDatabase;
@Override
public void setUp() {
mtpManager = new TestMtpManager(getContext());
mExecutor = Executors.newSingleThreadExecutor();
- mPipeManager = new PipeManager(mExecutor);
+ mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mPipeManager = new PipeManager(mDatabase, mExecutor);
}
public void testReadDocument_basic() throws Exception {
@@ -57,25 +61,35 @@ public class PipeManagerTest extends AndroidTestCase {
}
public void testWriteDocument_basic() throws Exception {
+ TestUtil.addTestDevice(mDatabase);
+ TestUtil.addTestStorage(mDatabase, "1");
+
+ final MtpObjectInfo info =
+ new MtpObjectInfo.Builder().setObjectHandle(1).setName("note.txt").build();
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(
+ 0, "2", TestUtil.OPERATIONS_SUPPORTED,
+ new MtpObjectInfo[] { info });
+ mDatabase.getMapper().stopAddingDocuments("2");
// Create a placeholder file which should be replaced by a real file later.
- mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
- .setObjectHandle(1)
- .build());
+ mtpManager.setObjectInfo(0, info);
// Upload testing bytes.
final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
getContext(),
mtpManager,
- new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
+ new Identifier(0, 0, 1, "2", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT),
+ TestUtil.OPERATIONS_SUPPORTED);
final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
new ParcelFileDescriptor.AutoCloseOutputStream(descriptor);
outputStream.write(HELLO_BYTES, 0, HELLO_BYTES.length);
outputStream.close();
- mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ mExecutor.shutdown();
+ assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
// Check if the placeholder file is removed.
try {
- final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
+ mtpManager.getObjectInfo(0, 1);
fail(); // The placeholder file has not been deleted.
} catch (IOException e) {
// Expected error, as the file is gone.
@@ -86,6 +100,14 @@ public class PipeManagerTest extends AndroidTestCase {
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
assertTrue(targetDocument != null);
+ // Confirm the object handle is updated.
+ try (final Cursor cursor = mDatabase.queryDocument(
+ "2", new String[] { MtpDatabaseConstants.COLUMN_OBJECT_HANDLE })) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(TestMtpManager.CREATED_DOCUMENT_HANDLE, cursor.getInt(0));
+ }
+
// Verify uploaded bytes.
final byte[] uploadedBytes = mtpManager.getImportFileBytes(
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
@@ -112,7 +134,8 @@ public class PipeManagerTest extends AndroidTestCase {
private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes)
throws IOException, InterruptedException {
- mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ mExecutor.shutdown();
+ assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
try (final ParcelFileDescriptor.AutoCloseInputStream stream =
new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
byte[] results = new byte[100];
@@ -125,7 +148,8 @@ public class PipeManagerTest extends AndroidTestCase {
private void assertDescriptorError(ParcelFileDescriptor descriptor)
throws InterruptedException {
- mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ mExecutor.shutdown();
+ assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
try {
descriptor.checkError();
fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 1aaeb6092fa5..5e0ee1e3e1fa 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -22,6 +22,7 @@ import android.os.ParcelFileDescriptor;
import android.util.SparseArray;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -76,32 +77,36 @@ public class TestMtpManager extends MtpManager {
result[i] = device;
} else {
result[i] = new MtpDeviceRecord(
- device.deviceId, device.name, device.opened, new MtpRoot[0], null, null);
+ device.deviceId, device.name, device.deviceKey, device.opened,
+ new MtpRoot[0], null, null);
}
}
return result;
}
@Override
- void openDevice(int deviceId) throws IOException {
+ MtpDeviceRecord openDevice(int deviceId) throws IOException {
final MtpDeviceRecord device = mDevices.get(deviceId);
- if (device == null || device.opened) {
+ if (device == null) {
throw new IOException();
}
- mDevices.put(
- deviceId,
- new MtpDeviceRecord(device.deviceId, device.name, true, device.roots, null, null));
+ final MtpDeviceRecord record = new MtpDeviceRecord(
+ device.deviceId, device.name, device.deviceKey, true, device.roots,
+ device.operationsSupported, device.eventsSupported);
+ mDevices.put(deviceId, record);
+ return record;
}
@Override
void closeDevice(int deviceId) throws IOException {
final MtpDeviceRecord device = mDevices.get(deviceId);
- if (device == null || !device.opened) {
+ if (device == null) {
throw new IOException();
}
mDevices.put(
deviceId,
- new MtpDeviceRecord(device.deviceId, device.name, false, device.roots, null, null));
+ new MtpDeviceRecord(device.deviceId, device.name, device.deviceKey, false,
+ device.roots, null, null));
}
@Override
@@ -145,7 +150,9 @@ public class TestMtpManager extends MtpManager {
if (mObjectInfos.containsKey(key)) {
throw new IOException();
}
- mObjectInfos.put(key, objectInfo);
+ final MtpObjectInfo newInfo = new MtpObjectInfo.Builder(objectInfo).
+ setObjectHandle(CREATED_DOCUMENT_HANDLE).build();
+ mObjectInfos.put(key, newInfo);
if (objectInfo.getFormat() != 0x3001) {
try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
new ParcelFileDescriptor.AutoCloseInputStream(source)) {
@@ -192,19 +199,6 @@ public class TestMtpManager extends MtpManager {
}
@Override
- int[] getOpenedDeviceIds() {
- final int[] result = new int[mDevices.size()];
- int count = 0;
- for (int i = 0; i < mDevices.size(); i++) {
- final MtpDeviceRecord device = mDevices.valueAt(i);
- if (device.opened) {
- result[count++] = device.deviceId;
- }
- }
- return Arrays.copyOf(result, count);
- }
-
- @Override
byte[] getObject(int deviceId, int objectHandle, int expectedSize) throws IOException {
return mImportFileBytes.get(pack(deviceId, objectHandle));
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
index b23038b6c3f6..8676b5a0d315 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
@@ -24,6 +24,10 @@ class TestResources extends MockResources {
switch (id) {
case R.string.root_name:
return "%1$s %2$s";
+ case R.string.error_busy_device:
+ return "error_busy_device";
+ case R.string.error_locked_device:
+ return "error_locked_device";
}
throw new NotFoundException();
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
index ffcc0882e019..5ceab01328b0 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -19,20 +19,27 @@ package com.android.mtp;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
import android.os.SystemClock;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Objects;
-import junit.framework.Assert;
-
/**
* Static utility methods for testing.
*/
final class TestUtil {
private TestUtil() {}
+ static final int[] OPERATIONS_SUPPORTED = new int[] {
+ MtpConstants.OPERATION_GET_PARTIAL_OBJECT,
+ MtpConstants.OPERATION_SEND_OBJECT,
+ MtpConstants.OPERATION_SEND_OBJECT_INFO,
+ MtpConstants.OPERATION_DELETE_OBJECT,
+ };
+
/**
* Requests permission for a MTP device and returns the first MTP device that has at least one
* storage.
@@ -57,6 +64,22 @@ final class TestUtil {
}
}
+ static void addTestDevice(MtpDatabase database) throws FileNotFoundException {
+ database.getMapper().startAddingDocuments(null);
+ database.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0],
+ OPERATIONS_SUPPORTED, null));
+ database.getMapper().stopAddingDocuments(null);
+ }
+
+ static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException {
+ database.getMapper().startAddingDocuments(parentId);
+ database.getMapper().putStorageDocuments(parentId, OPERATIONS_SUPPORTED, new MtpRoot[] {
+ new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
+ });
+ database.getMapper().stopAddingDocuments(parentId);
+ }
+
private static UsbDevice findMtpDevice(
UsbManager usbManager,
MtpManager manager) throws IOException {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 2ae3ec6268a7..7a6aad6a96f5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -16,6 +16,7 @@
package com.android.printspooler.model;
+import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
@@ -57,6 +58,8 @@ public final class RemotePrintDocument {
private static final boolean DEBUG = false;
+ private static final long FORCE_CANCEL_TIMEOUT = 1000; // ms
+
private static final int STATE_INITIAL = 0;
private static final int STATE_STARTED = 1;
private static final int STATE_UPDATING = 2;
@@ -212,7 +215,7 @@ public final class RemotePrintDocument {
// cancellation and start over.
if (mCurrentCommand != null && (mCurrentCommand.isRunning()
|| mCurrentCommand.isPending())) {
- mCurrentCommand.cancel();
+ mCurrentCommand.cancel(false);
}
// Schedule a layout command.
@@ -233,7 +236,7 @@ public final class RemotePrintDocument {
// Cancel the current write as a new one is to be scheduled.
if (mCurrentCommand instanceof WriteCommand
&& (mCurrentCommand.isPending() || mCurrentCommand.isRunning())) {
- mCurrentCommand.cancel();
+ mCurrentCommand.cancel(false);
}
// Schedule a write command.
@@ -277,9 +280,9 @@ public final class RemotePrintDocument {
}
}
- public void cancel() {
+ public void cancel(boolean force) {
if (DEBUG) {
- Log.i(LOG_TAG, "[CALLED] cancel()");
+ Log.i(LOG_TAG, "[CALLED] cancel(" + force + ")");
}
mNextCommand = null;
@@ -290,7 +293,7 @@ public final class RemotePrintDocument {
mState = STATE_CANCELING;
- mCurrentCommand.cancel();
+ mCurrentCommand.cancel(force);
}
public void destroy() {
@@ -441,8 +444,9 @@ public final class RemotePrintDocument {
if (mCurrentCommand != null) {
if (mCurrentCommand.isPending()) {
mCurrentCommand.run();
+
+ mState = STATE_UPDATING;
}
- mState = STATE_UPDATING;
} else {
mState = STATE_UPDATED;
}
@@ -535,14 +539,17 @@ public final class RemotePrintDocument {
protected final CommandDoneCallback mDoneCallback;
+ private final Handler mHandler;
+
protected ICancellationSignal mCancellation;
private CharSequence mError;
private int mState = STATE_PENDING;
- public AsyncCommand(IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
+ public AsyncCommand(Looper looper, IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
CommandDoneCallback doneCallback) {
+ mHandler = new AsyncCommandHandler(looper);
mAdapter = adapter;
mDocument = document;
mDoneCallback = doneCallback;
@@ -556,7 +563,29 @@ public final class RemotePrintDocument {
return mState == STATE_CANCELED;
}
- public final void cancel() {
+ /**
+ * If a force cancel is pending, remove it. This is usually called when a command returns
+ * and thereby does not need to be canceled anymore.
+ */
+ protected void removeForceCancel() {
+ if (DEBUG) {
+ if (mHandler.hasMessages(AsyncCommandHandler.MSG_FORCE_CANCEL)) {
+ Log.i(LOG_TAG, "[FORCE CANCEL] Removed");
+ }
+ }
+
+ mHandler.removeMessages(AsyncCommandHandler.MSG_FORCE_CANCEL);
+ }
+
+ /**
+ * Cancel the current command.
+ *
+ * @param force If set, does not wait for the {@link PrintDocumentAdapter} to cancel. This
+ * should only be used if this is the last command send to the as otherwise the
+ * {@link PrintDocumentAdapter adapter} might get commands while it is still
+ * running the old one.
+ */
+ public final void cancel(boolean force) {
if (isRunning()) {
canceling();
if (mCancellation != null) {
@@ -566,14 +595,25 @@ public final class RemotePrintDocument {
Log.w(LOG_TAG, "Error while canceling", re);
}
}
- } else if (isCanceling()) {
- // Nothing to do
- } else {
- canceled();
+ }
+
+ if (isCanceling()) {
+ if (force) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[FORCE CANCEL] queued");
+ }
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(AsyncCommandHandler.MSG_FORCE_CANCEL),
+ FORCE_CANCEL_TIMEOUT);
+ }
- // Done.
- mDoneCallback.onDone();
+ return;
}
+
+ canceled();
+
+ // Done.
+ mDoneCallback.onDone();
}
protected final void canceling() {
@@ -617,7 +657,7 @@ public final class RemotePrintDocument {
}
protected final void failed(CharSequence error) {
- if (mState != STATE_RUNNING) {
+ if (mState != STATE_RUNNING && mState != STATE_CANCELING) {
throw new IllegalStateException("Not running.");
}
mState = STATE_FAILED;
@@ -632,6 +672,37 @@ public final class RemotePrintDocument {
public CharSequence getError() {
return mError;
}
+
+ /**
+ * Handler for the async command.
+ */
+ private class AsyncCommandHandler extends Handler {
+ /** Message indicated the desire for to force cancel a command */
+ final static int MSG_FORCE_CANCEL = 0;
+
+ AsyncCommandHandler(@NonNull Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_FORCE_CANCEL:
+ if (isCanceling()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[FORCE CANCEL] executed");
+ }
+ failed("Command did not respond to cancellation in "
+ + FORCE_CANCEL_TIMEOUT + " ms");
+
+ mDoneCallback.onDone();
+ }
+ break;
+ default:
+ // not reached;
+ }
+ }
+ }
}
private static final class LayoutCommand extends AsyncCommand {
@@ -646,7 +717,7 @@ public final class RemotePrintDocument {
public LayoutCommand(Looper looper, IPrintDocumentAdapter adapter,
RemotePrintDocumentInfo document, PrintAttributes oldAttributes,
PrintAttributes newAttributes, boolean preview, CommandDoneCallback callback) {
- super(adapter, document, callback);
+ super(looper, adapter, document, callback);
mHandler = new LayoutHandler(looper);
mRemoteResultCallback = new LayoutResultCallback(mHandler);
mOldAttributes.copyFrom(oldAttributes);
@@ -795,6 +866,21 @@ public final class RemotePrintDocument {
@Override
public void handleMessage(Message message) {
+ // The command might have been force canceled, see
+ // AsyncCommand.AsyncCommandHandler#handleMessage
+ if (isFailed()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] on canceled layout command");
+ }
+
+ return;
+ } else {
+ if (message.what != MSG_ON_LAYOUT_STARTED) {
+ // No need to force cancel anymore if layout finished
+ removeForceCancel();
+ }
+ }
+
switch (message.what) {
case MSG_ON_LAYOUT_STARTED: {
ICancellationSignal cancellation = (ICancellationSignal) message.obj;
@@ -882,7 +968,7 @@ public final class RemotePrintDocument {
public WriteCommand(Context context, Looper looper, IPrintDocumentAdapter adapter,
RemotePrintDocumentInfo document, int pageCount, PageRange[] pages,
MutexFileProvider fileProvider, CommandDoneCallback callback) {
- super(adapter, document, callback);
+ super(looper, adapter, document, callback);
mContext = context;
mHandler = new WriteHandler(looper);
mRemoteResultCallback = new WriteResultCallback(mHandler);
@@ -1052,6 +1138,21 @@ public final class RemotePrintDocument {
@Override
public void handleMessage(Message message) {
+ // The command might have been force canceled, see
+ // AsyncCommand.AsyncCommandHandler#handleMessage
+ if (isFailed()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] on canceled write command");
+ }
+
+ return;
+ } else {
+ if (message.what != MSG_ON_WRITE_STARTED) {
+ // No need to force cancel anymore if write finished
+ removeForceCancel();
+ }
+ }
+
switch (message.what) {
case MSG_ON_WRITE_STARTED: {
ICancellationSignal cancellation = (ICancellationSignal) message.obj;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 08cd0b6434d4..64f5cc62201e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -320,8 +320,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
return;
}
- mPrintedDocument.cancel();
setState(STATE_PRINT_CANCELED);
+ mPrintedDocument.cancel(true);
doFinish();
}
}, PrintActivity.this);
@@ -1013,7 +1013,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
private void requestCreatePdfFileOrFinish() {
- mPrintedDocument.cancel();
+ mPrintedDocument.cancel(false);
if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
startCreateDocumentActivity();
@@ -1130,7 +1130,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
private void cancelPrint() {
setState(STATE_PRINT_CANCELED);
updateOptionsUi();
- mPrintedDocument.cancel();
+ mPrintedDocument.cancel(true);
doFinish();
}
@@ -1889,7 +1889,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
public void onPrinterUnavailable(PrinterInfo printer) {
if (mCurrentPrinter.getId().equals(printer.getId())) {
setState(STATE_PRINTER_UNAVAILABLE);
- mPrintedDocument.cancel();
+ mPrintedDocument.cancel(false);
ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
PrintErrorFragment.ACTION_NONE);
updateOptionsUi();
diff --git a/packages/SettingsLib/res/layout/usage_bottom_label.xml b/packages/SettingsLib/res/layout/usage_bottom_label.xml
new file mode 100644
index 000000000000..6c168806338e
--- /dev/null
+++ b/packages/SettingsLib/res/layout/usage_bottom_label.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/packages/SettingsLib/res/layout/usage_side_label.xml b/packages/SettingsLib/res/layout/usage_side_label.xml
new file mode 100644
index 000000000000..6c168806338e
--- /dev/null
+++ b/packages/SettingsLib/res/layout/usage_side_label.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/packages/SettingsLib/res/layout/usage_view.xml b/packages/SettingsLib/res/layout/usage_view.xml
new file mode 100644
index 000000000000..28981f87978f
--- /dev/null
+++ b/packages/SettingsLib/res/layout/usage_view.xml
@@ -0,0 +1,87 @@
+<!--
+ 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="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/graph_label_group"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/usage_graph_area_height"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@+id/label_group"
+ android:layout_width="@dimen/usage_graph_labels_width"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include android:id="@+id/label_top"
+ layout="@layout/usage_side_label" />
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <include android:id="@+id/label_middle"
+ layout="@layout/usage_side_label" />
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <include android:id="@+id/label_bottom"
+ layout="@layout/usage_side_label" />
+
+ </LinearLayout>
+
+ <com.android.settingslib.graph.UsageGraph
+ android:id="@+id/usage_graph"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_marginTop="@dimen/usage_graph_margin_top_bottom"
+ android:layout_marginBottom="@dimen/usage_graph_margin_top_bottom" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/bottom_label_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/usage_graph_labels_width"
+ android:orientation="horizontal">
+
+ <include android:id="@+id/label_start"
+ layout="@layout/usage_side_label" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+
+ <include android:id="@+id/label_end"
+ layout="@layout/usage_side_label" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 49d9f1715eca..94e376c87de1 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Teks-na-spraak-uitset"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Spraaktempo"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Spoed waarteen die teks gepraat word"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Toonhoogte"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Beïnvloed die klank van die gesintetiseerde spraak"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Taal"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Gebruik stelseltaal"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Taal nie gekies nie"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Laat altyd Wi-Fi-swerfskanderings toe"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gebruik vorige DHCP-kliënt"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Hierdie instellings is bedoel net vir ontwikkelinggebruik. Dit kan jou toestel en die programme daarop breek of vreemde dinge laat doen."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifieer programme oor USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontroleer programme wat via ADB/ADT geïnstalleer is vir skadelike gedrag."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiveer die Bluetooth-kenmerk vir absolute volume indien daar volumeprobleme met afgeleë toestelle is, soos onaanvaarbare harde klank of geen beheer nie."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Plaaslike terminaal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktiveer terminaalprogram wat plaaslike skermtoegang bied"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrolering"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Flits skerm as programme lang handelinge doen op die hoofdraad"</string>
<string name="pointer_location" msgid="6084434787496938001">"Wyserligging"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skermlaag wys huidige raakdata"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Wys tikke"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Wys visuele terugvoer vir tikke"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Wys oppervlakopdaterings"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Flits vensteroppervlaktes in geheel wanneer dit opdateer"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Wys GPU-aansigopdaterings"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Programme verplig ekstern toegelaat"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Laat enige program na ekstern geskryf word, ongeag manifeswaardes"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Verplig verstelbare groottes vir aktiwiteite"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Maak grootte van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Maak die groottes van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye-Windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye-Windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktiveer steun vir eksperimentele vormvrye-Windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Werkskerm-rugsteunwagwoord"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tik om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuwe rugsteunwagwoord ingestel"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nuwe wagwoord en bevestiging stem nie ooreen nie"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Rugsteunwagwoord kon nie ingestel word nie"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Kleure vir digitale inhoud geoptimeer"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Onaktiewe programme"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Onaktief. Tik om te wissel."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktief. Tik om te wissel."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Lopende dienste"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Sien en beheer dienste wat tans loop"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nagmodus"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Gedeaktiveer"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Altyd aan"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Outomaties"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktiveer multiproses-WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Laat loop WebView-leweraars in \'n geïsoleerde proses."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Die gekose WebView-toepassing is gedeaktiveer, maar moet geaktiveer wees om gebruik te word. Wil jy dit aktiveer?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Die gekose WebView-toepassing is ongeldig want die lys toepassingskeuses het verouderd geraak. Die lys moet nou opgedateer word."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Skakel om na lêerenkripsie"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Skakel om …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Lêerenkripsie is reeds uitgevoer"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kleurregstelling"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierdie kenmerk is eksperimenteel en kan werkverrigting beïnvloed."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ongeveer <xliff:g id="TIME">%1$s</xliff:g> oor"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – sowat <xliff:g id="TIME">%2$s</xliff:g> oor"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Laai nie"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Laai nie"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Vol"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Gedeaktiveer deur administrateur"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Beheer deur administrateur"</string>
+ <string name="home" msgid="8263346537524314127">"Tuis"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> gelede"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> oor"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index ab3d30445196..c605d2deae30 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"የፅሁፍ- ወደ- ንግግር ውፅዓት"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">" የንግግር ደረጃ"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"የተነገረበትን ፅሁፍ አፍጥን"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ቅላፄ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"በሲንተሲስ በተሠራው ድምፅ ላይ ተፅዕኖ ያሳድራል"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ቋንቋ"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"የስርዓት ቋንቋ ተጠቀም"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ቋንቋ አልተመረጠም"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ሁልጊዜ የWi‑Fi ማንቀሳቀስ ቅኝቶችን ይፍቀዱ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"የቆየ የDHCP ደንበኛ ይጠቀሙ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"የተንቀስቃሽ ስልክ ውሂብ ሁልጊዜ ንቁ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ፍጹማዊ ድምፅን አሰናክል"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"እነዚህ ቅንብሮች የታሰቡት ለግንባታ አጠቃቀም ብቻ ናቸው። መሳሪያህን እና በሱ ላይ ያሉትን መተግበሪያዎች እንዲበለሹ ወይም በትክክል እንዳይሰሩ ሊያደርጉ ይችላሉ።"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"መተግበሪያዎች በUSB በኩል ያረጋግጡ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"በADB/ADT በኩል የተጫኑ መተግበሪያዎች ጎጂ ባህሪ ካላቸው ያረጋግጡ።"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"እንደ ተቀባይነት በሌለው ደረጃ ድምፁ ከፍ ማለት ወይም መቆጣጠር አለመቻል ያሉ ከሩቅ መሣሪያዎች ጋር የድምፅ ችግር በሚኖርበት ጊዜ የብሉቱዝ ፍጹማዊ ድምፅን ባሕሪ ያሰናክላል።"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"አካባቢያዊ ተርሚናል"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"የአካባቢያዊ ሼል መዳረሻ የሚያቀርብ የተርሚናል መተግበሪያ አንቃ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"የHDCP ምልከታ"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"በውጫዊ ላይ ሃይል ይፈቀዳል"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"አንጸባራቂ እሴቶች ግምት ውስጥ ሳይገቡ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻ ለመጻፍ ብቁ ያደርጋል።"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች ዳግም የሚመጣጠኑ እንዲሆኑ ያደርጋቸዋል።"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች መጠናቸው የሚቀየሩ እንዲሆኑ ያደርጋቸዋል።"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"የሙከራ ነጻ ቅርጽ መስኮቶች ድጋፍን ያነቃል።"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"የሙከራ ነጻ መልክ መስኮቶች ድጋፍን አንቃ"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"የዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃሉን ለመለወጥ ወይም ለማስወገድ ነካ ያድርጉ"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"ገቢር። ለመቀያየር ነካ ያድርጉ።"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"አሂድ አገልግሎቶች"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"የሌሊት ሁነታ"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"ተሰናክሏል"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ሁልጊዜ ይበራል"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ራስ-ሰር"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ባለብዙ-ሂደት WebViewን አንቃ"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"የWebView ምስል ሰሪዎችን በተገለለ ሂደት ውስጥ አሂድ።"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"የWebView ትግበራ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"የWebView ትግበራን ያዘጋጁ"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"የተመረጠው WebView ትግበራ ተሰናክሏል፣ እና ጥቅም ላይ እንዲውል መንቃት አለበት፣ ሊያነቁት ይፈልጋሉ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"የትግበራ ምርጫዎች ዝርዝር እድገት ስላላሳየ የተመረጠው የWebView ትግበራ አይሠራም። ዝርዝሩ አሁን መዘመን አለበት።"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ወደ ፋይል ምሥጠራ ቀይር"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ለውጥ…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ፋይል አስቀድሞ ተመስጥሯል"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"የቀለም ማስተካከያ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ይህ ባህሪ የሙከራ ነውና አፈጻጸም ላይ ተጽዕኖ ሊኖረው ይችላል።"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g> ገደማ ቀርቷል"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ገደማ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> እስከሚሞላ ድረስ"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ባትሪ እየሞላ አይደለም"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ኃይል እየሞላ አይደለም"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"በአስተዳዳሪ የተሰናከለ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"በአስተዳዳሪ ቁጥጥር የተደረገበት"</string>
+ <string name="home" msgid="8263346537524314127">"መነሻ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"ከ<xliff:g id="ID_1">%1$s</xliff:g> በፊት"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ቀርቷል"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 12d3323b4e11..975051a83189 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"إخراج تحويل النص إلى كلام"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"معدل سرعة الكلام"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"سرعة نطق الكلام"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"درجة الصوت"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"للتأثير في نبرة الكلام المُرَكَّب"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"اللغة"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"استخدام لغة النظام"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"اللغة غير محددة"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏السماح دائمًا بعمليات فحص Wi-Fi للتجوال"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"‏استخدام برنامج DHCP القديم"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"بيانات الجوّال نشطة دائمًا"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"تعطيل مستوى الصوت المطلق"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"هذه الإعدادات مخصصة لاستخدام التطوير فقط. قد يتسبب هذا في حدوث أعطال أو خلل في أداء الجهاز والتطبيقات المثبتة عليه."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏التحقق من التطبيقات عبر USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏التحقق من التطبيقات المثبتة عبر ADB/ADT لكشف السلوك الضار"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"لتعطيل ميزة مستوى الصوت المطلق للبلوتوث في حالة حدوث مشكلات متعلقة بمستوى الصوت مع الأجهزة البعيدة مثل مستوى صوت عالٍ بشكل غير مقبول أو نقص إمكانية التحكم في الصوت."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"تطبيق طرفي محلي"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"تمكين تطبيق طرفي يوفر إمكانية الدخول إلى واجهة النظام المحلية"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"‏التحقق من HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"وميض الشاشة عند إجراء التطبيقات عمليات طويلة في سلسلة المحادثات الرئيسية"</string>
<string name="pointer_location" msgid="6084434787496938001">"موقع المؤشر"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"عرض تراكب الشاشة لبيانات اللمس الحالية"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"عرض النقرات"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"عرض التعليقات المرئية للنقرات"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"عرض تحديثات السطح"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"وميض أسطح النوافذ بالكامل عندما يتم تحديثها"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"‏إظهار تحديثات عرض GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"فرض السماح للتطبيقات على الخارجي"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"تأهيل أي تطبيق بحيث تتم كتابته على سعة تخزين خارجية، بغض النظر عن قيم البيان"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"فرض إمكانية تغيير على الأنشطة"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"لتمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"تمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"تمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"كلمة مرور احتياطية للكمبيوتر"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"النسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"انقر لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها."</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"تم تعيين كلمة مرور احتياطية جديدة"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"كلمة المرور الجديدة وتأكيدها لا يتطابقان"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"أخفق تعيين كلمة مرور احتياطية"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"الألوان المحسَّنة للمحتوى الرقمي"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"التطبيقات غير النشطة"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"غير نشط، انقر للتبديل."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"نشط، انقر للتبديل."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"الخدمات قيد التشغيل"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"الوضع الليلي"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"معطَّل"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"التشغيل دائمًا"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"تلقائيًا"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"تمكين عرض ويب متعدد العمليات"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"تشغيل أجهزة عرض الويب في عملية منفصلة."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"‏تطبيق WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏تعيين تطبيق WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏إن تنفيذ ميزة WebView التي تم اختيارها معطَّل، ويجب تمكين هذه الميزة ليتسنى استخدامها، فهل تريد تمكينها؟"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"‏التنفيذ الذي تم اختياره لطريقة WebView غير صالح لأن قائمة خيارات التنفيذ أصبحت قديمة. يجب أن يتم تحديث القائمة الآن."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"التحويل إلى تشفير ملفات"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تحويل…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"تم استخدام تشفير ملفات من قبل"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"تصحيح الألوان"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"هذه الميزة تجريبية وقد تؤثر في الأداء."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"يتبقى <xliff:g id="TIME">%1$s</xliff:g> تقريبًا"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تبقى <xliff:g id="TIME">%2$s</xliff:g> تقريبًا"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى الاكتمال"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"تم التعطيل بواسطة المشرف"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"إعدادات يتحكم فيها المشرف"</string>
+ <string name="home" msgid="8263346537524314127">"الشاشة الرئيسية"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"يتبقى <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 6c6903ec9b54..3f78fa242253 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Mətndən-nitqə çıxışı"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Nitq diapazonu"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Mətnin səsləndirilmə sürəti"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitç"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Sintez olunmuş nitqin tonuna təsir edir"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Dil"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Sistem dili işlədin"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Dil seçilməyib"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi axtarışlarına həmişə icazə verin"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Köhnə DHCP klient istifadə edin"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu parametrlər yalnız inkişafetdirici istifadə üçün nəzərdə tutulub. Onlar cihaz və tətbiqlərinizin sınması və ya pis işləməsinə səbəb ola bilər."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB üzərindən tətbiqləri yoxlayın"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT vasitəsi ilə quraşdırılmış tətbiqləri zərərli davranış üzrə yoxlayın."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Uzaqdan idarə olunan cihazlarda dözülməz yüksək səs həcmi və ya nəzarət çatışmazlığı kimi səs problemləri olduqda Bluetooth mütləq səs həcmi xüsusiyyətini deaktiv edir."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Yerli terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Yerli örtük girişini təklif edən terminal tətbiqi aktiv edin"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP yoxlanılır"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tətbiqlərə xaricdən məcburi icazə"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bəyannamə dəyərlərindən aslı olmayaraq bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edir."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bəyannamə dəyərlərindən aslı olmayaraq, bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edin."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Freeform windows aktiv edin"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Sınaq üçün freeform windows aktiv edir"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Sınaq üçün freeform windows aktiv edilir."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü rezerv parolu"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Masaüstünün tam rezerv kopyalanması üçün parolu dəyişmək və ya silmək üçün basın"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivdir. Keçid etmək üçün basın."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"İşləyən xidmətlər"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Hazırda prosesdə olan xidmətləri görüntüləyin və onlara nəzarət edin"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Gecə rejimi"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Qeyri-aktiv"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Həmişə aktiv"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Çox prosesli WebView\'nu aktiv edin"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView rendererləri təcrid olunmuş prosesdə işlədin."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView icrası"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView icrasını ayarlayın"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Seçilmiş WebView icrası deaktiv edildi, istifadəsi üçün aktiv edilməlidir, aktivləşdirmək istəyirsiniz?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Seçilmiş WebView icrası yararsızdır cünki, icra seçimlərinin siyahısı köhnədir. Bu siyahı güncəllənməlidir."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Fayl şifrələnməsinə çevirin"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Çevirin..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl artıq şifrələnib"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rəng düzəlişi"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya eksperimentaldır və performansa təsir edə bilər."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Təxminən <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - təxminən <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> dolana qədər"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Doldurulmur"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Enerji doldurulmur"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Tam"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administrator tərəfindən deaktiv edildi"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Admin tərəfindən nəzarət olunur"</string>
+ <string name="home" msgid="8263346537524314127">"Əsas səhifə"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> əvvəl"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qalıb"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 669b92dba48d..a38542d93424 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Izlaz za pretvaranje teksta u govor"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina izgovaranja teksta"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Nivo"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utiče na ton sintetizovanog govora"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Koristi jezik sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije izabran"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvek dozvoli skeniranje Wi‑Fi-ja u romingu"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ova podešavanja su namenjena samo za programiranje. Mogu da izazovu prestanak funkcionisanja ili neočekivano ponašanje uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije preko USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Proverava da li su aplikacije instalirane preko ADB-a/ADT-a štetne."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava glavno podešavanje jačine zvuka na Bluetooth uređaju u slučaju problema sa jačinom zvuka na daljinskim uređajima, kao što su izuzetno velika jačina zvuka ili nedostatak kontrole."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplik. terminala za pristup lokalnom komandnom okruženju"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provera"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Neka ekran treperi kada aplikacije obavljaju duge operacije na glavnoj niti"</string>
<string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Postav. element sa trenutnim podacima o dodiru"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Prikazuj dodire"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Prikazuj vizuelne povratne informacije za dodire"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja površine"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Osvetli sve površine prozora kada se ažuriraju"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Prikaži ažur. GPU prikaza"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Prinudno dozvoli aplikacije u spoljnoj"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore proizvoljnog formata"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogućite podršku za eksperimentalne prozore proizvoljnog formata."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Postavljena je nova lozinka rezervne kopije"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i njena potvrda se ne podudaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Postavljanje lozinke rezervne kopije nije uspelo"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Boje optimizovane za digitalni sadržaj"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktivne aplikacije"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktivna. Dodirnite da biste je aktivirali."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivna. Dodirnite da biste je deaktivirali."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Noćni režim"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Uvek uključeno"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogući višeprocesni WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrećite WebView prikazivače u okviru izolovanog procesa."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izabrana primena WebView-a je onemogućena, a mora da bude omogućena radi korišćenja. Želite li da je omogućite?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Izabrana primena WebView-a je nevažeća zato što je lista mogućnosti za primenu zastarela. Sada bi trebalo da ažurirate listu."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuj u šifrovanje datoteka"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuj..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Već se koristi šifrovanje datoteka"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boja"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna i može da utiče na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo oko <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> dok se ne napuni"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio je administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontroliše administrator"</string>
+ <string name="home" msgid="8263346537524314127">"Početni"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Pre <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a87e3d534120..e3c8d8a88f8c 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Синтезиран говор"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Скорост на речта"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Скорост, с която се изговаря текстът"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Височина"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Отразява се на тона на синтезирания говор"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Език"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Използване на системния език"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Езикът не е избран"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Сканирането за роуминг на Wi-Fi да е разрешено винаги"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Наследена клиентска програма за DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Винаги активни клетъчни данни"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Деактивиране на пълната сила на звука"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Тези настройки са предназначени само за програмиране. Те могат да доведат до прекъсване на работата или неправилно функциониране на устройството ви и приложенията в него."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Потвържд. на прил. през USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверка на инсталираните чрез ADB/ADT приложения за опасно поведение."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Деактивира функцията на Bluetooth за пълна сила на звука в случай на проблеми със звука на отдалечени устройства, като например неприемливо висока сила на звука или липса на управление."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Актив. на прил. за терминал с достъп до локалния команден ред"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Проверка с HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Примигване на екрана при дълги операции в главната нишка"</string>
<string name="pointer_location" msgid="6084434787496938001">"Mестопол. на показалеца"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Насл. на екран показва текущи данни при докосване"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Показване на докосванията"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Показване на визуална обр. връзка за докосванията"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Актуал. на повърхн: Показв."</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Примигв. на целите повърхности на прозорците при актуализирането им"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Показв. на актуал. на изгледа от GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Външно хран.: Принуд. разрешаване на приложенията"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Активиране на прозорците в свободна форма"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Активира поддръжката за експерименталните прозорци в свободна форма."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Активиране на поддръжката за експерименталните прозорци в свободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Наст. комп.: Парола"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Зададена е нова парола за резервно копие"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата парола и въведената за потвърждаване не съвпадат"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Задаването на парола за резервно копие не бе успешно"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Цветове, оптимизирани за дигитално съдържание"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивни приложения"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивно. Докоснете, за да превключите."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Докоснете, за да превключите."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Изпълнявани услуги:"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Нощен режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Деактивирано"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Винаги включено"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Многопроц. режим на WebView: Акт."</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Програми за визуализация на WebView: Изпъл. в изолиран процес."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Внедряване на WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Задаване на внедряването на WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Избраното внедряване на WebView е деактивирано и трябва да го активирате, за да се използва. Искате ли да го направите?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Избраната реализация на WebView е невалидна, тъй като списъкът с възможни реализации е остарял. Той следва да се актуализира сега."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Преобразуване към шифроване на ниво файл"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Преобразуване…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Данните вече са шифровани на ниво файл"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекция на цветове"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Тази функция е експериментална и може да се отрази на ефективността."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Прибл. оставащо време: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – приблизително оставащо време: <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Не се зарежда"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се зарежда"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пълна"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Деактивирано от администратора"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролира се от администратор"</string>
+ <string name="home" msgid="8263346537524314127">"Начало"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Преди <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Оставащо време: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 82d70b948409..d3c9e6b8ce37 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"লেখিত-থেকে-ভাষ্য"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"ভাষ্য হার"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"যে গতিতে পাঠ্য উচ্চারিত হয়"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"পিচ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"সিন্থেসাইজ করা ভাষ্যের স্বরকে প্রভাবিত করে"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ভাষা"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"সিস্টেমের ভাষা ব্যবহার করুন"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ভাষা নির্বাচন করা নেই"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"সর্বদা Wifi রোম স্ক্যানকে অনুমতি দিন"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"লেগাসি DHCP ক্লায়েন্ট ব্যবহার করুন"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"সেলুলার ডেটা সর্বদাই সক্রিয় থাকে"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"চূড়ান্ত ভলিউম অক্ষম করুন"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"এইসব সেটিংস কেবলমাত্র উন্নত করার উদ্দেশ্য। সেগুলি কারণে আপনার ডিভাইস ভেঙ্গে এবং অ্যাপ্লিকেশানগুলি ভালো ভাবে কাজ করা নাও কারতে পারে।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB এর অ্যাপ্লিকেশানগুলি যাচাই করুন"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ক্ষতিকারক ক্রিয়াকলাপ করছে কিনা তার জন্য ADB/ADT মারফত ইনস্টল করা অ্যাপ্লিকেশানগুলি চেক করুন।"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"অপ্রত্যাশিত উচ্চ ভলিউম বা নিয়ন্ত্রণের অভাবের মত দূরবর্তী ডিভাইসের ভলিউম সমস্যাগুলির ক্ষেত্রে, Bluetooth চুড়ান্ত ভলিউম বৈশিষ্ট্য অক্ষম করে৷"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"স্থানীয় টার্মিনাল"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"স্থানীয় শেল অ্যাক্সেসের প্রস্তাব করে এমন টার্মিনাল অ্যাপ্লিকেশন সক্ষম করুন"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP পরীক্ষণ"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"মুখ্য থ্রেডে অ্যাপ্লিকেশানগুলির দীর্ঘ কার্যকলাপের সময় স্ক্রীন ফ্ল্যাশ করে"</string>
<string name="pointer_location" msgid="6084434787496938001">"পয়েন্টারের অবস্থান"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"স্ক্রীন ওভারলে বর্তমান স্পর্শ ডেটা দেখাচ্ছে"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"আলতো চাপ দেখান"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"আলতো চাপ দিলে ভিজ্যুয়াল প্রতিক্রিয়া দেখান"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"সারফেস আপডেটগুলি দেখান"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"সম্পূর্ণ উইন্ডোর সারফেস আপডেট হয়ে গেলে সেটিকে ফ্ল্যাশ করুন"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU দৃশ্য আপডেটগুলি প্রদর্শন করুন"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"বহিরাগততে বলপূর্বক মঞ্জুরি"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করে তোলে৷"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলির আকার পরিবর্তনযোগ্য করুন৷"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ফ্রি-ফর্ম উইন্ডোগুলি সক্ষম করুন"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ডেস্কটপের সম্পূর্ণ ব্যাকআপের পাসওয়ার্ডটি পরিবর্তন করতে বা মুছে ফেলতে আলতো চাপুন"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন ব্যাকআপ পাসওয়ার্ড সেট করুন"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাসওয়ার্ড এবং নিশ্চিতকরণ মিলছে না"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ব্যাকআপ পাসওয়ার্ড সেট করা ব্যর্থ"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"ডিজিট্যাল সামগ্রীর জন্য অপ্টিমাইজ করা রঙগুলি"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"নিষ্ক্রিয় অ্যাপ্লিকেশানগুলি"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"নিষ্ক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"সক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"এখন চলছে যে পরিষেবাগুলি"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"রাতের মোড"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"অক্ষম করা রয়েছে"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"সবসময় চালু"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"স্বয়ংক্রিয়"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"বহু-প্রক্রিয়া ওয়েবভিউ সক্ষম করুন"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"একটি বিচ্ছিন্ন প্রক্রিয়ায় ওয়েবভিউ রেন্ডারারগুলি চালান৷"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"ওয়েবভিউ প্রয়োগ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ওয়েবভিউ প্রয়োগ সেট করুন"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"নির্বাচিত ওয়েবভিউ প্রয়োগটি অক্ষম করা আছে এবং ব্যবহার করার জন্য অবশ্যই সক্ষম করতে হবে, আপনি কি এটিকে সক্ষম করতে চান?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"প্রয়োগ করার জন্য বেছে নেওয়া ওয়েবভিউটি অবৈধ, কারণ প্রয়োগের চয়নগুলি পুরানো হয়ে গেছে৷ এই তালিকাটিকে এখনই আপডেট করা উচিৎ৷"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ফাইল এনক্রিপশান রূপান্তর করুন"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"রূপান্তর করুন..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ফাইল ইতিমধ্যেই এনক্রিপ্ট করা রয়েছে"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"রঙ সংশোধন"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"এই বৈশিষ্ট্যটি পরীক্ষামূলক এবং এটি কার্য-সম্পাদনা প্রভাবিত করতে পারে।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"প্রায় <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - আনুমানিক <xliff:g id="TIME">%2$s</xliff:g> বাকি আছে"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - সম্পূর্ণ হতে <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"চার্জ হচ্ছে না"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"চার্জ হচ্ছে না"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"পূর্ণ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"প্রশাসক দ্বারা অক্ষমিত"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"প্রশাসকের দ্বারা নিয়ন্ত্রিত"</string>
+ <string name="home" msgid="8263346537524314127">"হোম"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> আগে"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> বাকী আছে"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bs-rBA/arrays.xml b/packages/SettingsLib/res/values-bs-rBA/arrays.xml
new file mode 100644
index 000000000000..32b8bc555a38
--- /dev/null
+++ b/packages/SettingsLib/res/values-bs-rBA/arrays.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wifi_status">
+ <item msgid="1922181315419294640"></item>
+ <item msgid="8934131797783724664">"Skeniranje…"</item>
+ <item msgid="8513729475867537913">"Povezivanje…"</item>
+ <item msgid="515055375277271756">"Autentifikacija…"</item>
+ <item msgid="1943354004029184381">"Dobivanje IP adrese…"</item>
+ <item msgid="4221763391123233270">"Povezano"</item>
+ <item msgid="624838831631122137">"Suspendiran"</item>
+ <item msgid="7979680559596111948">"Prekidanje veze…"</item>
+ <item msgid="1634960474403853625">"Isključen"</item>
+ <item msgid="746097431216080650">"Neuspješno"</item>
+ <item msgid="6367044185730295334">"Blokirano"</item>
+ <item msgid="503942654197908005">"Privremeno izbjegavaj veze lošeg kvaliteta"</item>
+ </string-array>
+ <string-array name="wifi_status_with_ssid">
+ <item msgid="7714855332363650812"></item>
+ <item msgid="8878186979715711006">"Skeniranje…"</item>
+ <item msgid="355508996603873860">"Povezivanje na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+ <item msgid="554971459996405634">"Autentifikacija sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="7928343808033020343">"Dobivanje IP adrese iz mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="8937994881315223448">"Povezan na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+ <item msgid="1330262655415760617">"Suspendiran"</item>
+ <item msgid="7698638434317271902">"Prekidanje veze sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="197508606402264311">"Isključen"</item>
+ <item msgid="8578370891960825148">"Neuspješno"</item>
+ <item msgid="5660739516542454527">"Blokirano"</item>
+ <item msgid="1805837518286731242">"Privremeno izbjegavaj veze lošeg kvaliteta"</item>
+ </string-array>
+ <string-array name="hdcp_checking_titles">
+ <item msgid="441827799230089869">"Nikada ne provjeravaj"</item>
+ <item msgid="6042769699089883931">"Provjeri samo za DRM sadržaj"</item>
+ <item msgid="9174900380056846820">"Uvijek provjeri"</item>
+ </string-array>
+ <string-array name="hdcp_checking_summaries">
+ <item msgid="505558545611516707">"Nikada ne koristi HDCP provjeru"</item>
+ <item msgid="3878793616631049349">"Koristi HDCP provjeru samo za DRM sadržaj"</item>
+ <item msgid="45075631231212732">"Uvijek koristi HDCP provjeru"</item>
+ </string-array>
+ <string-array name="select_logd_size_titles">
+ <item msgid="8665206199209698501">"Isključeno"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
+ </string-array>
+ <string-array name="select_logd_size_lowram_titles">
+ <item msgid="6089470720451068364">"Isključeno"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
+ </string-array>
+ <string-array name="select_logd_size_summaries">
+ <item msgid="6921048829791179331">"Isključeno"</item>
+ <item msgid="2969458029344750262">"64K po međumemoriji dnevnika"</item>
+ <item msgid="1342285115665698168">"256k po međumemoriji dnevnika"</item>
+ <item msgid="1314234299552254621">"1M po međumemoriji dnevnika"</item>
+ <item msgid="3606047780792894151">"4M po međumemoriji dnevnika"</item>
+ <item msgid="5431354956856655120">"16M po međumemoriji dnevnika"</item>
+ </string-array>
+ <string-array name="window_animation_scale_entries">
+ <item msgid="8134156599370824081">"Animacija isključena"</item>
+ <item msgid="6624864048416710414">"Animacija razmjera .5x"</item>
+ <item msgid="2219332261255416635">"Animacija razmjera 1x"</item>
+ <item msgid="3544428804137048509">"Animacija razmjera 1,5x"</item>
+ <item msgid="3110710404225974514">"Animacija razmjera 2x"</item>
+ <item msgid="4402738611528318731">"Animacija razmjera 5x"</item>
+ <item msgid="6189539267968330656">"Animacija razmjera 10x"</item>
+ </string-array>
+ <string-array name="transition_animation_scale_entries">
+ <item msgid="8464255836173039442">"Animacija isključena"</item>
+ <item msgid="3375781541913316411">"Animacija razmjera .5x"</item>
+ <item msgid="1991041427801869945">"Animacija razmjera 1x"</item>
+ <item msgid="4012689927622382874">"Animacija razmjera 1,5x"</item>
+ <item msgid="3289156759925947169">"Animacija razmjera 2x"</item>
+ <item msgid="7705857441213621835">"Animacija razmjera 5x"</item>
+ <item msgid="6660750935954853365">"Animacija razmjera 10x"</item>
+ </string-array>
+ <string-array name="animator_duration_scale_entries">
+ <item msgid="6039901060648228241">"Animacija isključena"</item>
+ <item msgid="1138649021950863198">"Animacija razmjera .5x"</item>
+ <item msgid="4394388961370833040">"Animacija razmjera 1x"</item>
+ <item msgid="8125427921655194973">"Animacija razmjera 1.5x"</item>
+ <item msgid="3334024790739189573">"Animacija razmjera 2x"</item>
+ <item msgid="3170120558236848008">"Animacija razmjera 5x"</item>
+ <item msgid="1069584980746680398">"Animacija razmjera 10x"</item>
+ </string-array>
+ <string-array name="overlay_display_devices_entries">
+ <item msgid="1606809880904982133">"Nema"</item>
+ <item msgid="9033194758688161545">"480p"</item>
+ <item msgid="1025306206556583600">"480p (osiguran)"</item>
+ <item msgid="1853913333042744661">"720p"</item>
+ <item msgid="3414540279805870511">"720p (osiguran)"</item>
+ <item msgid="9039818062847141551">"1080p"</item>
+ <item msgid="4939496949750174834">"1080p (osiguran)"</item>
+ <item msgid="1833612718524903568">"4K"</item>
+ <item msgid="238303513127879234">"4K (osiguran)"</item>
+ <item msgid="3547211260846843098">"4K (povećava rezoluciju)"</item>
+ <item msgid="5411365648951414254">"4K (povećava rezoluciju, osiguran)"</item>
+ <item msgid="1311305077526792901">"720p, 1080p (dupli ekran)"</item>
+ </string-array>
+ <string-array name="enable_opengl_traces_entries">
+ <item msgid="3191973083884253830">"Nema"</item>
+ <item msgid="9089630089455370183">"Logcat"</item>
+ <item msgid="5397807424362304288">"Systrace (grafika)"</item>
+ <item msgid="1340692776955662664">"Pozovi skupinu na glGetError"</item>
+ </string-array>
+ <string-array name="show_non_rect_clip_entries">
+ <item msgid="993742912147090253">"Isključeno"</item>
+ <item msgid="675719912558941285">"Nacrtaj plavom bojom nepravougaonu oblast za isjecanje"</item>
+ <item msgid="1064373276095698656">"Označite zelenom bojom testirane komande za crtanje"</item>
+ </string-array>
+ <string-array name="track_frame_time_entries">
+ <item msgid="2193584639058893150">"Isključeno"</item>
+ <item msgid="2751513398307949636">"Na ekranu u vidu crtica"</item>
+ <item msgid="1851438178120770973">"U ADB ljuski dumpsys gfxinfo"</item>
+ </string-array>
+ <string-array name="debug_hw_overdraw_entries">
+ <item msgid="8190572633763871652">"Isključeno"</item>
+ <item msgid="7688197031296835369">"Prikaži overdraw područja"</item>
+ <item msgid="2290859360633824369">"Prikaži područja za Deuteranomaly"</item>
+ </string-array>
+ <string-array name="app_process_limit_entries">
+ <item msgid="3401625457385943795">"Standardno ograničenje"</item>
+ <item msgid="4071574792028999443">"Nema pozadinskih procesa"</item>
+ <item msgid="4810006996171705398">"Najviše 1 proces"</item>
+ <item msgid="8586370216857360863">"Najviše 2 procesa"</item>
+ <item msgid="836593137872605381">"Najviše 3 procesa"</item>
+ <item msgid="7899496259191969307">"Najviše 4 procesa"</item>
+ </string-array>
+ <string-array name="usb_configuration_titles">
+ <item msgid="488237561639712799">"Puni se"</item>
+ <item msgid="5220695614993094977">"MTP (protokol za prijenos sadržaja medija)"</item>
+ <item msgid="2086000968159047375">"PTP (protokol za prijenos slika)"</item>
+ <item msgid="7398830860950841822">"RNDIS (USB Ethernet)"</item>
+ <item msgid="1718924214939774352">"Izvor zvuka"</item>
+ <item msgid="8126315616613006284">"MIDI"</item>
+ </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index f09e1cab9f3c..673b08b0b326 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -20,138 +20,77 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for wifi_fail_to_scan (1265540342578081461) -->
- <skip />
- <!-- no translation found for wifi_security_none (7985461072596594400) -->
- <skip />
- <!-- no translation found for wifi_remembered (4955746899347821096) -->
- <skip />
- <!-- no translation found for wifi_disabled_generic (4259794910584943386) -->
- <skip />
- <!-- no translation found for wifi_disabled_network_failure (2364951338436007124) -->
- <skip />
- <!-- no translation found for wifi_disabled_wifi_failure (3081668066612876581) -->
- <skip />
- <!-- no translation found for wifi_disabled_password_failure (8659805351763133575) -->
- <skip />
- <!-- no translation found for wifi_not_in_range (1136191511238508967) -->
- <skip />
- <!-- no translation found for wifi_no_internet (9151470775868728896) -->
- <skip />
- <!-- no translation found for saved_network (4352716707126620811) -->
- <skip />
- <!-- no translation found for connected_via_wfa (3805736726317410714) -->
- <skip />
- <!-- no translation found for connected_via_passpoint (2826205693803088747) -->
- <skip />
- <!-- no translation found for available_via_passpoint (1617440946846329613) -->
- <skip />
- <!-- no translation found for wifi_connected_no_internet (3149853966840874992) -->
- <skip />
- <!-- no translation found for bluetooth_disconnected (6557104142667339895) -->
- <skip />
- <!-- no translation found for bluetooth_disconnecting (8913264760027764974) -->
- <skip />
- <!-- no translation found for bluetooth_connecting (8555009514614320497) -->
- <skip />
- <!-- no translation found for bluetooth_connected (6038755206916626419) -->
- <skip />
- <!-- no translation found for bluetooth_pairing (1426882272690346242) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_headset (2866994875046035609) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_a2dp (4576188601581440337) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_map (6504436917057479986) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (9195757766755553810) -->
- <skip />
- <!-- no translation found for bluetooth_profile_a2dp (2031475486179830674) -->
- <skip />
- <!-- no translation found for bluetooth_profile_headset (8658779596261212609) -->
- <skip />
- <!-- no translation found for bluetooth_profile_opp (9168139293654233697) -->
- <skip />
- <!-- no translation found for bluetooth_profile_hid (3680729023366986480) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pan (3391606497945147673) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pbap (5372051906968576809) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pbap_summary (6605229608108852198) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pan_nap (8429049285027482959) -->
- <skip />
- <!-- no translation found for bluetooth_profile_map (5465271250454324383) -->
- <skip />
- <!-- no translation found for bluetooth_profile_sap (5764222021851283125) -->
- <skip />
- <!-- no translation found for bluetooth_a2dp_profile_summary_connected (963376081347721598) -->
- <skip />
- <!-- no translation found for bluetooth_headset_profile_summary_connected (7661070206715520671) -->
- <skip />
- <!-- no translation found for bluetooth_opp_profile_summary_connected (2611913495968309066) -->
- <skip />
- <!-- no translation found for bluetooth_map_profile_summary_connected (8191407438851351713) -->
- <skip />
- <!-- no translation found for bluetooth_sap_profile_summary_connected (8561765057453083838) -->
- <skip />
- <!-- no translation found for bluetooth_opp_profile_summary_not_connected (1267091356089086285) -->
- <skip />
- <!-- no translation found for bluetooth_hid_profile_summary_connected (3381760054215168689) -->
- <skip />
+ <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ne može skenirati mreže"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"Sačuvano"</string>
+ <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string>
+ <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Greška u konfiguraciji IP-a"</string>
+ <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na Wi-Fi"</string>
+ <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
+ <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
+ <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
+ <string name="saved_network" msgid="4352716707126620811">"Sačuvao <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani preko Wi-Fi pomoćnika"</string>
+ <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
+ <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupan preko %1$s"</string>
+ <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Povezano. Nema interneta"</string>
+ <string name="bluetooth_disconnected" msgid="6557104142667339895">"Isključen"</string>
+ <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekidanje veze…"</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"Povezivanje…"</string>
+ <string name="bluetooth_connected" msgid="6038755206916626419">"Povezano"</string>
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"Uparivanje…"</string>
+ <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Povezano (bez telefona)"</string>
+ <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
+ <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano (bez pristupa porukama)"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez zvuka telefona ili medija)"</string>
+ <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medija"</string>
+ <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvuk telefona"</string>
+ <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenošenje fajla"</string>
+ <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Ulazni uređaj"</string>
+ <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Pristup internetu"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Dijeljenje kontakta"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Koristi za dijeljenje kontakta"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Dijeljenje internet veze"</string>
+ <string name="bluetooth_profile_map" msgid="5465271250454324383">"Pristup poruci"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM-u"</string>
+ <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano sa zvukom medija"</string>
+ <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano na zvuk telefona"</string>
+ <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezan na server za prijenos podataka"</string>
+ <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Povezano na mapu"</string>
+ <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Povezan na SAP"</string>
+ <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezan na server za prijenos podataka"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Spojen na ulazni uređaj"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pov. na ur. za pris. int."</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dij. lok. int. veze s ur."</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5664884523822068653) -->
- <skip />
- <!-- no translation found for bluetooth_map_profile_summary_use_for (5154200119919927434) -->
- <skip />
- <!-- no translation found for bluetooth_sap_profile_summary_use_for (7085362712786907993) -->
- <skip />
- <!-- no translation found for bluetooth_a2dp_profile_summary_use_for (4630849022250168427) -->
- <skip />
- <!-- no translation found for bluetooth_headset_profile_summary_use_for (8705753622443862627) -->
- <skip />
- <!-- no translation found for bluetooth_opp_profile_summary_use_for (1255674547144769756) -->
- <skip />
- <!-- no translation found for bluetooth_hid_profile_summary_use_for (232727040453645139) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_accept (6163520056536604875) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_accept_all_caps (6061699265220789149) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_decline (4185420413578948140) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_will_share_phonebook (4982239145676394429) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_error_message (3748157733635947087) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_pin_error_message (8337234855188925274) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_device_down_error_message (7870998403045801381) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_rejected_error_message (1648157108520832454) -->
- <skip />
- <!-- no translation found for accessibility_wifi_off (1166761729660614716) -->
- <skip />
- <!-- no translation found for accessibility_no_wifi (8834610636137374508) -->
- <skip />
- <!-- no translation found for accessibility_wifi_one_bar (4869376278894301820) -->
- <skip />
- <!-- no translation found for accessibility_wifi_two_bars (3569851234710034416) -->
- <skip />
- <!-- no translation found for accessibility_wifi_three_bars (8134185644861380311) -->
- <skip />
- <!-- no translation found for accessibility_wifi_signal_full (7061045677694702) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Koristi za pristup internetu"</string>
+ <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Koristi za mapu"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Koristi za pristup SIM-u"</string>
+ <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Koristi za zvuk medija"</string>
+ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Koristi za zvuk telefona"</string>
+ <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Koristi za prijenos fajlova"</string>
+ <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Koristi kao ulaz"</string>
+ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string>
+ <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Otkaži"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Uparivanje odobrava pristup kontaktima i istoriji poziva kada je uspostavljeno."</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zbog pogrešnog PIN-a ili pristupnog koda."</string>
+ <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ne može komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio uparivanje."</string>
+ <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi isključen."</string>
+ <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi nije povezan."</string>
+ <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi jedna crtica."</string>
+ <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi dvije crtice."</string>
+ <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi tri crtice."</string>
+ <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi puni signal."</string>
<string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string>
<string name="tether_settings_title_usb" msgid="6688416425801386511">"USB dijeljenje veze"</string>
- <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosna pristupna tačka"</string>
+ <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prijenosna pristupna tačka"</string>
<string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Dijeljenje Bluetooth veze"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Dijeljenje veze"</string>
- <string name="tether_settings_title_all" msgid="8356136101061143841">"Dijeljenje internetske veze i prenosna pristupna tačka"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"Dijeljenje internetske veze i prijenosna pristupna tačka"</string>
<string name="managed_user_title" msgid="8101244883654409696">"Profil za Work"</string>
<string name="user_guest" msgid="8475274842845401871">"Gost"</string>
<string name="unknown" msgid="1592123443519355854">"Nepoznato"</string>
@@ -162,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Izlaz za pretvaranje teksta u govor"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina kojom se izgovara tekst"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Visina"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utječe na ton sintetiziranog govora"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Koristi sistemski jezik"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije izabran"</string>
@@ -170,34 +111,34 @@
<string name="tts_play_example_summary" msgid="8029071615047894486">"Reproduciraj kratku demonstraciju sintetiziranja govora"</string>
<string name="tts_install_data_title" msgid="4264378440508149986">"Instaliraj glasovne podatke"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"Instalirajte glasovne podatke potrebne za sintetiziranje govora"</string>
- <string name="tts_engine_security_warning" msgid="8786238102020223650">"Ovaj program za sintetiziranje govora može biti u mogućnosti da prikuplja sav tekst koji se izgovara, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. Potiče od aplikacije <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Da li želite koristiti ovaj program za sintetiziranje govora?"</string>
+ <string name="tts_engine_security_warning" msgid="8786238102020223650">"Ovaj program za sintetiziranje govora u mogućnosti je da prikuplja sav tekst koji se izgovara, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. Program omogućava aplikacija <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Da li želite koristiti ovaj program za sintetiziranje govora?"</string>
<string name="tts_engine_network_required" msgid="1190837151485314743">"Ovaj jezik zahtijeva mrežnu vezu radi za izlaz tekst-u-govor."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Ovo je primjer sinteze govora"</string>
<string name="tts_status_title" msgid="7268566550242584413">"Zadani status jezika"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> je u potpunosti podržan"</string>
<string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> zahtjeva mrežnu vezu"</string>
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> nije podržan"</string>
- <!-- no translation found for tts_status_checking (5339150797940483592) -->
- <skip />
+ <string name="tts_status_checking" msgid="5339150797940483592">"Provjerava se…"</string>
<string name="tts_engine_settings_title" msgid="3499112142425680334">"Postavke za <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
<string name="tts_engine_settings_button" msgid="1030512042040722285">"Pokreni postavke programa"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Željeni program"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Opće"</string>
- <!-- no translation found for tts_rate_entries:0 (6695494874362656215) -->
- <!-- no translation found for tts_rate_entries:1 (4795095314303559268) -->
- <!-- no translation found for tts_rate_entries:2 (8903157781070679765) -->
- <!-- no translation found for tts_rate_entries:3 (164347302621392996) -->
- <!-- no translation found for tts_rate_entries:4 (5794028588101562009) -->
- <!-- no translation found for tts_rate_entries:5 (7163942783888652942) -->
- <!-- no translation found for tts_rate_entries:6 (7831712693748700507) -->
- <!-- no translation found for tts_rate_entries:7 (5194774745031751806) -->
- <!-- no translation found for tts_rate_entries:8 (9085102246155045744) -->
+ <string-array name="tts_rate_entries">
+ <item msgid="6695494874362656215">"Veoma sporo"</item>
+ <item msgid="4795095314303559268">"Sporo"</item>
+ <item msgid="8903157781070679765">"Normalno"</item>
+ <item msgid="164347302621392996">"Brzo"</item>
+ <item msgid="5794028588101562009">"Brže"</item>
+ <item msgid="7163942783888652942">"Veoma brzo"</item>
+ <item msgid="7831712693748700507">"Ubrzano"</item>
+ <item msgid="5194774745031751806">"Veoma ubrzano"</item>
+ <item msgid="9085102246155045744">"Najbrže"</item>
+ </string-array>
<string name="choose_profile" msgid="8229363046053568878">"Odaberite profil"</string>
<string name="category_personal" msgid="1299663247844969448">"Lično"</string>
<string name="category_work" msgid="8699184680584175622">"Posao"</string>
<string name="development_settings_title" msgid="215179176067683667">"Opcije za programere"</string>
- <!-- no translation found for development_settings_enable (542530994778109538) -->
- <skip />
+ <string name="development_settings_enable" msgid="542530994778109538">"Omogući opcije za programere"</string>
<string name="development_settings_summary" msgid="1815795401632854041">"Postavi opcije za razvoj aplikacija"</string>
<string name="development_settings_not_available" msgid="4308569041701535607">"Opcije za programere nisu dostupne za ovog korisnika"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"VPN postavke nisu dostupne za ovog korisnika"</string>
@@ -226,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopustiti Wi-Fi lutajuće skeniranje"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
<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="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>
@@ -240,12 +182,13 @@
<string name="legacy_dhcp_client_summary" msgid="163383566317652040">"Koristi DHCP klijent iz Lollipopa umjesto novog Android DHCP klijenta."</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Uvijek drži mobilne podatke aktivnim, čak i kada je Wi-Fi je aktivan (za brzo prebacivanje između mreža)."</string>
<string name="adb_warning_title" msgid="6234463310896563253">"Omogućiti USB otklanjanje grešaka?"</string>
- <string name="adb_warning_message" msgid="7316799925425402244">"USB otklanjanje grešaka je namijenjeno samo u svrhe razvoja aplikacija. Koristite ga za kopiranje podataka između računara i uređaja, instaliranje aplikacija na uređaj bez obavještenja te čitanje podataka iz dnevnika rada."</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"USB otklanjanje grešaka je namijenjeno samo u svrhe razvoja aplikacija. Koristite ga za kopiranje podataka između računara i uređaja, instaliranje aplikacija na uređaj bez obavještenja te čitanje podataka iz zapisnika."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Opozvati pristup otklanjanju grešaka USB-om za sve računare koje ste prethodno ovlastili?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Dopustiti postavke za razvoj?"</string>
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove postavke su namijenjene samo za svrhe razvoja. Mogu izazvati pogrešno ponašanje uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije putem USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerava da li se u aplikacijama instaliranim putem ADB-a/ADT-a javlja zlonamerno ponašanje."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava opciju Bluetooth apsolutne jačine zvuka u slučaju problema s jačinom zvuka na udaljenim uređajima, kao što je neprihvatljivo glasan zvuk ili nedostatak kontrole."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogući terminalnu aplik. koja nudi pristup lok. kom. okruženju"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjeravanje"</string>
@@ -268,7 +211,7 @@
<string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Trenutni podaci o dodirivanju prikazuje se u nadsloju preko ekrana"</string>
<string name="show_touches" msgid="2642976305235070316">"Prikaži dodirivanja"</string>
- <string name="show_touches_summary" msgid="6101183132903926324">"Prikaži vizualne povratne podatke za dodirivanja"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Prikaži vizuelne povratne informacije za dodirivanja"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja za površinu"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Prikazi cijele površine prozora uz treptanje prilikom ažuriranja"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Pok. ažur. za GPU prikaz"</string>
@@ -293,9 +236,9 @@
<string name="force_msaa" msgid="7920323238677284387">"Prinudno primjeni 4x MSAA"</string>
<string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string>
<string name="show_non_rect_clip" msgid="505954950474595172">"Ispravi pogreške na nepravougaonim operacijama isecanja"</string>
- <string name="track_frame_time" msgid="6146354853663863443">"Iscrtavanje GPU profila"</string>
+ <string name="track_frame_time" msgid="6146354853663863443">"Profil GPU iscrtavanja"</string>
<string name="window_animation_scale_title" msgid="6162587588166114700">"Skala animacije prozora"</string>
- <string name="transition_animation_scale_title" msgid="387527540523595875">"Skaliranje animacije prelaza"</string>
+ <string name="transition_animation_scale_title" msgid="387527540523595875">"Skaliranje animacije prijelaza"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Skala trajanja animatora"</string>
<string name="overlay_display_devices_title" msgid="5364176287998398539">"Simuliraj sekundarne ekrane"</string>
<string name="debug_applications_category" msgid="4206913653849771549">"Aplikacije"</string>
@@ -304,21 +247,15 @@
<string name="app_process_limit_title" msgid="4280600650253107163">"Ograničenje procesa u pozadini"</string>
<string name="show_all_anrs" msgid="28462979638729082">"Prikaži sve ANR-ove"</string>
<string name="show_all_anrs_summary" msgid="641908614413544127">"Prik. dijalog Aplikacija ne reagira za apl. u poz."</string>
- <!-- no translation found for force_allow_on_external (3215759785081916381) -->
- <skip />
- <!-- no translation found for force_allow_on_external_summary (3191952505860343233) -->
- <skip />
- <!-- no translation found for force_resizable_activities (8615764378147824985) -->
- <skip />
- <!-- no translation found for force_resizable_activities_summary (4508217476997182216) -->
- <skip />
- <!-- no translation found for enable_freeform_support (1461893351278940416) -->
- <skip />
- <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
- <skip />
- <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka za rezervnu kopiju za radnu površinu"</string>
+ <string name="force_allow_on_external" msgid="3215759785081916381">"Nametni aplikacije na vanjskoj pohrani"</string>
+ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Dozvoljava da bilo koja aplikacija bude upisana na vanjsku pohranu, bez obzira na vrijednosti manifesta."</string>
+ <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni aktivnostima mijenjanje veličina"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Neka sve aktivnosti budu takve da mogu mijenjati veličinu za prikaz sa više prozora, bez obzira na prikazane vrijednosti."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore nepravilnih oblika"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogućiti podršku za eksperimentalne prozore nepravilnih oblika."</string>
+ <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka za rezervnu kopiju radne površine"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promijenili ili uklonili lozinku za potpune rezervne kopije sa radne površine"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije sa radne površine"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za rezervnu kopiju postavljena"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i potvrda se ne podudaraju"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje lozinke za rezervnu kopiju"</string>
@@ -337,32 +274,17 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dodirnite za promjenu opcije."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Prikažite trenutno pokrenute usluge i upravljajte njima"</string>
- <!-- no translation found for night_mode_title (2594133148531256513) -->
- <skip />
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <!-- no translation found for night_mode_no (9171772244775838901) -->
- <skip />
- <!-- no translation found for night_mode_yes (2218157265997633432) -->
- <skip />
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
- <!-- no translation found for select_webview_provider_title (4628592979751918907) -->
- <skip />
- <!-- no translation found for select_webview_provider_dialog_title (4370551378720004872) -->
- <skip />
- <!-- no translation found for select_webview_provider_confirmation_text (6671472080671066972) -->
- <skip />
- <!-- no translation found for convert_to_file_encryption (3060156730651061223) -->
- <skip />
- <!-- no translation found for convert_to_file_encryption_enabled (2861258671151428346) -->
- <skip />
- <!-- no translation found for convert_to_file_encryption_done (7859766358000523953) -->
- <skip />
- <!-- no translation found for title_convert_fbe (1263622876196444453) -->
- <skip />
- <!-- no translation found for convert_to_fbe_warning (6139067817148865527) -->
- <skip />
- <!-- no translation found for button_convert_fbe (5152671181309826405) -->
- <skip />
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogućiti višeprocesni WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrenite WebView operatera u izolovanom procesu."</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Postavljanje WebViewa"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesi WebView"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Primjena izabranog prikaza weba ne važi jer je spisak izbora primjene zastario. Spisak se sada treba ažurirati."</string>
+ <string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u šifrirani fajl"</string>
+ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvaranje…"</string>
+ <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fajl je već šifriran"</string>
+ <string name="title_convert_fbe" msgid="1263622876196444453">"Pretvaranje u šifrirane fajlove"</string>
+ <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Pretvori particiju sa podacima u particiju šifriranu sistemom fajlova.\n !! Upozorenje!! Ovo će izbrisati sve vaše podatke.\n Ova funkcija je u alfa fazi razvoja i možda neće ispravno raditi.\n Pritisnite \'Obriši i pretvori…\" da nastavite."</string>
+ <string name="button_convert_fbe" msgid="5152671181309826405">"Obriši i pretvori…"</string>
<string name="picture_color_mode" msgid="4560755008730283695">"Režim boja Slika"</string>
<string name="picture_color_mode_desc" msgid="1141891467675548590">"Koristi sRGB"</string>
<string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Onemogućeno"</string>
@@ -373,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Ispravka boje"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna te može utjecati na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo vreme je otprilike <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pune baterije"</string>
@@ -387,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pod kontrolom administratora"</string>
+ <string name="home" msgid="8263346537524314127">"Početna stranica"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Još otprilike <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index bfca38114298..d4d2f6c51900 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Síntesi de veu"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Velocitat de veu"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocitat de lectura del text"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"To"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta el to de la veu sintetitzada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Utilitza l\'idioma del sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"No has seleccionat cap idioma"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permet sempre cerca de Wi-Fi en ininerància"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utilitza el client DHCP heretat"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Aquesta configuració només està prevista per a usos de desenvolupament. Pot fer que el dispositiu i que les aplicacions s\'interrompin o tinguin un comportament inadequat."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica aplicacions per USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprova les aplicacions instal·lades mitjançant ADB/ADT per detectar possibles comportaments perillosos"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva la funció de volum absolut de Bluetooth en cas que es produeixin problemes de volum amb dispositius remots, com ara un volum massa alt o una manca de control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activa l\'aplicació de terminal que ofereix accés al shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprovació HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet que les aplicacions es puguin escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activa les finestres de format lliure"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa la compatibilitat amb les finestres de format lliure experimentals."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activa la compatibilitat amb finestres de format lliure experimentals."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasenya per a còpies d\'ordinador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les còpies de seguretat d\'ordinador completes no estan protegides"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca per canviar o suprimir la contrasenya per a les còpies de seguretat completes de l\'ordinador"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aplicació activa. Toca per desactivar-la."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Serveis en execució"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Visualitza i controla els serveis en execució"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Mode nocturn"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Desactivat"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sempre activat"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automàtic"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activa WebView amb multiprocés"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executa els renderitzadors de WebView en un procés aïllat."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementació de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configura la implementació de WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementació de WebView que has triat està desactivada i s\'ha d\'activar per utilitzar-la. Vols activar-la?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementació de WebView que s\'ha triat no és vàlida perquè la llista d\'opcions d\'implementació ha quedat inactiva. Ara la llista ja hauria d\'estar actualitzada."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converteix en l\'encriptació de fitxers"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converteix…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"El fitxer ja està encriptat"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correcció del color"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Aquesta funció és experimental i pot afectar el rendiment."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Temps restant aproximat: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g>: falten aproximadament <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"No s\'està carregant"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"No s\'està carregant"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Plena"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Opció desactivada per l\'administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlat per l\'administrador"</string>
+ <string name="home" msgid="8263346537524314127">"Inici"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Fa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Temps restant: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index beba7c35a61c..00d4f478f12a 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Převod textu na řeč"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Rychlost řeči"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Rychlost mluveného textu"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Výška"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Určuje tón syntetizované řeči"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Jazyk"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Použít jazyk systému"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nebyl vybrán jazyk"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povolit Wi-Fi roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Použít starý klient DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tato nastavení jsou určena pouze pro vývojáře. Mohou způsobit rozbití nebo nesprávné fungování zařízení a nainstalovaných aplikací."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Ověřit aplikace z USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovat škodlivost aplikací nainstalovaných pomocí nástroje ADB/ADT"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Zakáže funkci absolutní hlasitosti Bluetooth. Zabrání tak problémům s hlasitostí vzdálených zařízení (jako je příliš vysoká hlasitost nebo nemožnost ovládání)."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Místní terminál"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivovat terminálovou aplikaci pro místní přístup k prostředí shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrola HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Rozblikat obrazovku při dlouhých operacích hlavního vlákna"</string>
<string name="pointer_location" msgid="6084434787496938001">"Umístění ukazatele"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Zobrazit překryvnou vrstvu s aktuálními daty o dotycích"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Zobrazovat klepnutí"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Zobrazování vizuální zpětné vazby pro klepnutí"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Zobrazit obnovení obsahu"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Rozblikat obsah okna při aktualizaci"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Zobrazit obnovení s GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Vynutit povolení aplikací na externím úložišti"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vynutit možnost změny velikosti aktivit"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Velikost všech aktivit bude možné změnit na několik oken (bez ohledu na hodnoty manifestu)."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Umožnit změnu velikosti všech aktivit na několik oken (bez ohledu na hodnoty manifestu)"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivovat okna s volným tvarem"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivuje podporu experimentálních oken s volným tvarem."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivovat podporu experimentálních oken s volným tvarem"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pro zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy do počítače"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pro zálohy je nastaveno"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo se neshoduje s potvrzením hesla."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavení hesla pro zálohy selhalo"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Barvy optimalizované pro digitální obsah"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktivní aplikace"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktivní. Klepnutím možnost přepnete."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivní. Klepnutím možnost přepnete."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Spuštěné služby"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Noční režim"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Vypnuto"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuto"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Povolit WebView ve více procesech"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Spouštět moduly vykreslení WebView jako samostatné procesy."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementace WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavte implementaci WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Vybraná implementace WebView je zakázána a nelze ji použít. Chcete ji povolit a použít?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Vybraná implementace WebView není platná, protože seznam možností implementace je zastaralý. Seznam je potřeba aktualizovat."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Převést na šifrování souborů"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Převést…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Obsah je již na úrovni souborů zašifrován"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekce barev"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkce je experimentální a může mít vliv na výkon."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zbývající čas: <xliff:g id="TIME">%1$s</xliff:g> (přibližně)"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zbývá přibližně <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nenabíjí se"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenabíjí se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Zakázáno administrátorem"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Spravováno administrátorem"</string>
+ <string name="home" msgid="8263346537524314127">"Plocha"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"před <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Zbývající čas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f00a49af7b05..398875a8bd66 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Oplæsning"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Talehastighed"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Oplæsningshastighed for tekst"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Toneleje"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Påvirker tonen af den syntetiserede tale"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Sprog"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Brug systemsprog"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Der er ikke valgt sprog"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillad altid scanning af Wi-Fi-roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Brug ældre DHCP-klient"</string>
<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="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>
@@ -185,6 +188,7 @@
<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_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>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivér terminalappen, der giver lokal shell-adgang"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrol"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Blink med skærmen, når apps foretager handlinger på hovedtråd"</string>
<string name="pointer_location" msgid="6084434787496938001">"Markørens placering"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skærmoverlejringen viser de aktuelle berøringsdata"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Vis tryk"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Vis visuel feedback ved tryk"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Vis overfladeopdateringer"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Fremhæv hele vinduesoverflader, når de opdateres"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Vis opdat. af GPU-eksp."</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Gennemtving tilladelse til eksternt lager"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Sørger for, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivér vinduer i frit format"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverer understøttelse af eksperimentelle vinduer i frit format."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivér understøttelse af eksperimentelle vinduer i frit format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Ny adgangskode til sikkerhedskopi er angivet"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ny adgangskode og bekræftelse matcher ikke"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fejl ved angivelse af adgangskode til sikkerhedskopi"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Farver, der er optimeret til digitalt indhold"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Inaktive apps"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Inaktiv. Tryk for at skifte."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Tryk for at skifte."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Kørende tjenester"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Vis og kontrollér kørende tjenester"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nattilstand"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Deaktiveret"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Altid slået til"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktivér WebView i flere processer"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Kør WebView-gengivelse i en isoleret proces."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Konfigurer WebView-implementering"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valgte WebView-implementering er deaktiveret og skal aktiveres, før den kan bruges. Vil du aktivere den?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Den valgte WebView-implementering er ugyldig, da listen over implementeringsvalg var forældet. Listen bør nu være opdateret."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertér til filkryptering"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertér…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Allerede filkrypteret"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korriger farver"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funktion er eksperimentel og kan påvirke ydeevnen."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> tilbage"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> tilbage"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til fuldt opladet"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Oplader ikke"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Oplader ikke"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fuld"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Deaktiveret af administratoren"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolleret af administratoren"</string>
+ <string name="home" msgid="8263346537524314127">"Start"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> tilbage"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index e39e4640676c..2a5642513c11 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Text-in-Sprache-Ausgabe"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Sprechgeschwindigkeit"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Geschwindigkeit, mit der der Text gesprochen wird"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonlage"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Beeinflusst den Ton der künstlichen Sprache"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Sprache"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Systemsprache verwenden"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Keine Sprache ausgewählt"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"WLAN-Roamingsuchen immer zulassen"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Alten DHCP-Client verwenden"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke gedacht. Sie können dein Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps über USB bestätigen"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Überprüft installierte Apps über ADB/ADT auf schädliches Verhalten"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiviert die Bluetooth-Maximallautstärkefunktion, falls auf Remote-Geräten Probleme mit der Lautstärke auftreten, wie beispielsweise übermäßig laute Wiedergabe oder fehlende Kontrolle bei der Steuerung."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokales Terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-App mit Zugriff auf lokale Shell aktivieren"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-Prüfung"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Externe Speichernutzung von Apps erlauben"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ermöglicht es, die Größe aller Aktivitäten an den Mehrfenstermodus anzupassen, unabhängig von den Manifestwerten."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Größe aller Aktivitäten an den Mehrfenstermodus anpassen, unabhängig von den Manifestwerten."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Freiform-Fenster zulassen"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Unterstützt experimentelle Freiform-Fenster."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Experimentelle Freiform-Fenster unterstützen."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Zum Wechseln tippen."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Aktive Dienste"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nachtmodus"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Deaktiviert"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Immer an"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView-Simultanverarbeitung aktivieren"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView-Renderer isoliert ausführen."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-Implementierung"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-Implementierung festlegen"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Die ausgewählte WebView-Implementierung ist deaktiviert. Um sie nutzen zu können, muss sie aktiviert sein. Möchtest du sie aktivieren?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Die ausgewählte WebView-Implementierung ist ungültig, weil die Liste der Implementierungsmöglichkeiten veraltet war. Die Liste sollte jetzt aktualisiert sein."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Zu Dateiverschlüsselung wechseln"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Wechseln…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dateiverschlüsselung wird bereits verwendet."</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Farbkorrektur"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierbei handelt es sich um eine experimentelle Funktion. Dies kann sich auf die Leistung auswirken."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Noch ca. <xliff:g id="TIME">%1$s</xliff:g> verbleibend"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noch etwa <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Wird nicht geladen"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wird nicht geladen"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Vom Administrator deaktiviert"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Durch den Administrator verwaltet"</string>
+ <string name="home" msgid="8263346537524314127">"Startseite"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Vor <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Noch <xliff:g id="ID_1">%1$s</xliff:g> verbleibend"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index e71d4063591a..dd6bb4fae8bb 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Έξοδος μετατροπής κειμένου σε ομιλία"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Ταχύτητα λόγου"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Ταχύτητα με την οποία εκφωνείται το κείμενο"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Τόνος"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Επηρεάζει τον τόνο της σύνθεσης ομιλίας"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Γλώσσα"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Χρήση γλώσσας συστήματος"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Δεν έχει επιλεγεί γλώσσα"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Να επιτρέπεται πάντα η σάρωση Wi-Fi κατά την περιαγωγή"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Χρήση εφαρμογής-πελάτη DHCP παλαιού τύπου"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Απενεργοποίηση απόλυτης έντασης"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Αυτές οι ρυθμίσεις προορίζονται για χρήση κατά την ανάπτυξη. Μπορούν να προκαλέσουν προβλήματα στη λειτουργία της συσκευής και των εφαρμογών σας."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Επαλήθευση εφαρμογών μέσω USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Έλεγχος εφαρμογών που έχουν εγκατασταθεί μέσω ADB/ADT για επιβλαβή συμπεριφορά."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Απενεργοποιεί τη δυνατότητα απόλυτης έντασης του Bluetooth σε περίπτωση προβλημάτων έντασης με απομακρυσμένες συσκευές, όπως όταν υπάρχει μη αποδεκτά υψηλή ένταση ή απουσία ελέγχου."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Τοπική τερματική εφαρμογή"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ενεργοπ.τερμ.εφαρμογής που προσφέρει πρόσβαση στο τοπικό κέλυφος"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Έλεγχος HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Να επιτρέπονται υποχρεωτικά εφαρμογές σε εξωτ.συσ."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό χώρο αποθήκευσης, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ενεργοποιεί την υποστήριξη για πειραματικά παράθυρα ελεύθερης μορφής."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ενεργοποίηση υποστήριξης για πειραματικά παράθυρα ελεύθερης μορφής."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Εφ/κός κωδικός desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Πατήστε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Ενεργό. Πατήστε για εναλλαγή."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Υπηρεσίες που εκτελούνται"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Λειτουργία νύχτας"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Ανενεργό"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Πάντα ενεργό"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Αυτόματο"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ενεργοποίηση WebView πολλαπλών διεργασιών"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Εκτέλεση λειτ.απόδοσης WebView σε μια απομονωμένη διεργασία."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Υλοποίηση WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ορισμός υλοποίησης WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Η επιλεγμένη ενσωμάτωση WebView είναι απενεργοποιημένη και θα πρέπει να ενεργοποιηθεί για να χρησιμοποιηθεί. Θέλετε να την ενεργοποιήσετε;"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Η επιλεγμένη υλοποίηση WebView δεν είναι έγκυρη επειδή η λίστα των επιλογών υλοποίησης δεν είναι ενημερωμένη. Η λίστα θα πρέπει να ενημερωθεί."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Μετατροπή σε κρυπτογράφηση αρχείου"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Μετατροπή…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Με κρυπτογράφηση αρχείου"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Διόρθωση χρωμάτων"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Αυτή η λειτουργία είναι πειραματική και ενδεχομένως να επηρεάσει τις επιδόσεις."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Απομένουν περίπου <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - απομένουν περίπου <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Δεν φορτίζει"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Δεν φορτίζει"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Απενεργοποιήθηκε από το διαχειριστή"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ελέγχονται από το διαχειριστή"</string>
+ <string name="home" msgid="8263346537524314127">"Αρχική οθόνη"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Πριν από <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Απομένουν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index dd152459462c..1ed6dbdd6abf 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Text-to-speech output"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Speech rate"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Speed at which the text is spoken"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affects the tone of the synthesised speech"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Language"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Use system language"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Language not selected"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Use legacy DHCP client"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Enable support for experimental freeform windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tap to change or remove the password for desktop full backups"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Active. Tap to toggle."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Running services"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"View and control currently running services"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Enable multi-process WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Run WebView renderers in an isolated process."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"The chosen WebView implementation is invalid because the list of implementation choices grew stale. The list should now be updated."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disabled by administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+ <string name="home" msgid="8263346537524314127">"Home"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index dd152459462c..1ed6dbdd6abf 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Text-to-speech output"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Speech rate"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Speed at which the text is spoken"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affects the tone of the synthesised speech"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Language"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Use system language"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Language not selected"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Use legacy DHCP client"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Enable support for experimental freeform windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tap to change or remove the password for desktop full backups"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Active. Tap to toggle."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Running services"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"View and control currently running services"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Enable multi-process WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Run WebView renderers in an isolated process."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"The chosen WebView implementation is invalid because the list of implementation choices grew stale. The list should now be updated."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disabled by administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+ <string name="home" msgid="8263346537524314127">"Home"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index dd152459462c..1ed6dbdd6abf 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Text-to-speech output"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Speech rate"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Speed at which the text is spoken"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affects the tone of the synthesised speech"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Language"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Use system language"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Language not selected"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Use legacy DHCP client"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Enable terminal app that offers local shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP checking"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Enable support for experimental freeform windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tap to change or remove the password for desktop full backups"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Active. Tap to toggle."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Running services"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"View and control currently running services"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Enable multi-process WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Run WebView renderers in an isolated process."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"The chosen WebView implementation is invalid because the list of implementation choices grew stale. The list should now be updated."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Not charging"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disabled by administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
+ <string name="home" msgid="8263346537524314127">"Home"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ago"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> left"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 09d569520a22..3f2befd16972 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Salida de texto a voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidad de voz"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidad en la que se habla el texto"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Sonido"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta el tono de la voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usar el idioma del sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma no seleccionado"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP heredado"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estos parámetros de configuración están destinados únicamente a los programadores. Pueden hacer que el dispositivo o sus aplicaciones no funcionen correctamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicaciones por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar que las aplicaciones instaladas mediante ADB/ADT no ocasionen daños"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inhabilita la función de volumen absoluto de Bluetooth si se producen problemas de volumen con dispositivos remotos (por ejemplo, volumen demasiado alto o falta de control)."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Habilitar aplicac. de terminal que ofrece acceso al shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permisos en almacenamiento externo"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Cualquier aplicación puede escribirse en una memoria externa, independientemente de los valores del manifiesto."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permitir que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Habilita la admisión de ventanas de forma libre experimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Habilitar la admisión de ventanas de forma libre experimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseñas"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Presiona para cambiar o quitar la contraseña de las copias de seguridad completas de tu escritorio."</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Activa. Presiona para activar o desactivar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"En ejecución"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ver y controlar servicios actuales en ejecución"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Habilitar multiproceso WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ejecutar procesadores de WebView en un proceso aislado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar la implementación de WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementación de WebView que elegiste está inhabilitada. Debes habilitarla para poder usarla. ¿Quieres hacerlo?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementación de WebView elegida no es válida debido a que las opciones de la lista de implementación están inactivas. Debes actualizar la lista."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a encriptación de archivo"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está encriptado"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección de color"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar el rendimiento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Falta <xliff:g id="TIME">%1$s</xliff:g> aproximadamente"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g>: alrededor de <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"No se está cargando."</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"No se realiza la carga"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Inhabilitada por el administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
+ <string name="home" msgid="8263346537524314127">"Página principal"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Falta <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 79c35e1fc14d..57a749d5c5b4 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Síntesis de voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidad de la voz"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidad a la que se lee el texto"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tono"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta al tono de la síntesis de voz"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma del sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma no seleccionado"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP heredado"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estos ajustes están destinados únicamente a los desarrolladores. Pueden provocar que el dispositivo o las aplicaciones no funcionen correctamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicaciones por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprueba las aplicaciones instaladas mediante ADB/ADT para detectar comportamientos dañinos"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inhabilita la función de volumen absoluto de Bluetooth si se producen problemas de volumen con dispositivos remotos (por ejemplo, volumen demasiado alto o falta de control)."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Habilitar aplicación de terminal que ofrece acceso a shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación de HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Parpadear si las aplicaciones tardan mucho en el thread principal"</string>
<string name="pointer_location" msgid="6084434787496938001">"Ubicación del puntero"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Superponer los datos de las pulsaciones en la pantalla"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Mostrar la ubicación de los toques en la pantalla"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Cambios de superficie"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Actualizar superficies de ventana al actualizarse"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Actualizaciones GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicaciones de forma externa"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hace que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo, independientemente de los valores definidos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar el ajuste de tamaño de las actividades"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Permite utilizar ventanas de forma libre experimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Habilita la opción para utilizar ventanas de forma libre experimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseña para copias de ordenador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Las copias de seguridad completas de ordenador no están protegidas"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar o quitar la contraseña de las copias de seguridad completas del escritorio"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de seguridad establecida"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al establecer la contraseña de seguridad"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Colores optimizados para contenido digital"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Aplicaciones inactivas"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Inactiva. Toca para alternar."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Activa. Toca para alternar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Servicios en ejecución"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ver y controlar los servicios en ejecución"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Habilitar WebView multiproceso"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ejecuta procesadores de WebView en un proceso aislado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Establecer implementación de WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementación de WebView seleccionada está inhabilitada y debes habilitarla para utilizarla. ¿Quieres hacerlo?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementación de WebView seleccionada no es válida porque la lista de opciones de implementación no estaba activada. Esta ya debería estar actualizada."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a cifrado de archivo"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está cifrado"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección del color"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar al rendimiento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Tiempo restante (aproximado): <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quedan <xliff:g id="TIME">%2$s</xliff:g> aproximadamente"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la batería"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"No se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"No se está cargando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Inhabilitada por el administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
+ <string name="home" msgid="8263346537524314127">"Inicio"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Tiempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 2f9532be5616..27546ce184d8 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Kõnesünteesi väljund"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Kõnekiirus"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Teksti rääkimise kiirus"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Helikõrgus"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Mõjutab sünteesitud kõne tooni"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Keel"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Süsteemi keele kasutamine"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Keelt pole valitud"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luba alati WiFi-rändluse skannimine"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"DHCP pärandkliendi kasutamine"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Need seaded on mõeldud ainult arendajatele. Need võivad põhjustada seadme ja seadmes olevate rakenduste rikkeid või valesti toimimist."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Kinnita rakendus USB kaudu"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolli, kas ADB/ADT-ga installitud rakendused on ohtlikud."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Keelatakse Bluetoothi absoluutse helitugevuse funktsioon, kui kaugseadmetega on helitugevuse probleeme (nt liiga vali heli või juhitavuse puudumine)."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Kohalik terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Luba kohalikku turvalist juurdepääsu pakkuv terminalirakendus"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontrollimine"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Luba rakendused välises salvestusruumis"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lubab rakendusi kirjutada välisesse salvestusruumi olenemata manifesti väärtustest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Muuda tegevuste suurused muudetavaks"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Muudab kõigi tegevuste suurused mitme aknaga vaates olenemata manifesti väärtustest muudetavaks."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Muudetakse kõigi tegevuste suurused mitme aknaga vaates muudetavaks (manifesti väärtustest olenemata)."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Luba vabas vormis aknad"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Lubatakse katseliste vabas vormis akende tugi."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Lubatakse katseliste vabavormis akende tugi."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Arvutivarunduse parool"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Täielikud arvutivarundused pole praegu kaitstud"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Puudutage täielike arvutivarunduste parooli muutmiseks või eemaldamiseks"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiivne. Puudutage vahetamiseks."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Käitatud teenused"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Öörežiim"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Keelatud"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Alati sees"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automaatne"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Luba mitme protsessiga WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView\' renderdajad käitatakse eraldi protsessis."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView\' rakendamine"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView\' rakendamise seadistamine"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Valitud WebView\' rakendamisviis on keelatud ja see tuleb kasutamiseks lubada. Kas soovite selle lubada?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Valitud WebView\' rakendamine on sobimatu, kuna rakendamisvalikute loend aegus. Loendit tuleb nüüd värskendada."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Teisendamine failikrüpteeringuga andmeteks"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Teisenda …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Juba failikrüpteeringuga"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Värviparandus"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"See funktsioon on katseline ja võib mõjutada toimivust."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Umbes <xliff:g id="TIME">%1$s</xliff:g> on jäänud"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – jäänud on umbes <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, kuni aku on täis"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei lae"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täis"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administraator on keelanud"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Juhib administraator"</string>
+ <string name="home" msgid="8263346537524314127">"Avaekraan"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> tagasi"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> on jäänud"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 8cd36faf2228..dd0e1cbb050c 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -99,8 +99,10 @@
<string name="launch_defaults_none" msgid="4241129108140034876">"Ez dago hobespen lehenetsirik ezarrita"</string>
<string name="tts_settings" msgid="8186971894801348327">"Testua ahots bihurtzeko eginbidearen ezarpenak"</string>
<string name="tts_settings_title" msgid="1237820681016639683">"Testua ahots bihurtzeko eginbidearen irteera"</string>
- <string name="tts_default_rate_title" msgid="6030550998379310088">"Hizketa-abiadura"</string>
+ <string name="tts_default_rate_title" msgid="6030550998379310088">"Hizketaren abiadura"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Testua zer abiaduran esaten den"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonua"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Hizketa sintetizatuaren tonuari eragiten dio"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Hizkuntza"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Erabili sistemaren hizkuntza"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Ez da hizkuntza hautatu"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Onartu beti ibiltaritzan Wi-Fi sareak bilatzea"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Erabili aurreko bertsioko DHCP bezeroa"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ezarpen hauek garapen-xedeetarako pentsatu dira soilik. Baliteke ezarpenen eraginez gailua matxuratzea edo funtzionamendu okerra izatea."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Egiaztatu USBko aplikazioak."</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak antzemateko."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desgaitu egiten du Bluetooth bidezko bolumen absolutuaren eginbidea urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Tokiko terminala"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Gaitu tokiko shell-sarbidea duen terminal-aplikazioa"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP egiaztapena"</string>
@@ -224,7 +228,7 @@
<string name="debug_layout" msgid="5981361776594526155">"Erakutsi diseinuaren mugak"</string>
<string name="debug_layout_summary" msgid="2001775315258637682">"Erakutsi kliparen mugak, marjinak, etab."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Behartu eskuin-ezker norabidea."</string>
- <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuinetik ezkerrerakoa izatera eskualdeko ezarpen guztiekin."</string>
+ <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuin-ezker izatera eskualdeko ezarpen guztiekin."</string>
<string name="show_cpu_usage" msgid="2389212910758076024">"Erakutsi PUZ erabilera"</string>
<string name="show_cpu_usage_summary" msgid="2113341923988958266">"PUZ erabilera erakusten duen pantaila-gainjartzea"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Behartu GPU errendatzea"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Behartu aplikazioak onartzea kanpoko biltegian"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Behartu jardueren tamaina doitu ahal izatea"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifestuan jartzen duena jartzen duela ere, jarduera guztien tamaina doitzeko aukera ematen du, hainbat leihotan erabili ahal izan daitezen."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Eman aukera jarduera guztien tamaina doitzeko, hainbat leihotan erabili ahal izan daitezen, manifestuan jartzen duena jartzen duela ere."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Gaitu estilo libreko leihoak"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Estilo libreko leiho esperimentalak onartzen ditu."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Onartu estilo libreko leiho esperimentalak."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Tokiko babeskop. pasahitza"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ordenagailuko eduki guztiaren babeskopia egiteko erabiltzen den pasahitza aldatzeko edo kentzeko, sakatu hau"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktibo. Aldatzeko, sakatu hau."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Abian diren zerbitzuak"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ikusi eta kontrolatu unean abian diren zerbitzuak"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Gau modua"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Desgaituta"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Beti aktibatuta"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatikoa"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Gaitu prozesu anitzeko WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Exekutatu WebView errendatzaileak prozesu isolatu batean."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Desgaituta dago aukeratu den WebView inplementazioa. Erabili nahi izanez gero, gaitu egin behar duzu. Gaitu nahi al duzu?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Aukeratutako WebView inplementazioak ez du balio inplementazioen aukeren zerrenda zaharkituta gelditu delako. Zerrenda eguneratu behar da."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Eman fitxategietan oinarritutako enkriptatzea"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Enkriptatu…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fitxategietan oinarritutako enkriptatzea dauka dagoeneko"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kolore-zuzenketa"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g> inguru guztiz kargatu arte"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> inguru. <xliff:g id="TIME">%2$s</xliff:g> geratzen d(ir)a"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ez da kargatzen ari"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ez da kargatzen ari"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Beteta"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administratzaileak desgaitu du"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administratzaileak kontrolatzen du"</string>
+ <string name="home" msgid="8263346537524314127">"Hasierako pantaila"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Duela <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> guztiz kargatu arte"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index dd6d0c4664ef..a683c5572b10 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"خروجی تبدیل متن به گفتار"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"سرعت گفتار"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"سرعتی که متن خوانده می‌شود"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"زیر و بمی صدا"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"بر صدای متن گفته شده تأثیر می‌گذارد"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"زبان"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"استفاده از زبان سیستم"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"زبان انتخاب نشده است"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏اسکن‌های رومینگ Wi‑Fi همیشه مجاز است"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"‏استفاده از کلاینت DHCP قدیمی"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"داده سلولی همیشه فعال"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"غیرفعال کردن میزان صدای مطلق"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"این تنظیمات فقط برای برنامه‌نویسی در نظر گرفته شده است. ممکن است استفاده از این تنظیمات موجب خرابی یا عملکرد نادرست دستگاه یا برنامه‌های شما شود."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏تأیید برنامه‌های نصب شده از طریق USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏برنامه‌های نصب شده از طریق ADB/ADT را ازنظر رفتار مخاطره‌آمیز بررسی کنید."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"در صورت وجود مشکل میزان صدا با دستگاه‌های راه دور مثل میزان صدای بلند ناخوشایند یا عدم کنترل صدا، قابلیت میزان صدای کامل بلوتوث را غیرفعال کنید."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ترمینال محلی"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"فعال کردن ترمینال برنامه‌ کاربردی که دسترسی به برنامه محلی را پیشنهاد می‌کند"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"‏بررسی HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"چشمک زدن صفحه هنگام انجام عملیات طولانی توسط برنامه‌ها در رشته اصلی"</string>
<string name="pointer_location" msgid="6084434787496938001">"محل اشاره‌گر"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"هم‌پوشانی صفحهٔ نمایش با نمایش داده لمسی فعلی"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"نمایش ضربه‌ها"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"نمایش بازخورد تصویری برای ضربه‌ها"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"نمایش به‌روزرسانی سطح"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"هنگام به‌روزرسانی سطوح پنجره همه فلش شوند"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"‏نمایش به روزرسانی‌های نمای GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"اجازه اجباری به برنامه‌های دستگاه ذخیره خارجی"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامه‌ای را برای نوشتن در حافظه خارجی واجد شرایط می‌کند"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیت‌ها به قابل تغییر اندازه بودن"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"بدون درنظر گرفتن مقادیر مانیفست، همه فعالیت‌ها را برای چندپنجره قابل تغییر اندازه می‌کند."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"بدون توجه به مقادیر مانیفست، اندازه همه فعالیت‌ها برای حالت چند پنجره‌ای می‌تواند تغییر کند."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"فعال کردن پنجره‌های آزاد"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"پشتیبانی برای پنجره‌های آزاد آزمایشی را امکان‌پذیر می‌کند"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"فعال کردن پشتیبانی برای پنجره‌های آزاد آزمایشی."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"گذرواژه پشتیبان‌گیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبان‌گیری کامل رایانه درحال حاضر محافظت نمی‌شود"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"برای تغییر یا حذف گذرواژه برای نسخه‌های پشتیبان کامل رایانه‌ای ضربه بزنید"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"گذرواژه جدید نسخهٔ پشتیبان تنظیم شد"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"گذرواژه جدید و تأیید آن با یکدیگر مطابقت ندارند"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"گذرواژه پشتیبان‌گیری تنظیم نشد"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"رنگ‌های بهینه‌شده برای محتوای دیجیتالی"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"برنامه‌های غیرفعال"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"غیرفعال. برای تغییر حالت ضربه بزنید."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال. برای تغییر حالت ضربه بزنید."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"سرویس‌های در حال اجرا"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"مشاهده و کنترل سرویس‌های در حال اجرای فعلی"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"حالت شب"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"غیرفعال است"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"همیشه روشن"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"‏فعال کردن WebView چند پردازشی"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"‏اجرای تولیدکننده تصویر WebView در یک پردازش مجزا."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"‏اجرای WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏تنظیم اجرای WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏پیاده‌سازی WebView انتخاب‌شده غیرفعال شده است و برای استفاده شدن باید فعال شود؛ می‌خواهید آن را فعال کنید؟"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"‏اجرای WebView انتخابی نامعتبر است چون فهرست گزینه‌های اجرای انتخابی قدیمی شده است. این فهرست اکنون باید به‌روزرسانی شود."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"تصحیح رنگ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"این قابلیت آزمایشی است و ممکن است عملکرد را تحت تأثیر قرار دهد."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> باقی مانده است"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تقریباً ‏<xliff:g id="TIME">%2$s</xliff:g> باقی مانده است"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"شارژ نمی‌شود"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"شارژ نمی‌شود"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"پر"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"سرپرست آن را غیرفعال کرده است"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"توسط سرپرست سیستم کنترل می‌شود"</string>
+ <string name="home" msgid="8263346537524314127">"صفحه اصلی"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی مانده است"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 2f3f5da9a675..bb27bcf624de 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Tekstistä puheeksi -toisto"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Puheen nopeus"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Tekstin puhumisnopeus"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Äänenkorkeus"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Tämä vaikuttaa syntetisoidun puheen äänensävyyn."</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Kieli"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Käytä järjestelmän kieltä"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Kieltä ei ole valittu"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Salli Wi-Fi-verkkovierailuskannaus aina"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Käytä vanhaa DHCP-asiakassovellusta"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Nämä asetukset on tarkoitettu vain kehityskäyttöön, ja ne voivat aiheuttaa haittaa laitteellesi tai sen sovelluksille."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Tarkista USB:n kautta asennetut"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tarkista ADB:n/ADT:n kautta asennetut sovellukset haitallisen toiminnan varalta."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Bluetoothin yleinen äänenvoimakkuuden säätö poistetaan käytöstä ongelmien välttämiseksi esimerkiksi silloin, kun laitteen äänenvoimakkuus on liian kova tai sitä ei voi säätää."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Paikallinen pääte"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ota käyttöön päätesov. joka mahdollistaa paikall. liittymäkäytön"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-tarkistus"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Salli aina ulkoinen tallennus"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta riippumatta"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pakottaa kaikki toiminnot hyväksymään koon muuttamisen rinnakkaisnäkymään luettelon arvoista riippumatta."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Pakota kaikki toiminnot hyväksymään koon muuttaminen usean ikkunan tilassa luettelon arvoista riippumatta."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ota käyttöön vapaamuotoiset ikkunat"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ottaa käyttöön kokeellisten vapaamuotoisten ikkunoiden tuen."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ota kokeellisten vapaamuotoisten ikkunoiden tuki käyttöön."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Varmuuskop. salasana"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Vaihda tai poista tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla."</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Käytössä. Poista käytöstä koskettamalla."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Käynnissä olevat palvelut"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Tarkastele ja hallitse käynnissä olevia palveluita"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Yötila"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Ei käytössä"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Aina käytössä"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automaattinen"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView\'n usean prosessin tila"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Suorita WebView\'n hahmontajat erillisinä prosesseina."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-käyttöönotto"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Määritä WebView-käyttöönotto"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Valittu WebView-käyttöönotto on poistettu käytöstä. Haluatko ottaa sen käyttöön?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Valittu WebView-toteutus ei kelpaa, sillä toteutusvaihtoehtojen lista vanhentui. Listan pitäisi nyt olla ajan tasalla."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Muunna tiedostojen salaukseksi"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Muunna…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Tiedostot on jo salattu."</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Värikorjaus"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tämä ominaisuus on kokeellinen ja voi vaikuttaa suorituskykyyn."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Noin <xliff:g id="TIME">%1$s</xliff:g> jäljellä"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ei laturissa"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ei laturissa"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täynnä"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Järjestelmänvalvojan käytöstä poistama"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
+ <string name="home" msgid="8263346537524314127">"Aloitusnäyttö"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> sitten"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> jäljellä"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 679d209233ef..7ca3f8952866 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Sortie de la synthèse vocale"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Cadence"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Vitesse à laquelle le texte est énoncé"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Touche le ton utilisé pour la synthèse vocale"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Langue"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Utiliser la langue du système"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Langue non sélectionnée"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utiliser l\'ancien client DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu par Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Vérification HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Afficher un cadre rouge si le thread principal reste occupé"</string>
<string name="pointer_location" msgid="6084434787496938001">"Emplacement du curseur"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Superposition écran indiquant données actuelles"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Afficher éléments sélect."</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Afficher repère visuel pour éléments sélectionnés"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Affich. mise à jour surface"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Faire clignoter les surfaces à chaque mise à jour"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Afficher mises à jour GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forcer l\'autor. d\'applis sur stockage externe"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Touchez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur ordinateur."</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Couleurs optimisées pour le contenu numérique"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Applications inactives"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Application inactive. Touchez ici pour l\'activer."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Application active. Touchez ici pour la désactiver."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Afficher et contrôler les services en cours d\'exécution"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Mode Nuit"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Toujours actif"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activer WebView multiprocessus"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Exécuter moteurs de rendu WebView dans un processus isolé."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La mise en œuvre WebView sélectionnée est désactivée. Vous devez l\'activer pour l\'utiliser. Souhaitez-vous l\'activer?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La mise en œuvre WebView sélectionnée n\'est pas valide, car la liste de sélections de mises en œuvre est désormais obsolète. Cette liste devrait être mise à jour."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir en chiffrement basé sur un fichier"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Déjà chiffré par un fichier"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction des couleurs"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut toucher les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> %% – Temps restant : environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> %% (chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"N\'est pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"N\'est pas en charge"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pleine"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
+ <string name="home" msgid="8263346537524314127">"Accueil"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Durée restante :<xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 556edaf38d4d..adfc7a343d67 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Synthèse vocale"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Cadence"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Vitesse à laquelle le texte est énoncé"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Affecte le ton utilisé pour la synthèse vocale"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Langue"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Utiliser la langue du système"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Langue non sélectionnée"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utiliser l\'ancien client DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu du Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activer l\'application Terminal permettant l\'accès au shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Vérification HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forcer disponibilité stockage externe pour applis"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rend possible enregistrement de toute appli sur espace stockage externe, indépendamment valeurs fichier manifeste."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permettre de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Application active. Appuyez ici pour la désactiver."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Afficher et contrôler les services en cours d\'exécution"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Mode Nuit"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Toujours activé"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activer WebView multiprocessus"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Exécuter moteurs de rendu WebView dans un processus isolé."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La mise en œuvre WebView sélectionnée est désactivée. Vous devez l\'activer pour l\'utiliser. Souhaitez-vous l\'activer ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La mise en œuvre WebView sélectionnée n\'est pas valide, car la liste de sélections de mises en œuvre est désormais obsolète. Cette liste ne doit pas être mise à jour."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir en chiffrement basé sur un fichier"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Déjà chiffré via un fichier"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction couleur"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut affecter les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>."</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g> environ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> (chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Débranchée"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
+ <string name="home" msgid="8263346537524314127">"Accueil"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Il reste <xliff:g id="ID_1">%1$s</xliff:g>."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index ca49d2d9153b..867a29d9f70a 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Síntese de voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidade da fala"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade á que se di o texto"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta ao ton da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizar idioma do sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma non seleccionado"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre buscas de itinerancia da wifi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP herdado"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Esta configuración só está destinada á programación. Esta pode provocar que o dispositivo e as aplicacións fallen ou se comporten incorrectamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicacións por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar as aplicacións instaladas a través de ADB/ADT para detectar comportamento perigoso."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva a función do volume absoluto do Bluetooth en caso de que se produzan problemas de volume cos dispositivos remotos, como volume demasiado alto ou falta de control."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activa a aplicación terminal que ofrece acceso ao shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Comprobación HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Pestanexa se aplicacións tardan moito no proceso principal"</string>
<string name="pointer_location" msgid="6084434787496938001">"Localización do punteiro"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Superpoñer datos dos toques na pantalla"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Mostrar toques"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Mostra a información visual dos toques"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Cambios de superficie"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Iluminar superficies de ventás ao actualizarse"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Actualizacións GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicacións de forma externa"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Fai que calquera aplicación se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activar ventás de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguridade de ordenador completas non están protexidas"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo contrasinal de copia de seguranza definido"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"O contrasinal novo e a confirmación non coinciden"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Erro ao definir un contrasinal de copia de seguranza"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Cores optimizadas para contido dixital"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Aplicacións inactivas"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Aplicación inactiva. Toca para alternar a configuración."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aplicación activa. Toca para alternar a configuración."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Servizos en execución"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ver e controlar servizos actualmente en execución"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modo nocturno"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Desactivado"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sempre activada"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activar WebView multiproceso"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executa os procesadores de WebView nun proceso illado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementación de WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementación de WebView escollida está desactivada e, para poder usala, debe estar activada. Queres activala?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"A implementación de WebView seleccionada non é válida porque a lista de opcións de implementación estaba inactiva. A lista xa debería estar actualizada."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter no encriptado baseado en ficheiros"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Xa se encriptou o ficheiro"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección da cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función é experimental e pode afectar ao rendemento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Duración aproximada de <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - faltan aproximadamente <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Non se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non está cargando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desactivado polo administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Opción controlada polo administrador"</string>
+ <string name="home" msgid="8263346537524314127">"Inicio"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Hai <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Tempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 2aa8c5f295ec..54e7288b2224 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"ટેક્સ્ટ ટુ સ્પીચ આઉટપુટ"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"વાણી દર"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ટેક્સ્ટ બોલાયેલ છે તે ઝડપ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"પિચ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"સિન્થેસાઇઝ કરેલ વાણીના ટોન પર અસર કરે છે"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ભાષા"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"સિસ્ટમ ભાષાનો ઉપયોગ કરો"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ભાષા પસંદ કરેલ નથી"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"હંમેશા Wi‑Fi રોમ સ્કૅન્સને મંજૂરી આપો"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"લેગેસી DHCP ક્લાઇન્ટનો ઉપયોગ કરો"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"સેલ્યુલર ડેટા હંમેશા સક્રિય"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"આ સેટિંગ્સ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ઉપકરણ અને તેના પરની એપ્લિકેશન્સનાં ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB પર એપ્લિકેશનો ચકાસો"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"હાનિકારક વર્તણૂંક માટે ADB/ADT મારફતે ઇન્સ્ટોલ કરવામાં આવેલી એપ્લિકેશનો તપાસો."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"રિમોટ ઉપકરણોમાં વધુ પડતું ઊંચું વૉલ્યૂમ અથવા નિયંત્રણની કમી જેવી વૉલ્યૂમની સમસ્યાઓની સ્થિતિમાં Bluetooth ચોક્કસ વૉલ્યૂમ સુવિધાને અક્ષમ કરે છે."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"સ્થાનિક ટર્મિનલ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"સ્થાનિક શેલ અ‍ૅક્સેસની ઑફર કરતી ટર્મિનલ એપ્લિકેશનને સક્ષમ કરો"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP તપાસણી"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"બાહ્ય પર એપ્લિકેશનોને મંજૂરી આપવાની ફરજ પાડો"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવે છે, મેનીફેસ્ટ મુલ્યોને ધ્યાનમાં લીધા સિવાય."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"મૅનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવો."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ફ્રિફોર્મ વિંડોઝ સક્ષમ કરો"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક ફ્રિફોર્મ વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"પ્રાયોગિક ફ્રિફોર્મ વિંડોઝ માટે સમર્થનને સક્ષમ કરો."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ડેસ્કટૉપ બેકઅપ પાસવર્ડ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ હાલમાં સુરક્ષિત નથી"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટૅચ કરો"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"સક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"ચાલુ સેવાઓ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"રાત્રિ મોડ"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"અક્ષમ કરેલ"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"હંમેશાં ચાલુ"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"સ્વચલિત"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"મલ્ટિપ્રોસેસ WebView સક્ષમ કરો"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"પૃથક પ્રક્રિયામાં WebView રેંડરર્સ ચલાવો."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView અમલીકરણ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView અમલીકરણ સેટ કરો"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"પસંદ કરેલ WebView અમલીકરણ અક્ષમ કરેલ છે અને ઉપયોગ કરવા માટે સક્ષમ કરવું આવશ્યક છે, શું તમે તેને સક્ષમ કરવા માગો છો?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"પસંદ કરેલ WebView અમલીકરણ અમાન્ય છે કારણ કે અમલીકરણ પસંદગીઓની સૂચિમાં જૂની છે. સૂચિ હવે અપડેટ કરવી જોઈએ."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ફાઇલ એન્ક્રિપ્શનમાં રૂપાંતરિત કરો"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"રૂપાંતરિત કરો..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ફાઇલ પહેલેથી જ એન્ક્રિપ્ટ કરેલ છે"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"રંગ સુધારણા"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"આ સુવિધા પ્રાયોગિક છે અને કામગીરી પર અસર કરી શકે છે."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"અંદાજે. <xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - આશરે <xliff:g id="TIME">%2$s</xliff:g> બાકી"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"સંપૂર્ણ થવામાં <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"પૂર્ણ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"વ્યવસ્થાપક દ્વારા અક્ષમ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
+ <string name="home" msgid="8263346537524314127">"હોમ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> પહેલાં"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> બાકી"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 8f382c5a26d6..a7e838e914a0 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"लेख को सुनें"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"बोली दर"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"बोलने की गति तय करें"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"पिच"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"कृत्रिम बोली के लहजे को प्रभावित करता है"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"भाषा"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"सिस्‍टम भाषा का उपयोग करें"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"भाषा नहीं चुनी गई है"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"हमेशा वाई-फ़ाई रोम स्कैन करने दें"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"लीगेसी DHCP क्‍लाइंट"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा हमेशा सक्रिय"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"पूर्ण वॉल्यूम अक्षम करें"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ये सेटिंग केवल विकास संबंधी उपयोग के प्रयोजन से हैं. वे आपके डिवाइस और उस पर स्‍थित ऐप्स को खराब कर सकती हैं या उनके दुर्व्यवहार का कारण हो सकती हैं."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB पर ऐप्स सत्यापित करें"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT के द्वारा इंस्टॉल किए गए ऐप्स जांचें."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूरस्थ डिवाइस के साथ वॉल्यूम की समस्याओं जैसे अस्वीकार्य तेज़ वॉल्यूम या नियंत्रण की कमी की स्थिति में ब्लूटूथ पूर्ण वॉल्यूम सुविधा को अक्षम करता है."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"स्थानीय शेल एक्सेस ऑफ़र करने वाला टर्मिनल ऐप्स सक्षम करें"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जांच"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ऐप्स को बाहरी मेमोरी पर बाध्‍य करें"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"इससे कोई भी ऐप मेनिफेस्‍ट मान अनदेखा करके, बाहरी मेमोरी पर लिखने योग्‍य बन जाता है"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"एकाधिक-विंडो के लिए सभी गतिविधियों के आकार को बदले जाने योग्य बनाता है, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"सभी गतिविधियों को एकाधिक विंडो के लिए आकार बदलने योग्य बनाएं, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करती है."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करें."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्‍कटॉप बैकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्‍कटॉप पूर्ण बैकअप वर्तमान में सुरक्षित नहीं हैं"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉप के पूर्ण बैकअप का पासवर्ड बदलने या निकालने के लिए टैप करें"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करने पर टैप करें."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"चल रही सेवाएं"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"वर्तमान में चल रही सेवाओं को देखें और नियंत्रित करें"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"रात्रि मोड"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"अक्षम"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"हमेशा चालू"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"मल्टीप्रोसेस WebView सक्षम करें"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"किसी अलग प्रक्रिया में WebView रेंडरर चलाएं."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट करें"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"चुना गया WebView कार्यान्वयन अक्षम है और उसे उपयोग करने के लिए सक्षम किया जाना आवश्यक है, क्या आप उसे सक्षम करना चाहते हैं?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"चुना गया WebView कार्यान्वयन अमान्य है क्योंकि कार्यान्वयन विकल्पों की सूची पुरानी हो चुकी है. सूची को अब अपडेट किया जाना चाहिए."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फ़ाइल एन्क्रिप्शन में रूपांतरित करें"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करें..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फ़ाइल पहले से एन्क्रिप्ट की हुई है"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"रंग सुधार"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यह सुविधा प्रायोगिक है और निष्पादन को प्रभावित कर सकती है."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग <xliff:g id="TIME">%2$s</xliff:g> शेष"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूरी होने तक"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"व्यवस्थापक के द्वारा अक्षम किया गया"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"व्यवस्थापक द्वारा नियंत्रित"</string>
+ <string name="home" msgid="8263346537524314127">"होम"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहले"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शेष"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 266e4d71d573..f315fe930d06 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Pretvaranje teksta u govor"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina kojom se izgovara tekst"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Visina glasa"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utječe na ton sintetiziranog govora"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"upotrijebi jezik sustava"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije odabran"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopusti slobodno traženje Wi-Fi mreže"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Upotrebljavaj stari DHCP klijent"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove su postavke namijenjene samo razvojnim programerima. One mogu uzrokovati kvar ili neželjeno ponašanje vašeg uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Potvrdi aplikacije putem USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerite uzrokuju li aplikacije instalirane putem ADB-a/ADT-a poteškoće."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućuje Bluetoothovu značajku apsolutne glasnoće ako udaljeni uređaji imaju poteškoća sa zvukom, kao što su, primjerice, neprihvatljiva glasnoća ili nepostojanje kontrole."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplikaciju terminala koja nudi pristup lokalnoj ovojnici"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provjera"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Prisilno dopusti aplikacije u vanjskoj pohrani"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veličina svih aktivnosti može se mijenjati za više prozora, neovisno o vrijednostima manifesta."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući mijenjanje veličine svih aktivnosti za više prozora, neovisno o vrijednostima manifesta."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore slobodnog oblika"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućuje podršku za eksperimentalne prozore slobodnog oblika."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogući podršku za eksperimentalne prozore slobodnog oblika."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaporka sigurnosne kopije"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promijenili ili uklonili zaporku za potpune sigurnosne kopije na računalu"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dodirnite da biste to promijenili."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Pogledajte i nadzirite pokrenute procese"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Noćni način rada"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Uvijek uključeno"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatska"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogući višeprocesni WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokreni ispunjivače WebViewa u izoliranim procesima."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacija WebViewa"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Postavi implementaciju WebViewa"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Odabrana implementacija WebViewa onemogućena je i morate je omogućiti da biste je mogli upotrebljavati. Želite li je omogućiti?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Odabrana implementacija WebViewa nije važeća jer je popis odabira za implementaciju zastario. Popis se treba ažurirati."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u enkripciju datoteka"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvori…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Enkripcija datoteka već je izvršena"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boje"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova je značajka eksperimentalna i može utjecati na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – još približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ne puni se"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolira administrator"</string>
+ <string name="home" msgid="8263346537524314127">"Početni zaslon"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index f2dc5ce92adb..9b62eb1274d0 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Szövegfelolvasás"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Beszéd sebessége"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"A szöveg kimondásának sebessége"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Hangmagasság"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Az előállított beszédhang hangszínét befolyásolja"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Nyelv"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"A rendszer nyelvének használata"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nincs nyelv kiválasztva"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi-roaming ellenőrzésének engedélyezése mindig"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Korábbi DHCP-kliens használata"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ezek a beállítások csak fejlesztői használatra szolgálnak. Használatuk esetén eszköze vagy alkalmazásai meghibásodhatnak, illetve nem várt módon viselkedhetnek."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB-n keresztül telepített alkalmazások ellenőrzése"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Az ADB/ADT útján telepített alkalmazások ellenőrzése kártékony viselkedésre."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Letiltja a Bluetooth abszolút hangerő funkcióját a távoli eszközökkel kapcsolatos hangerőproblémák – például elfogadhatatlanul magas vagy nem vezérelhető hangerő – esetén."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Helyi végpont"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Végalkalmazás engedélyezése a helyi rendszerhéj eléréséhez"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ellenőrzés"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Külső tárhely alkalmazásainak engedélyezése"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lehetővé teszi, hogy külső tárhelyre lehessen írni"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tevékenységek átméretezésének kényszerítése"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Lehetővé teszi, hogy az összes tevékenység átméretezhető legyen a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Legyen az összes tevékenység átméretezhető a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Szabad formájú ablakok engedélyezése"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Engedélyezi a kísérleti jellegű, szabad formájú ablakok támogatását."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Kísérleti, szabad formájú ablakok támogatásának engedélyezése."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Asztali mentés jelszava"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Koppintson ide az asztali teljes mentések jelszavának módosításához vagy eltávolításához"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Bekapcsolva. Koppintson ide a váltáshoz."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Futó szolgáltatások"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Éjszakai mód"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Kikapcsolva"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Mindig bekapcsolva"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatikus"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Többfolyamatos WebView indítása"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView-megjelenítők futtatása külön folyamatként."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-megvalósítás"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-megvalósítás beállítása"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A kiválasztott WebView-megvalósítás le van tiltva, a használathoz viszont engedélyezni kell. Szeretné engedélyezni?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"A kiválasztott WebView-megvalósítás érvénytelen, mert a megvalósítási lehetőségeket tartalmazó lista elévült. A listát elvileg már frissítették."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertálás fájlalapú titkosításra"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertálás…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Már fájlalapú titkosítást használ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Színkorrekció"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ez egy kísérleti funkció, és hatással lehet a teljesítményre."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kb. <xliff:g id="TIME">%1$s</xliff:g> van hátra"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – kb. <xliff:g id="TIME">%2$s</xliff:g> van hátra"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttség eléréséig"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nem tölt"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nem töltődik"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Feltöltve"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Letiltva a rendszergazda által"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Rendszergazda által irányítva"</string>
+ <string name="home" msgid="8263346537524314127">"Főoldal"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Ennyi ideje: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> van hátra"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index bd0a33906feb..36a3813833fc 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Գրվածքից խոսք ելք"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Խոսքի գնահատական"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Տեքստի արտասանման արագությունը"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Բարձրություն"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ազդում է սինթեզած խոսքի ձայներանգի վրա"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Լեզու"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Օգտագործել համակարգի լեզուն"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Լեզուն ընտրված չէ"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Միշտ թույլատրել Wi‑Fi ռոումինգի որոնումը"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Օգտագործել DHCP ծրագրի ավելի հին տարբերակները"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Բջջային տվյալները՝ միշտ ակտիվացրած"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Անջատել ձայնի բացարձակ ուժգնությունը"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Այս կարգավորումները միայն ծրագրավորման նպատակների համար են նախատեսված: Դրանք կարող են խանգարել ձեր սարքի կամ ծրագրի աշխատանքին:"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Ստուգել հավելվածները USB-ի նկատմամբ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Ստուգեք տեղադրված հավելվածը ADB/ADT-ի միջոցով կասկածելի աշխատանքի պատճառով:"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ՝ երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Տեղային տերմինալ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Միացնել տերմինալային հավելվածը, որն առաջարկում է մուտք տեղային խեցի"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ստուգում"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Լուսավորել էկրանը` ծրագրի գլխավոր շղթայի վրա երկար աշխատելիս"</string>
<string name="pointer_location" msgid="6084434787496938001">"Նշիչի տեղադրություն"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ հպման տվյալները"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Ցույց տալ հպումները"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Ցույց տալ հպումների տեսանելի արձագանքը"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Ցույց տալ մակերեսի թարմացումները"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Թող պատուհանի ամբողջական մակերեսները առկայծեն, երբ թարմացվում են"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Ցույց տալ GPU տեսքի թարմացումները"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Միշտ թույլատրել ծրագրեր արտաքին պահեստում"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ակտիվացնում է կամայական ձևի փորձնական պատուհանների աջակցումը:"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Միացնել ազատ ձևի փորձնական պատուհանների աջակցումը:"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Հպեք՝ աշխատասեղանի ամբողջական պահուստավորման գաղտնաբառը փոխելու կամ հեռացնելու համար"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Պահուստավորման նոր գաղտնաբառը սահմանված է"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Նոր գաղտնաբառը և հաստատումը չեն համընկնում"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ձախողում գաղտնաբառի պահուստավորման կարգավորման ընթացքում"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Թվային բովանդակության համար հարմարեցված գույներ"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Միացրած հավելվածներ"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Ակտիվ չէ: Հպեք՝ փոխելու համար:"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Ակտիվ է: Հպեք՝ փոխելու համար:"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Աշխատեցվող ծառայություններ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Դիտել և վերահսկել ընթացիկ աշխատեցվող ծառայությունները"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Գիշերային ռեժիմ"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Անջատված"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Միշտ միացված"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Ավտոմատ"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Միացնել բազմագործընթաց WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Գործարկել WebView-ի մշակիչները առանձնացված գործընթացում:"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-ի իրականացում"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ընտրեք WebView-ի իրականացումը"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"WebView-ի իրականացման ընտրված եղանակն անջատված է և օգտագործելու համար պետք է նախ միացվի: Միացնե՞լ:"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"WebView-ի իրագործման ընտրված եղանակն անվավեր է, քանի որ իրագործման ընտրանքների ցանկը արդի չէ: Այն այժմ կթարմացվի:"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Վերածել ֆայլային գաղտնագրման"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Փոխարկել…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ֆայլային գաղտնագրումն արդեն կատարվել է"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Գունային կարգաբերում"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Սա փորձնական գործառույթ է և կարող է ազդել աշխատանքի վրա:"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Մնացել է մոտ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - մնաց մոտավորապես <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Չի լիցքավորվում"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Չի լիցքավորվում"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Լիցքավորված"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Կասեցված է ադմինիստրատորի կողմից"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
+ <string name="home" msgid="8263346537524314127">"Գլխավոր էջ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> առաջ"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Մնացել է <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2aa96d8981c3..62372ee920c6 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Keluaran text-to-speech"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Laju bicara"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Kecepatan teks diucapkan"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tinggi nada"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Memengaruhi nada ucapan yang disintesis"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Bahasa"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Gunakan bahasa sistem"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Bahasa tidak dipilih"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Selalu izinkan Pemindaian Roaming Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gunakan klien DHCP lawas"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Setelan ini hanya dimaksudkan untuk penggunaan pengembangan. Setelan dapat menyebabkan perangkat dan aplikasi yang menerapkannya rusak atau tidak berfungsi semestinya."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikasi aplikasi melalui USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Periksa perilaku membahayakan dalam aplikasi yang terpasang melalui ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Menonaktifkan fitur volume absolut Bluetooth jika ada masalah volume dengan perangkat jarak jauh, misalnya volume terlalu keras atau kurangnya kontrol."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktifkan aplikasi terminal yang menawarkan akses kerangka lokal"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Pemeriksaan HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Paksa izinkan aplikasi di eksternal"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Buat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktifkan jendela berformat bebas"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mengaktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Sandi cadangan desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ketuk guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktif. Ketuk untuk beralih."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Layanan yang sedang berjalan"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Melihat dan mengontrol layanan yang sedang berjalan"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Mode malam"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Dinonaktifkan"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Selalu aktif"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Otomatis"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktifkan WebView multiproses"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Jalankan perender WebView dalam proses yang terisolasi."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Penerapan WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setel penerapan WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Implementasi WebView yang dipilih telah dinonaktifkan, dan harus diaktifkan agar dapat digunakan. Ingin mengaktifkannya?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Implementasi WebView yang dipilih tidak valid karena daftar pilihan implementasi sudah usang. Daftar tersebut sekarang harus diperbarui."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konversi ke enkripsi file"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konversi..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sudah dienkripsi berbasis file"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Koreksi warna"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Fitur ini bersifat eksperimental dan dapat memengaruhi kinerja."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kira-kira tersisa <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira tersisa. <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sampai penuh"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Tidak mengisi daya"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengisi daya"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dinonaktifkan oleh administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikontrol oleh admin"</string>
+ <string name="home" msgid="8263346537524314127">"Layar Utama"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> lalu"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Tersisa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index b78cb0b9c53b..cd8734dead18 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Úttak upplesturs"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Talhraði"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Hraði talaðs texta"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tónhæð"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Hefur áhrif á raddblæ talgervils"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Tungumál"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Nota tungumál kerfis"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Tungumál ekki valið"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Leyfa alltaf reikileit með Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Nota gamlan DHCP-biðlara"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Þessar stillingar eru einungis ætlaðar í þróunarskyni. Þær geta valdið því að tækið og forrit þess bili eða starfi á rangan hátt."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Staðfesta forrit gegnum USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kanna skaðlega hegðun forrita sem sett eru upp frá ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Slekkur á samstillingu Bluetooth-hljóðstyrks ef vandamál koma upp með hljóðstyrk hjá fjartengdum tækjum, svo sem of hár hljóðstyrkur eða erfiðleikar við stjórnun."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Staðbundin skipanalína"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Virkja skipanalínuforrit sem leyfir staðbundinn skeljaraðgang"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-athugun"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Blikka skjá ef forrit gera tímafreka hluti á aðalþræði"</string>
<string name="pointer_location" msgid="6084434787496938001">"Staðsetning bendils"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skjáyfirlögn sem sýnir rauntímagögn um snertingar"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Sýna snertingar"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Sýna snertingar myndrænt"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Sýna yfirborðsuppfærslur"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Láta allt yfirborð glugga blikka við uppfærslu"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Sýna uppfærslur skjákorts"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Þvinga fram leyfi forrita í ytri geymslu"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gerir hvaða forriti sem er kleift að skrifa í ytri geymslu, burtséð frá gildum í upplýsingaskrá"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gerir stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gera stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Virkja glugga með frjálsu sniði"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Kveikir á stuðningi við glugga með frjálsu sniði á tilraunastigi."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Virkja stuðning við glugga með frjálsu sniði á tilraunastigi."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ýttu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nýtt aðgangsorð fyrir afritun valið"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nýja aðgangsorðið og staðfestingaraðgangsorðið eru ekki eins"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Villa við að velja aðgangsorð fyrir afritun"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Litir sérhannaðir fyrir stafrænt efni"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Óvirk forrit"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Óvirkt. Ýttu til að breyta."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Virkt. Ýttu til að breyta."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Þjónustur í gangi"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Skoða og stjórna þjónustum í gangi"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Næturstilling"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Óvirkt"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Alltaf kveikt"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Sjálfvirkt"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Virkja WebView í fjölvinnslu"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Keyra WebView teiknun í lokuðu ferli."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Innleiðing WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stilla innleiðingu WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Slökkt er á valinni innleiðingu WebView. Kveikja þarf á henni til að hægt sé að nota hana. Viltu gera það?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Sú innleiðing WebView sem hér var valin er ógild vegna þess að innleiðingalistinn rann út. Uppfæra þarf listann."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Umbreyta í dulkóðun skráa"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Umbreyta…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Þegar dulkóðað á grundvelli skráa"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Litaleiðrétting"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Þessi eiginleiki er á tilraunastigi og getur haft áhrif á frammistöðu."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Um það bil <xliff:g id="TIME">%1$s</xliff:g> eftir"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – u.þ.b. <xliff:g id="TIME">%2$s</xliff:g> eftir"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> í fulla hleðslu"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ekki í hleðslu"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ekki í hleðslu"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullhlaðin"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Stjórnandi gerði óvirkt"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Stjórnað af kerfisstjóra"</string>
+ <string name="home" msgid="8263346537524314127">"Heim"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Fyrir <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> eftir"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index c8e482e8cf73..44bffcb9e893 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Output sintesi vocale"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Velocità voce"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocità di pronuncia del testo"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tono"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Si applica al tono della sintesi vocale"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Lingua"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usa lingua di sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Lingua non selezionata"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Consenti sempre scansioni roaming Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usa client DHCP precedente"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le applicazioni installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Consente di disattivare la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verifica HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forza autorizzazione app su memoria esterna"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rende l\'app idonea all\'installaz. su mem. esterna, senza considerare i valori manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Imponi formato modificabile alle attività"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Rende il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Rendi il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Attiva finestre a forma libera"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Attiva il supporto per le finestre a forma libera sperimentali."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Attiva il supporto delle finestre a forma libera sperimentali."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Password di backup desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"I backup desktop completi non sono attualmente protetti."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Attiva. Tocca per attivare/disattivare."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Servizi in esecuzione"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modalità Notte"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Disattivato"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sempre attivo"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatico"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Attiva WebView multiprocesso"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Esegui renderer WebView in un processo isolato."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementazione di WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Imposta l\'implementazione di WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"L\'implementazione di WebView selezionata non è attiva e deve essere attivata per poterla utilizzare. Vuoi attivarla?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"L\'implementazione WebView selezionata non è valida perché l\'elenco di opzioni di implementazione è obsoleto. Aggiorna l\'elenco."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converti in crittografia basata su file"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converti..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Crittografia su base file già eseguita"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correzione del colore"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Questa funzione è sperimentale e potrebbe influire sulle prestazioni."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Circa <xliff:g id="TIME">%1$s</xliff:g> rimanenti"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tempo rimanente: <xliff:g id="TIME">%2$s</xliff:g> circa"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Non in carica"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Non in carica"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disattivata dall\'amministratore"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Gestita dall\'amministratore"</string>
+ <string name="home" msgid="8263346537524314127">"Home page"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c12a050973c4..de7f7e3cd476 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"פלט טקסט לדיבור"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"קצב דיבור"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"המהירות שבה הטקסט נאמר"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"גובה צליל"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"משפיע על הטון של הדיבור המסונתז"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"שפה"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"שימוש בשפת המערכת"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"לא נבחרה שפה"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏התר תמיד סריקות נדידה של Wi‑Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"‏השתמש בלקוח DHCP מדור קודם"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"נתונים סלולריים פעילים תמיד"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"השבת עוצמת קול מוחלטת"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"הגדרות אלה מיועדות לשימוש בפיתוח בלבד. הן עלולות לגרום למכשיר או לאפליקציות המותקנות בו לקרוס או לפעול באופן לא תקין."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏אמת אפליקציות באמצעות USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏בדוק אפליקציות שהותקנו באמצעות ADB/ADT לאיתור התנהגות מזיקה."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"‏משבית את תכונת עוצמת הקול המוחלטת ב-Bluetooth במקרה של בעיות בעוצמת הקול במכשירים מרוחקים, כגון עוצמת קול רמה מדי או חוסר שליטה ברמת העוצמה."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"מסוף מקומי"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"הפעל אפליקציית מסוף המציעה גישה מקומית למעטפת"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"‏בדיקת HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"אילוץ הרשאה של אפליקציות באחסון חיצוני"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"אפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"הפעל את האפשרות לשנות את הגודל והמיקום של החלונות"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"מפעיל תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"הפעל תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי מקומי"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"הקש כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"אפליקציה פעילה. הקש כדי להחליף מצב."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"שירותים פועלים"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"הצג ושלוט בשירותים הפועלים כעת"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"מצב לילה"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"מושבת"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"פועל תמיד"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"באופן אוטומטי"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"הפעל תצוגת אתר לריבוי עיבודים"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"הרץ מעבדי תצוגת אתר בהליך מבודד"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"‏יישום WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏הגדרת יישום WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏יישום ה-WebView שנבחר מושבת, ויש להפעיל אותו כדי להשתמש בו. האם ברצונך להפעיל אותו?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"‏יישום WebView שנבחר אינו חוקי שכן רשימת מבחר היישומים אינה פעילה יותר. יש צורך לעדכן את הרשימה."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"המר להצפנת קבצים"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"המר..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"הצפנת קבצים כבר מוגדרת"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"תיקון צבע"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"תכונה זו היא ניסיונית ועשויה להשפיע על הביצועים."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"נשארו <xliff:g id="TIME">%1$s</xliff:g> בערך"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="TIME">%2$s</xliff:g> בקירוב עד לסיום"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>‏ - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> ‏- <xliff:g id="TIME">%2$s</xliff:g> עד למילוי"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"לא בטעינה"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"לא טוען"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"מלא"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"הושבת על ידי מנהל המערכת"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"נמצא בשליטת מנהל מערכת"</string>
+ <string name="home" msgid="8263346537524314127">"דף הבית"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"לפני <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"נשארו <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index c26882c55254..f341d717464f 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"テキスト読み上げの出力"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"音声の速度"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"テキストの読み上げ速度"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"音の高さ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"合成音声のトーンに影響します"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"言語"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"システムの言語を使用"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"言語が選択されていません"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fiローミングスキャンを常に許可する"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"従来のDHCPクライアントを使用する"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"モバイルデータを常にON"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"絶対音量を無効にする"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"これらの設定は開発専用に設計されています。そのため端末や端末上のアプリが故障したり正常に動作しなくなったりするおそれがあります。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB経由のアプリを確認"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT経由でインストールされたアプリに不正な動作がないかを確認する"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"リモート端末で音量に関する問題(音量が大きすぎる、制御できないなど)が発生した場合に、Bluetooth の絶対音量の機能を無効にする。"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ローカルターミナル"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ローカルシェルアクセスを提供するターミナルアプリを有効にします"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCPチェック"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"外部ストレージへのアプリの書き込みを許可"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようになります。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようにします。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"フリーフォーム ウィンドウの有効化"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"テスト段階のフリーフォーム ウィンドウのサポートを有効にします。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"外部のフリーフォーム ウィンドウのサポートを有効にします。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"PCバックアップパスワード"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"有効です。タップすると切り替わります。"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"実行中のサービス"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"現在実行中のサービスを表示して制御する"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"夜間モード"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"無効"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"常にON"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"複数プロセス WebView を有効化"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"別個のプロセスで WebView レンダラを実行します。"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView の実装"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView の実装の設定"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"選択した WebView の実装は無効になっていますが、使用するには有効にする必要があります。有効にしますか?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"選択した WebView の実装は無効です。これは実装の選択に使用するリストが古くなっているためです。リストを更新する必要があります。"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ファイル暗号化に変換する"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"変換…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ファイルは既に暗号化済みです"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色補正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"この機能は試験運用機能であり、パフォーマンスに影響することがあります。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"あと約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 残り約<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -310,7 +312,8 @@
<!-- String.format failed for translation -->
<!-- no translation found for battery_info_status_full (2824614753861462808) -->
<skip />
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理者によって無効にされています"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"管理者により管理されています"</string>
+ <string name="home" msgid="8263346537524314127">"ホーム"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"あと <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 2a09ec08e073..08e632743993 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"მეტყველების სინთეზი"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"მეტყველების ტემპი"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ტექსტის თხრობის სიჩქარე"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"სიმაღლე"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"გავლენას ახდენს სინთეზირებული ხმის სიძლიერეზე"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ენა"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"სისტემის ენის გამოყენება"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ენა არჩეული არ არის"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Roam სკანირების მუდამ დაშვება"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"მოძველებული DHCP კლიენტის გამოყენება"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ფიჭური მონაცემები ყოველთვის აქტიურია"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ხმის აბსოლუტური სიძლიერის გათიშვა"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ამ პარამეტრების გამოყენება დასაშვებია მხოლოდ დეველოპერული მიზნებით. მათმა გამოყენებამ შეიძლება გამოიწვიოს თქვენი მოწყობილობის და მისი აპლიკაციების დაზიანება ან გაუმართავი მუშაობა."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"აპლიკაციების USB-ს საშუალებით შემოწმება"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"შეამოწმეთ, რამდენად უსაფრთხოა ADB/ADT-ის საშუალებით ინსტალირებული აპლიკაციები."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"გათიშავს Bluetooth-ის ხმის აბსოლუტური სიძლიერის ფუნქციას დისტანციურ მოწყობილობებზე ხმასთან დაკავშირებული ისეთი პრობლემების არსებობის შემთხვევაში, როგორიცაა ხმის დაუშვებლად მაღალი სიძლიერე ან კონტროლის შეუძლებლობა."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ადგილობრივი ტერმინალი"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ლოკალურ გარსზე წვდომის ტერმინალური აპლიკაციის ჩართვა"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP შემოწმება"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Flash screen when apps do long operations on main thread"</string>
<string name="pointer_location" msgid="6084434787496938001">"მაჩვენებლის მდებარეობა"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"ეკრანის გადაფარვა შეხების მონაცემების ჩვენებით"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"შეხებების ჩვენება"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"შეხებებისთვის ვიზუალური უკუკავშირის ჩვენება"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"ზედაპირის განახლებების ჩვენება"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"ფანჯრის მთელი ზედაპირის აციმციმება მისი განახლებისას"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU ხედის განახლებების ჩვენება"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"აპების დაშვება გარე მეხსიერებაში"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"მანიფესტის მნიშვნელობების მიუხედავად, ყველა აქტივობას მრავალი ფანჯრის რეჟიმისთვის ზომაცვლადად აქცევს."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"მანიფესტის მნიშვნელობების მიუხედავად, მრავალი ფანჯრის რეჟიმისთვის ყველა აქტივობის ზომაცვლადად გადაქცევა."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ჩართავს თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტულ ფუნქციას"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტული ფუნქციის ჩართვა."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"ახალი სარეზერვო პაროლის დაყენება"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ახალი და დადასტურებული პაროლები არ შეესატყვისება ერთმანეთს"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"სარეზერვო პაროლის დაყენება ვერ მოხერხდა"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"ციფრული კონტენტისთვის ოპტიმიზებული ფერები"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"უმოქმედო აპები"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"უმოქმედო. შეეხეთ გადასართავად."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"აქტიური. შეეხეთ გადასართავად."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"მიმდინარე სერვისები"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"ღამის რეჟიმი"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"გამორთულია"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ყოველთვის ჩართული"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ავტომატური"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"მრავალპროც. WebView-ს ჩართვა"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView ვიზუალიზატორების იზოლირებულ პროცესში გაშვება."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView რეალიზაცია"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView რეალიზაციის დაყენება"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"არჩეული WebView რეალიზაცია გათიშულია და გამოყენებამდე უნდა ჩაირთოს. გსურთ მისი ჩართვა?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"არჩეული WebView რეალიზაცია არასწორია. რეალიზაციების სია მოძველდა და ახლა განახლდება."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ფაილების დაშიფვრაზე გარდაქმნა"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"გარდაქმნა…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"უკვე დაშიფრულია ფაილების დონეზე"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ფერის კორექცია"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ეს ფუნქცია საცდელია და შეიძლება გავლენა იქონიოს შესრულებაზე."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"დარჩენილია დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"დაახლ. <xliff:g id="LEVEL">%1$s</xliff:g> დარჩენილია <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> სრულ დატენვამდე"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"არ იტენება"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"არ იტენება"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ბატარეა დატენილია"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"გათიშულია ადმინისტრატორის მიერ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"იმართება ადმინისტრატორის მიერ"</string>
+ <string name="home" msgid="8263346537524314127">"მთავარი"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"გავიდა <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"დარჩენილია <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 2841af55bb73..921812acd19f 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Мәтінді тілге айналдыру"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Сөйлеу жылдамдығы"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Мәтіннің оқылу жылдамдығы"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Дауыс жиілігі"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Синтезделген сөйлеу үніне әсер етеді"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Тіл"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Жүйелік тілді пайдалану"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Тіл таңдалған жоқ"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi роумингін іздеулерге әрқашан рұқсат ету"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Бұрынғы DHCP клиентін пайдалану"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Ұялы деректер әрқашан белсенді"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Бұл параметрлер жетілдіру мақсатында ғана қолданылады. Олар құрылғыңыз бен қолданбаларыңыздың бұзылуына немесе әдеттен тыс әрекеттерге себеп болуы мүмкін."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB арқылы орнатылған қолданбаларды растау"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT арқылы орнатылған қолданбалардың залалды болмауын тексеру."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Қолайсыз қатты дыбыс деңгейі немесе басқарудың болмауы сияқты қашықтағы құрылғыларда дыбыс деңгейімен мәселелер жағдайында Bluetooth абсолютті дыбыс деңгейі функциясын өшіреді."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Жергілікті терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Жергілікті шелл-код қол жетімділігін ұсынатын терминалды қолданбаны қосу"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP (жоғары кең жолақты сандық мазмұнды қорғау) тексеру"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Сыртқыда қолданбаларға мәжбүрлеп рұқсат ету"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест мәндеріне қарамастан бірнеше терезе режимінде барлық әрекеттердің өлшемін өзгертуге рұқсат беру."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Еркін пішіндегі терезелерді қосу"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эксперименттік еркін пішіндегі терезелерді қолдауды қосады."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Еркін пішінді терезелерді құру эксперименттік функиясын қосу."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Компьютер үстелінің сақтық көшірмесі"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Үстелдік компьютердің толық сақтық көшірмелерінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Белсенді. Ауыстырып қосу үшін түртіңіз."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Қосылып тұрған қызметтер"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ағымдағы қосылып тұрған қызметтерді көру және басқару"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Түнгі режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Өшірілген"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Әрқашан қосулы"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Aвтоматты"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Бірнеше процесті веб-көріністі қосу"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Веб-көрініс бейнелеушілерін оқшауланған процесте іске қосу."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ендіру"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ендіруін орнату"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Таңдалған веб-көріністі енгізу өшірілген және пайдалану үшін оны қосу керек. Оны қосу керек пе?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Таңдалған WebView ендіру жарамсыз, өйткені ендіру таңдауларының тізімі ескірген. Тізімді қазір жаңарту керек."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файлды шифрлауға түрлендіру"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Түрлендіру..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл шифрланып қойылған"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Түсті түзету"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бұл мүмкіндік эксперименттік болып табылады және өнімділікке әсер етуі мүмкін."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - шамамен <xliff:g id="TIME">%2$s</xliff:g> қалды"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - толғанша <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Зарядталу орындалып жатқан жоқ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Зарядталып тұрған жоқ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Толық"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Әкімші өшірген"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Әкімші басқарады"</string>
+ <string name="home" msgid="8263346537524314127">"Негізгі бет"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> бұрын"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> қалды"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 5f913092e63a..f64158c13a73 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"លទ្ធផល​អត្ថបទ​ទៅ​ការ​និយាយ"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"អត្រា​និយាយ"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ល្បឿន​ពេល​អាន​​អត្ថបទ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ឡើង​-ចុះ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ប៉ះពាល់ដល់សំឡេងនៃការនិយាយដែលបានបម្លែង"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ភាសា"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"ប្រើ​ភាសា​ប្រព័ន្ធ"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"មិន​បាន​ជ្រើស​ភាសា"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"តែងតែ​អនុញ្ញាត​​​ការវិភាគ​រ៉ូម​វ៉ាយហ្វាយ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ប្រើម៉ាស៊ីនកូន DHCP ចាស់"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ទិន្នន័យចល័តសកម្មជានិច្ច"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"បិទកម្រិតសំឡេងលឺខ្លាំង"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ការ​កំណត់​ទាំង​នេះ​សម្រាប់​តែ​ការ​ប្រើ​ក្នុង​ការ​អភិវឌ្ឍ​ប៉ុណ្ណោះ។ ពួក​វា​អាច​ធ្វើ​ឲ្យ​ឧបករណ៍ និង​កម្មវិធី​របស់​អ្នក​ខូច ឬ​ដំណើរ​មិន​ត្រឹមត្រូវ។"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ផ្ទៀងផ្ទាត់​កម្មវិធី​តាម​យូអេសប៊ី"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ពិនិត្យ​កម្មវិធី​បាន​ដំឡើង​តាម​រយៈ ADB/ADT សម្រាប់​ឥរិយាបថ​ដែល​គ្រោះ​ថ្នាក់។"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"បិទលក្ខណៈពិសេសកម្រិតសំឡេងលឺខ្លាំងពេលភ្ជាប់ប៊្លូធូសក្នុងករណីមានបញ្ហាជាមួយឧបករណ៍បញ្ជាពីចម្ងាយ ដូចជាកម្រិតសំឡេងលឺខ្លាំងដែលមិនអាចទទួលយកបាន ឬខ្វះការគ្រប់គ្រង។"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ស្ថានីយ​មូលដ្ឋាន"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"បើក​កម្មវិធី​ស្ថានីយ​ដែល​ផ្ដល់​ការ​ចូល​សែល​មូលដ្ឋាន"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"ពិនិត្យ HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"បង្ខំឲ្យអនុញ្ញាតកម្មវិធីលើឧបករណ៍ផ្ទុកខាងក្រៅ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសឡើយ។"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេស។"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"បើកដំណើរការគាំទ្រផ្ទាំងវិនដូទម្រង់សេរីសាកល្បង"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"បើកដំណើរការគាំទ្រផ្ទាំងវិនដូទម្រង់សេរីសាកល្បង"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ពាក្យ​សម្ងាត់​បម្រុង​ទុក​លើ​ផ្ទៃតុ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ការ​បម្រុង​ទុក​ពេញលេញ​លើ​ផ្ទៃតុ​បច្ចុប្បន្ន​មិន​ត្រូវ​បាន​ការពារ​ទេ។"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ប៉ះដើម្បីប្ដូរ ឬយកពាក្យសម្ងាត់ចេញសម្រាប់ការបម្រុងទុកពេញលេញលើកុំព្យូទ័រ"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"សកម្ម។ ប៉ះដើម្បីបិទ/បើក។"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"សេវាកម្ម​កំពុង​ដំណើរការ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"មើល និង​គ្រប់គ្រង​សេវាកម្ម​កំពុង​ដំណើរការ​បច្ចុប្បន្ន"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"របៀបពេលយប់"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"បានបិទ"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"បើកជានិច្ច"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ស្វ័យប្រវត្តិ"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"បើកដំណើរការ WebView ដែលមានអង្គដំណើរការច្រើន"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ដំណើរការកម្មវិធីបំលែង WebView ក្នុងដំណើរការដាច់ដោយឡែក"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"ការប្រតិបត្តិ WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"កំណត់ការប្រតិបត្តិ WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ការប្រតិបត្តិការ WebView ដែលបានជ្រើសត្រូវបានបិទដំណើរការ ប៉ុន្តែអ្នកត្រូវបើកដំណើរការវាដើម្បីប្រើ តើអ្នកចង់បើកដំណើរការវាដែរឬទេ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"ការអនុវត្ត WebView ដែលបានជ្រើសមិនត្រូវត្រឹមត្រូវទេ ដោយសារតែបញ្ជីជម្រើសនៃការអនុវត្តន៍ចាស់ហើយ។ គួរតែអាប់ដេតបញ្ជីនោះ។"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"បម្លែងទៅជាការអ៊ីនគ្រីបឯកសារ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"បម្លែង…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"បានអ៊ីនគ្រីបឯកសាររួចហើយ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ការ​កែ​ពណ៌"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"លក្ខណៈ​នេះ​គឺ​ជា​ការ​ពិសោធន៍ ហើយ​អាច​ប៉ះពាល់​ការ​អនុវត្ត។"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"បដិសេធ​ដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"នៅសល់ប្រហែល <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅ​សល់​ប្រហែល <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូត​ដល់​ពេញ"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"មិនកំពុង​បញ្ចូល​ថ្ម"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"មិន​បញ្ចូលថ្ម"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"គ្រប់គ្រងដោយអ្នកគ្រប់គ្រង"</string>
+ <string name="home" msgid="8263346537524314127">"ដើម"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> មុន"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"នៅសល់ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index f24bd080cf2f..7e686559411b 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"ಧ್ವನಿಗೆ-ಪಠ್ಯದ ಔಟ್‌ಪುಟ್‌"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"ಧ್ವನಿಯ ದರ"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ಪಠ್ಯವನ್ನು ಹೇಳಿದ ವೇಗ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ಪಿಚ್"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ಸಂಯೋಜಿತ ಧ್ವನಿಯ ಟೋನ್ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತದೆ"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ಭಾಷೆ"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"ಸಿಸ್ಟಂ ಭಾಷೆಯನ್ನು ಬಳಸು"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ಭಾಷೆಯನ್ನು ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi ರೋಮ್ ಸ್ಕ್ಯಾನ್‌ಗಳನ್ನು ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ಹಿಂದಿನ DHCP ಕ್ಲೈಂಟ್ ಬಳಸಿ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಅಭಿವೃದ್ಧಿಯ ಬಳಕೆಗೆ ಮಾತ್ರ. ಅವುಗಳು ನಿಮ್ಮ ಸಾಧನ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌‌ಗಳಿಗೆ ಧಕ್ಕೆ ಮಾಡಬಹುದು ಅಥವಾ ಅವು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರುವಂತೆ ಮಾಡಬಹುದು."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ಮೂಲಕ ಆಪ್‌ ಪರಿಶೀಲಿಸಿ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ಹಾನಿಮಾಡುವಂತಹ ವರ್ತನೆಗಾಗಿ ADB/ADT ಮೂಲಕ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ರಿಮೋಟ್ ಸಾಧನಗಳೊಂದಿಗೆ ಒಪ್ಪಲಾಗದ ಜೋರಾದ ವಾಲ್ಯೂಮ್ ಅಥವಾ ನಿಯಂತ್ರಣದ ಕೊರತೆಯಂತಹ ವಾಲ್ಯೂಮ್ ಸಮಸ್ಯೆಗಳಂತಹ ಸಂದರ್ಭದಲ್ಲಿ ಬ್ಲೂಟೂತ್ ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್ ವೈಶಿಷ್ಟ್ಯವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ಸ್ಥಳೀಯ ಟರ್ಮಿನಲ್"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ಸ್ಥಳೀಯ ಶೆಲ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸುವ ಟರ್ಮಿನಲ್ ಅಪ್ಲಿಕೇಶನ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ಪರೀಕ್ಷಿಸುವಿಕೆ"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ಬಾಹ್ಯವಾಗಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಒತ್ತಾಯವಾಗಿ ಅನುಮತಿಸಿ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡುತ್ತದೆ."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ಪ್ರಾಯೋಗಿಕ ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ಪ್ರಾಯೋಗಿಕ ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ಡೆಸ್ಕ್‌ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್‌ವರ್ಡ್"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ಡೆಸ್ಕ್‌ಟಾಪ್‌‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌‌ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್‌ ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"ಸಕ್ರಿಯ. ಟಾಗಲ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ಈಗ ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"ರಾತ್ರಿ ಮೋಡ್"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ಯಾವಾಗಲೂ ಆನ್"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ಸ್ವಯಂಚಾಲಿತ"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ಬಹುಪ್ರಕ್ರಿಯೆ WebView ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ಪ್ರತ್ಯೇಕಗೊಳಿಸಿದ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ WebView ರೆಂಡರರ್‌‌ ರನ್‌ ಮಾಡಿ."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ಆಯ್ಕೆಮಾಡಲಾದ WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಮತ್ತು ಬಳಸಲು ಸಕ್ರಿಯಗೊಳಿಸಬೇಕಾಗಿದೆ, ಇದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ನೀವು ಬಯಸುತ್ತೀರಾ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"ಅನುಷ್ಠಾನ ಆಯ್ಕೆಗಳ ಪಟ್ಟಿ ಸ್ಥಬ್ದವಾಗಿರುವ ಕಾರಣ ಆಯ್ಕೆಮಾಡಿದ WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯು ಅಮಾನ್ಯವಾಗಿದೆ. ಈಗ ಪಟ್ಟಿಯನ್ನು ಅಪ್‌‌ಡೇಟ್‌ ಮಾಡಬೇಕಾಗಿದೆ."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ಫೈಲ್ ಎನ್‌ಕ್ರಿಪ್ಶನ್‌ಗೆ ಪರಿವರ್ತಿಸು"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ಪರಿವರ್ತಿಸು…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ಫೈಲ್ ಈಗಾಗಲೇ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ಇದು ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯವಾಗಿದೆ. ಕಾರ್ಯಕ್ಷಮತೆ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರಬಹುದು."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ಸುಮಾರು <xliff:g id="TIME">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"ಸುಮಾರು <xliff:g id="LEVEL">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> ಉಳಿದಿದೆ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ಚಾರ್ಜ್‌ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ಭರ್ತಿ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ನಿರ್ವಾಹಕರಿಂದ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
+ <string name="home" msgid="8263346537524314127">"ಮುಖಪುಟ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ಹಿಂದೆ"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index dc55956fdac8..a7434d07fe1d 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"TTS 출력"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"말하는 속도"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"텍스트를 읽어주는 속도"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"피치"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"합성 음성의 어조에 영향을 미침"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"언어"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"시스템 언어 사용"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"언어가 선택되지 않음"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi 로밍 스캔 항상 허용"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"이전 DHCP 클라이언트 사용"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"모바일 데이터 항상 활성화"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"절대 볼륨 사용 안함"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"이 설정은 개발자용으로만 설계되었습니다. 이 설정을 사용하면 기기 및 애플리케이션에 예기치 않은 중단이나 오류가 발생할 수 있습니다."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB를 통해 설치된 앱 확인"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT을 통해 설치된 앱에 유해한 동작이 있는지 확인"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"참기 어려울 정도로 볼륨이 크거나 제어가 되지 않는 등 원격 기기에서 볼륨 문제가 발생할 경우 블루투스 절대 볼륨 기능을 사용 중지합니다."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"로컬 터미널"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"로컬 셸 액세스를 제공하는 터미널 앱 사용"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 확인"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"외부에서 앱 강제 허용"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"자유 형식 창 사용"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"자유 형식 창(베타) 지원 사용"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"자유 형식 창 지원 사용"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"데스크톱 백업 비밀번호"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 탭하세요."</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"활성화되었습니다. 전환하려면 탭하세요."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"실행 중인 서비스"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"현재 실행 중인 서비스 보기 및 제어"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"야간 모드"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"사용 안함"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"항상 사용"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"자동"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"멀티 프로세스 WebView 사용"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"단독 프로세스 내에서 WebView 렌더러를 실행합니다."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 구현"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView 구현 설정"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"선택한 WebView 구현이 사용 중지되어 있습니다. 사용하려면 사용 설정해야 합니다. 사용 설정하시겠습니까?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"구현 선택 목록이 비활성화되어 선택한 WebView 구현이 잘못되었습니다. 목록을 지금 업데이트해야 합니다."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"파일 암호화로 변환"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"변환..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"파일이 이미 암호화됨"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"색보정"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"실험실 기능이며 성능에 영향을 줄 수 있습니다."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"약 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 대략 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"충전 안함"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"충전 안함"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"관리자가 사용 중지함"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"관리자가 제어"</string>
+ <string name="home" msgid="8263346537524314127">"홈"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> 전"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> 남음"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 4e3bfdba842f..e05d82e25f31 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Текстти-оозекилөө"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Кеп ылдамдыгы"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Текст айтылчу ылдамдык"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Негизги тон"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Синтезделген кептин интонациясына таасирин тийгизет"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Тил"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Тутум тилин колдонуу"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Тил тандалган жок"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi Роуминг Скандоо мүмкүнчүлүгүнө ар дайым уруксат берилсин"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Эскирген DHCP кардарын колдонуу"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Уюлдук дайындар ар дайым активдүү"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үндүн абсолюттук деңгээли өчүрүлсүн"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB аркылуу келген колдонмолорду ырастоо"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT аркылуу орнотулган колдонмолорду зыянкечтикке текшерүү."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Алыскы түзмөктөр өтө катуу добуш чыгарып же көзөмөлдөнбөй жатса Bluetooth \"Үндүн абсолюттук деңгээли\" функциясын өчүрөт."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Жергиликтүү терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Жергиликтүү буйрук кабыгын сунуштаган терминалга уруксат берүү"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP текшерүү"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Колдонмолор негизги жикте узак иш-аракеттерди аткарганда экран жаркылдасын"</string>
<string name="pointer_location" msgid="6084434787496938001">"Көрсөткүчтүн жайгшкн жери"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Учурдагы басылган дайндрд көрсөтүүчү экран катмары"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Таптоолорду көрсөтүү"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Экранда тапталган жерлерди көрсөтүү"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Экран жаңыруусун көрсөтүү"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Экран жаңырганда аны бүт бойдон жарык кылуу"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU көрүнүш жаңыртуулары"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Тышкы сактагычка сактоого уруксат берүү"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылат."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылуу."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Компүтердеги бэкаптын сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Иш тактасынын камдалган сырсөзүн өзгөртүү же алып салуу үчүн таптап коюңуз"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Жаңы бэкапка сырсөз коюулду"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Жаңы сырсөз жана анын ырастоосу дал келген жок"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Жаңы бэкапка сырсөз коюлган жок"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Санарип мазмун үчүн оптималдаштырылган түстөр"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Иштебеген колдонмолор"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Иштеген жок. Которуштуруу үчүн таптап коюңуз."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Иштеп турат. Которуштуруу үчүн таптап коюңуз."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Иштеп жаткан кызматтар"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Учурда иштеп жаткан кызматтарды көрүү жана көзөмөлдөө"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Түнкү режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Өчүрүлгөн"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Ар дайым күйгүзүлгөн"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Автоматтык"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Көп процесстүү WebView иштт"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView рендерерлерин корголгон процессте иштетүү."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"WebView кызматын пайдалануу үчүн аны иштетүү керек. Иштетесизби?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Аткарууларды тандоо тизмеси эскирип кеткендиктен тандалган WebView аткарылышы жараксыз. Тизме азыр жаңыртылышы керек."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Түсүн тууралоо"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бул сынамык мүмкүнчүлүк болгондуктан, иштин майнаптуулугуна таасир этиши мүмкүн."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Болжол менен <xliff:g id="TIME">%1$s</xliff:g> калды"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - болжол менен <xliff:g id="TIME">%2$s</xliff:g> саат калды"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> толгончо"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Кубат алган жок"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Кубатталган жок"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Толук"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Администратор өчүрүп койгон"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Администратор тарабынан көзөмөлдөнөт"</string>
+ <string name="home" msgid="8263346537524314127">"Башкы бет"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> мурун"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> калды"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 0e3eebde2bde..e9017d951822 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"ການປ່ຽນຂໍ້ຄວາມເປັນສຽງ"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"ອັດຕາການເວົ້າ"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ຄວາມໄວໃນການເວົ້າຂໍ້ຄວາມ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ໂທນສຽງ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ມີຜົນກັບໂທນສຽງເວົ້າທີ່ສັງເຄາະ"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ພາສາ"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"​ໃຊ້​ພາ​ສາ​ຂອງ​ລະ​ບົບ"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ບໍ່ໄດ້ເລືອກພາສາ"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ອະ​ນຸ​ຍາດ​ການ​ສະ​ແກນ​ການ​ໂຣມ Wi‑Fi ​ສະ​ເໝີ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ໃຊ້​ລູກ​ຄ້າ DHCP ຕຳ​ນານ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ຂໍ້​ມູນ​ມື​ຖື​ເປີດ​ຢູ່​ສະ​ເໝີ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ການ​ຕັ້ງຄ່າ​ເຫຼົ່ານີ້​ແມ່ນ​ມີ​ຈຸດປະສົງ​ເພື່ອ​ການ​ພັດທະນາ​ເທົ່ານັ້ນ. ພວກ​ມັນ​ສາມາດ​ເຮັດ​ໃຫ້​ອຸປະກອນ ແລະ​ແອັບພລິເຄຊັນ​ຂອງ​ທ່ານ​ຢຸດ​ເຮັດ​ວຽກ ຫຼື​ເຮັດ​ວຽກ​ຜິດປົກກະຕິ​ໄດ້."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ຢືນຢັນແອັບຯຜ່ານທາງ USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ກວດສອບແອັບຯທີ່ຕິດຕັ້ງແລ້ວຜ່ານທາງ ADB/ADT ເພື່ອກວດຫາພຶດຕິກຳທີ່ເປັນອັນຕະລາຍ."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ປິດໃຊ້ຄຸນສົມບັດລະດັບສຽງສົມບູນຂອງ Bluetooth ໃນກໍລະນີເກີດບັນຫາລະດັບສຽງສົມບູນກັບອຸປະກອນທາງໄກ ເຊັ່ນວ່າ ລະດັບສຽງດັງເກີນຍອມຮັບໄດ້ ຫຼື ຄວບຄຸມບໍ່ໄດ້."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal ໃນໂຕເຄື່ອງ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ເປີດນຳໃຊ້ແອັບຯ Terminal ທີ່ໃຫ້ການເຂົ້າເຖິງ shell ໃນໂຕເຄື່ອງໄດ້"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"ການກວດສອບ HDCP"</string>
@@ -246,12 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ບັງຄັບອະນຸຍາດແອັບ​ຢູ່​ພາຍນອກ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດ​ໃຫ້ທຸກແອັບ​ມີ​ສິດ​ໄດ້ຮັບການຂຽນ​ໃສ່​ບ່ອນ​ຈັດ​ເກັບ​ພາຍນອກ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ບັງ​ຄັງ​ໃຫ້​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ເຮັດ​ໃຫ້​ທຸກ​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້​ສຳ​ລັບ​ຫຼາຍ​ໜ້າ​ຕ່າງ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ເຮັດໃຫ້ທຸກກິດຈະກຳສາມາດປັບຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຈໍ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ເປີດໃຊ້ໜ້າຕ່າງຮູບແບບອິດສະຫຼະ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ເປີດໃຊ້ການຮອງຮັບໜ້າຕ່າງຮູບແບບອິດສະຫຼະທີ່ທົດລອງໃຊ້."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ເປີດໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບທົດລອງ."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການ​ສຳຮອງ​ຂໍ້ມູນ​ເຕັມຮູບແບບ​ໃນ​ເດັກສະທັອບ​ຍັງ​ບໍ່​ໄດ້​ຮັບ​ການ​ປ້ອງກັນ​ໃນ​ເວລາ​ນີ້"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັສທັອບ"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"ຕັ້ງລະຫັດສຳຮອງໃໝ່ແລ້ວ"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ລະຫັດຜ່ານໃໝ່ ແລະລະຫັດຢືນຢັນບໍ່ກົງກັນ"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ການຕັ້ງລະຫັດສຳຮອງຂໍ້ມູນລົ້ມເຫລວ"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"ນຳໃຊ້ຢູ່. ແຕະເພື່ອສັບປ່ຽນ."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"ໂໝດກາງຄືນ"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"ປິດໃຊ້ງານແລ້ວ"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ເປີດຕະຫຼອດ"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ອັດຕະໂນມັດ"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ອະນຸຍາດໃຫ້ມີໂປຣເຊສ WebView ຫຼາຍອັນໄດ້"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ເປີດໃຊ້ຕົວປະມວນ WebView ໃນໂປຣເຊສທີ່ແຍກຈາກກັນໄດ້."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ຕັ້ງການຈັດຕັ້ງປະຕິບັດ WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ການຈັດຕັ້ງປະຕິບັດ WebView ທີ່ເລືອກຖືກປິດນຳໃຊ້, ແລະຕ້ອງຖືກເປີດນຳໃຊ້, ທ່ານຕ້ອງການເປີດນຳໃຊ້ມັນບໍ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"ການນຳໃຊ້ WebView ທີ່ເລືອກນັ້ນບໍ່ຖືກຕ້ອງເນື່ອງຈາກລາຍຊື່ຂອງການເລືອກນຳໃຊ້ນັ້ນເກົ່າເກີນໄປ. ລາຍຊື່ຕອນນີ້ແມ່ນອັບເດດແລ້ວ."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ປ່ຽນ​ເປັນ​ການ​ເຂົ້າ​ລະ​ຫັດ​ໄຟ​ລ໌"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ປ່ຽນ..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ໄຟ​ລ໌​ເຂົ້າ​ລະ​ຫັດ​ຮຽບ​ຮ້ອຍ​ແລ້ວ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ການ​ປັບ​ແຕ່ງ​ສີ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"​ຄຸນ​ສົມ​ບັດ​ນີ້​ກຳ​ລັງ​ຢູ່​ໃນ​ການ​ທົດ​ລອງ​ແລະ​ອາດ​ມີ​ຜົນ​ຕໍ່​ປະ​ສິດ​ທິ​ພາບ."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ຍັງເຫຼືອປະມານ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ​ເຫຼືອປະ​ມານ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງ​ຈະ​ເຕັມ"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ຖືກປິດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ຄວບຄຸມໂດຍຜູ້ເບິ່ງແຍງ"</string>
+ <string name="home" msgid="8263346537524314127">"​ໜ້າຫຼັກ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ກ່ອນນີ້"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"ຍັງເຫຼືອ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 109fa09cd873..5c3f5be1daf6 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"„Teksto į kalbą“ išvestis"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Kalbėjimo greitis"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Greitis, kuriuo sakomas tekstas"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Garso aukštis"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Daro poveikį susintetintai kalbai"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Kalba"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Naudoti sistemos kalbą"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Kalba nepasirinkta"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Visada leisti „Wi-Fi“ tarptiklinio ryšio nuskaitymą"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Naudoti seną DHCP kliento programą"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Šie nustatymai skirti tik kūrėjams. Nustačius juos įrenginys ir jame naudojamos programos gali nustoti veikti arba veikti netinkamai."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Patvirtinti progr. naudojant USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Patikrinkite, ar programų, įdiegtų naudojant ADB / ADT, veikimas nėra žalingas."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Išjungiama „Bluetooth“ didžiausio garso funkcija, jei naudojant nuotolinio valdymo įrenginius kyla problemų dėl garso, pvz., garsas yra per didelis arba jo negalima tinkamai valdyti."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Vietinis terminalas"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Įgal. terminalo progr., siūlančią prieigą prie viet. apvalkalo"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP tikrinimas"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Ekr. blyksės, kai pr. atl. ilgus proc. pgr. gijoje"</string>
<string name="pointer_location" msgid="6084434787496938001">"Žymiklio vieta"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Ekrano perdanga rodo dabartinius lietimo duomenis"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Rodyti palietimus"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Rodyti vaizdinius palietimų atsiliepimus"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Rodyti paviršiaus naujin."</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Naujinant mirginti visus langų paviršius"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Rodyt GPU rodinių naujin."</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Priverstinai leisti programas išorinėje atmintin."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Nustatoma, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Nustatyti, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Įgalinti laisvos formos langus"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Įgalinamas eksperimentinių laisvos formos langų palaikymas."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Įgalinti eksperimentinių laisvos formos langų palaikymą."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Jei norite pakeisti ar pašalinti visų stalinio kompiuterio atsarginių kopijų slaptažodį, palieskite"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nustatytas naujas atsarginės kopijos slaptažodis"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Naujas slaptažodis ir patvirtinimas neatitinka"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nustatant atsarginės kopijos slaptažodį įvyko klaida"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Skaitmeniniam turiniui optimizuotos spalvos"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktyvios programos"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktyvi. Palieskite, kad perjungtumėte."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktyvi. Palieskite, kad perjungtumėte."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Vykdomos paslaugos"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Naktinis režimas"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Išjungta"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Visada įjungta"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatinė"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Įgal. kelių procesų „WebView“"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Paleisti „WebView“ pateikimo priemones vienam procesui."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"„WebView“ diegimas"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"„WebView“ diegimo nustatymas"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Pasirinktas „WebView“ diegimas išjungtas ir jį būtina įgalinti, kad būtų galima naudoti. Ar norite jį įgalinti?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Pasirinktas „WebView“ diegimas netinkamas, nes diegimo pasirinkimų sąrašas tapo neaktyvus. Sąrašas dabar turėtų būti atnaujintas."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuoti į failų šifruotę"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuoti…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Jau konvertuota į failų šifruotę"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Spalvų taisymas"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ši funkcija yra eksperimentinė ir ji gali turėti įtakos našumui."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Liko maždaug <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko maždaug <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nekraunama"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nekraunama"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Išjungė administratorius"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Valdo administratorius"</string>
+ <string name="home" msgid="8263346537524314127">"Pagrindinis ekranas"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Prieš <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Liko <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 9a5483e269c5..27eeaf5766d9 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Teksta-runas izvade"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Runas ātrums"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Teksta ierunāšanas ātrums"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonis"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ietekmē sintezētās runas toni"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Valoda"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Izmantot sistēmas valodu"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nav atlasīta valoda."</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vienmēr atļaut Wi‑Fi meklēšanu"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Lietot mantoto DHCP klientu"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Šie iestatījumi ir paredzēti tikai izstrādei. To dēļ var tikt pārtraukta vai traucēta ierīces un lietojumprogrammu darbība."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificēt, ja instalētas no USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Pārbaudīt, vai lietotņu, kuru instalēšanai izmantots ADB/ADT, darbība nav kaitīga."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Atspējo Bluetooth absolūtā skaļuma funkciju skaļuma problēmu gadījumiem attālajās ierīcēs, piemēram, ja ir nepieņemami liels skaļums vai nav iespējas kontrolēt skaļumu."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Vietējā beigu lietotne"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Iespējot beigu lietotni, kurā piedāvāta vietējā čaulas piekļuve"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP pārbaude"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Zibsnīt ekrānu, ja liet. ilgi darbojas galv. pav."</string>
<string name="pointer_location" msgid="6084434787496938001">"Rādītāja atrašanās vieta"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Ekrāna pārklājums ar aktuāliem pieskāriena datiem"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Rādīt pieskārienus"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Rādīt vizuālo reakciju pēc pieskārieniem"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Rādīt virsmas atjauninājumus WL: 294"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Atjaunināt visa loga virsmas, kad tās tiek atjauninātas WL: 294"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Rādīt GPU skat. atjaun."</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Lietotņu piespiedu atļaušana ārējā krātuvē"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pielāgo visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Pielāgot visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Iespējot brīvās formas logus"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Iespējo eksperimentālo brīvās formas logu atbalstu."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Iespējot eksperimentālo brīvās formas logu atbalstu."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem datora dublējumiem."</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Jaunā dublējuma parole ir iestatīta."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Jaunā parole un apstiprinājums neatbilst."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Iestatot dublējuma paroli, radās kļūme."</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Digitālajam saturam optimizētas krāsas"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Neaktīvās lietotnes"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Neaktīva. Pieskarieties, lai pārslēgtu."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktīva. Pieskarieties, lai pārslēgtu."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Aktīvie pakalpojumi"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nakts režīms"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Atspējots"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Vienmēr ieslēgts"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automātiski"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Iespējot vairākprocesu WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Atsevišķā procesā tiek palaisti WebView renderētāji."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ieviešana"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Iestatīt WebView ieviešanu"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izvēlētā WebView ieviešana ir atspējota, un tā ir jāiespējo, lai to varētu izmantot. Vai vēlaties to iespējot?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Izvēlētā WebView ieviešana nav derīga, jo ieviešanas iespēju saraksts ir novecojis. Saraksts ir jāatjaunina."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Pārvērst par failu šifrējumu"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pārvērst…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Jau šifrēts failu līmenī"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Krāsu korekcija"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Šī funkcija ir eksperimentāla un var ietekmēt veiktspēju."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Atlikušais laiks: aptuveni <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> — aptuvenais atlikušais laiks: <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nenotiek uzlāde"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenotiek uzlāde"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Atspējojis administrators"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolē administrators"</string>
+ <string name="home" msgid="8263346537524314127">"Sākums"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Pirms šāda laika: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Atlikušais laiks: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 17de45b61d4e..ec09f21860e6 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Излез текст-во-говор"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Брзина на говор"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Брзина со која се кажува текстот"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Интензитет"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Влијае на тонот на синтетизираниот говор"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Јазик"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Користете системски јазик"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Јазикот не е избран"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Секогаш дозволувај Wi‑Fi скенирање во роаминг"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Користете наследен клиент на DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Мобилниот интернет е секогаш активен"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Оневозможете апсолутна јачина на звук"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Овие подесувања се наменети само за употреба за развој. Тие може да предизвикаат уредот и апликациите во него да се расипат или да се однесуваат необично."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Потврди апликации преку УСБ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Провери апликации инсталирани преку ADB/ADT за штетно однесување."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Ја оневозможува карактеристиката за апсолутна јачина на звук преку Bluetooth во случај кога ќе настанат проблеми со далечинските уреди, како на пр., неприфатливо силен звук или недоволна контрола."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Овозможи апликација на терминал што овозможува локален пристап кон школка."</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Проверување HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Осветли екран при. долги операции на главна нишка"</string>
<string name="pointer_location" msgid="6084434787496938001">"Локација на покажувач"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Прекривката на екран ги покажува тековните податоци на допир"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Прикажувај допири"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Прикажи визуелни повратни информации за допири"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Прикажи ажурир. површина"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Осветли површ. на прозорци при нивно ажурирање"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Прикажи ажурир. со GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Принуд. дозволете апликации на надворешна меморија"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Запишува апл. во надв.меморија, незав. од манифест"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Принуди ги активностите да ја менуваат големината"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ги прави сите активности да бидат со променлива големина за мултипрозорец, без разлика на вредностите на манифестот."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Направете сите активности да бидат со променлива големина за повеќе прозорци, без разлика на вредностите на манифестот."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Овозможи поддршка за експериментални прозорци со слободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Резервна лозинка за работна површина"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Целосни резервни копии на работната површина кои во моментов не се заштитени"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Допрете за да се промени или отстрани лозинката за целосни резервни копии на работната површина"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Подесена нова лозинка на резервна копија"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата лозинка и потврдата не се исти"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Неуспешно подесување лозинка на резервна копија"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Оптимизирани бои за дигитална содржина"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивни апликации"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивно. Допрете за да смените."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Допрете за да смените."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Активни услуги"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Погледнете и контролирајте услуги што се моментално активни"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Ноќен режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Оневозможено"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Секогаш вклучено"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Автоматски"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Овозможи мултипроцесен WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Активирајте ги WebView-прикажувачите во изолиран процес."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Воведување WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Поставете воведување WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Избраната примена на WebView е оневозможена, а за да се користи, мора да се овозможи. Дали сакате да ја овозможите?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Избраната WebView имплементација е неважечка поради неажуриран список со избори за имплементација. Списокот ќе се ажурира сега."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертирајте до шифрирање датотеки"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертирај..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Датотеката е веќе шифрирана"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекција на боја"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Функцијата е експериментална и може да влијае на изведбата."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Преостанаа прибл. <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостанува приближно <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Не се полни"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не се полни"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Целосна"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Оневозможено од администраторот"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролирано од администраторот"</string>
+ <string name="home" msgid="8263346537524314127">"Почетна страница"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Пред <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Преостанаа <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 7df1cf35a0b5..24ad333085f0 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"ടെക്‌സ്റ്റ്-ടു-സ്‌പീച്ച് ഔട്ട്‌പുട്ട്"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"വായന നിരക്ക്"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"വാചകം പറയുന്ന വേഗത"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"പിച്ച്"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"സിന്തസൈസ് ചെയ്ത സംസാരത്തിന്റെ സ്വരഭേദത്തെ ബാധിക്കുന്നു"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ഭാഷ"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"സി‌സ്റ്റം ഭാഷ ഉപയോഗിക്കുക"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ഭാഷ തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"എപ്പോഴും വൈഫൈ റോം സ്‌‌കാൻ അനുവദിക്കൂ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"പഴയ DHCP ക്ലയന്റ് ഉപയോഗിക്കുക"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"സെല്ലുലാർ ഡാറ്റ എല്ലായ്‌പ്പോഴും സജീവം"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ഈ ക്രമീകരണങ്ങൾ വികസന ഉപയോഗത്തിന് മാത്രമായുള്ളതാണ്. അവ നിങ്ങളുടെ ഉപകരണവും അതിലെ അപ്ലിക്കേഷനുകളും തകരാറിലാക്കുന്നതിനോ തെറ്റായി പ്രവർത്തിക്കുന്നതിനോ ഇടയാക്കാം."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB വഴി ആപ്സ് പരിശോധിച്ചുറപ്പിക്കൂ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"കേടാക്കുന്ന പ്രവർത്തനരീതിയുള്ള ADB/ADT വഴി ഇൻസ്റ്റാളുചെയ്‌ത അപ്ലിക്കേഷനുകൾ പരിശോധിക്കുക."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"അസ്വീകാര്യമായ തരത്തിൽ ഉയർന്ന വോളിയമോ ശബ്ദ നിയന്ത്രണത്തിന്റെ അഭാവമോ പോലെ, വിദൂര ഉപകരണങ്ങളുമായി ബന്ധപ്പെട്ട വോളിയം പ്രശ്നങ്ങൾ ഉണ്ടാകുന്ന സാഹചര്യത്തിൽ, Bluetooth അബ്‌സൊല്യൂട്ട് വോളിയം ഫീച്ചർ പ്രവർത്തനരഹിതമാക്കുന്നു."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"പ്രാദേശിക ടെർമിനൽ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"പ്രാദേശിക ഷെൽ ആക്‌സസ് നൽകുന്ന ടെർമിനൽ അപ്ലിക്കേഷൻ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP പരിശോധന"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ബാഹ്യമായതിൽ നിർബന്ധിച്ച് അനുവദിക്കുക"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ പ്രവർത്തനങ്ങളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുന്നു."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ ആക്ടിവിറ്റികളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുക."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുന്നു."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുക."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ഡെ‌സ്‌ക്ടോപ്പ് ബാക്കപ്പ് പാസ്‌വേഡ്"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്‌വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ ടാപ്പുചെയ്യുക"</string>
@@ -266,18 +270,15 @@
<item msgid="5363960654009010371">"ഡിജിറ്റൽ ഉള്ളടക്കത്തിനായി വർണ്ണങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്തു"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"നിഷ്‌ക്രിയ ആപ്പ്‌സ്"</string>
- <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"നിഷ്‌ക്രിയം. ടോഗിൾ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
- <string name="inactive_app_active_summary" msgid="4174921824958516106">"സജീവം. ടോഗിൾ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"നിഷ്‌ക്രിയം. മാറ്റുന്നതിനു ടാപ്പുചെയ്യുക."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"നൈറ്റ് മോഡ്"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"പ്രവർത്തനരഹിതമാക്കി"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"എല്ലായ്‌പ്പോഴും ഓണാണ്"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ഓട്ടോമാറ്റിക്"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"മൾട്ടിപ്രോസസ്സ് WebView പ്രവർത്തനക്ഷമമാക്കൂ"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ഒറ്റപ്പെട്ടൊരു പ്രോസസ്സിൽ WebView റെൻഡററുകൾ റൺ ചെയ്യുക."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView നടപ്പാക്കൽ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"തിരഞ്ഞെടുത്ത WebView നടപ്പാക്കൽ പ്രവർത്തനരഹിതമാക്കി, ഉപയോഗിക്കുന്നതിന് ഇത് പ്രവർത്തനക്ഷമമാക്കണം, പ്രവർത്തനക്ഷമമാക്കാൻ ആഗ്രഹിക്കുന്നുണ്ടോ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"തിരഞ്ഞെടുത്ത WebView നടപ്പാക്കൽ അസാധുവാണ്, കാരണം നടപ്പാക്കൽ തിരഞ്ഞെടുപ്പുകളുടെ ലിസ്റ്റ് പഴകിപ്പോയി. ഈ ലിസ്റ്റിപ്പോൾ അപ്‌ഡേറ്റ് ചെയ്യേണ്ടതുണ്ട്."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ഫയൽ എൻക്രിപ്ഷനിലേക്ക് പരിവർത്തിപ്പിക്കുക"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"പരിവർത്തിപ്പിക്കുക…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ഇതിനകം തന്നെ ഫയൽ എൻക്രിപ്റ്റ് ചെയ്തു"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ഈ ഫീച്ചർ പരീക്ഷണാത്മകമായതിനാൽ പ്രകടനത്തെ ബാധിച്ചേക്കാം."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഏകദേശം <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"നിറഞ്ഞു"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"അഡ്‌മിനിസ്ട്രേറ്റർ പ്രവർത്തനരഹിതമാക്കി"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"അഡ്‌മിൻ നിയന്ത്രിക്കുന്നത്"</string>
+ <string name="home" msgid="8263346537524314127">"ഹോം"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> മുമ്പ്"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index d4a3d44cbae1..5466ff1a6193 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Текст-яриа гаргах"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Ярианы түвшин"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Текстийг унших хурд"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Авиа тон"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Авоматаар үүссэн ярианы дуудлаганд нөлөөлдөг"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Хэл"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Системийн хэлийг ашиглах"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Хэл сонгогдоогүй байна"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Роум сканыг байнга зөвшөөрөх"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Хуучин DHCP харилцагчийг хэрэглэх"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Үүрэн холбооны датаг үргэлж идэвхтэй байлгана"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликешнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локал терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Локал суурьт хандалт хийх боломж олгодог терминалын апп-г идэвхжүүлэх"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP шалгах"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Апп-ыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааг олон цонхонд хэмжээг нь өөрчилж болохуйц болгох."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлдэг."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлнэ үү."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөшлөлтийн нууц үг"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Компьютерийн бүтэн нөөцлөлтийн нууц үгийг өөрчлөх, устгах бол дарна уу"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Идэвхтэй байна. Унтраах/асаахын тулд дарна уу."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Ажиллаж байгаа үйлчилгээнүүд"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Шөнийн горим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Идэвхгүй"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Байнга асаалттай"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Автоматаар"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView-н олон боловсруулалтыг идэвхжүүлэх"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView хөрвүүлэгчийг тусдаа боловсруулалтаар ажиллуулна уу."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView хэрэгжилт"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView хэрэгжилтийг тохируулах"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Сонгосон WebView хэрэгжүүлэлтийг идэвхгүй болгосон бөгөөд хэрэглэхийн тулд заавал идэвхжүүлэх шаардлагатай. Үүнийг идэвхжүүлэх үү?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Хэрэгжүүлэлтийн сонголтын жагсаалт хуучирсан тул сонгосон WebView хэрэгжүүлэлт хүчингүй байна. Жагсаалтыг одоо шинэчлэх болно."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файлын шифрлэлт болгон хөрвүүлэх"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Хөрвүүлэх..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Аль хэдийнэ файл шифрлэгдсэн"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Өнгө тохируулах"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Энэ функц туршилтынх бөгөөд ажиллагаанд нөлөөлж болзошгүй."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ойролцоогоор <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"дүүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Цэнэглэхгүй байна"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Цэнэглэхгүй байна"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Дүүрэн"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Админ идэвхгүй болгосон"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Админ удирдсан"</string>
+ <string name="home" msgid="8263346537524314127">"Нүүр"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> өмнө"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> үлдсэн"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 6a2bd61f80c0..ab55a3d9e1ad 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"टेक्स्ट-टू-स्पीच आउटपुट"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"बोलण्याचा रेट"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ज्या गतीने मजकूर बोलला जातो ती"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"पिच"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"संश्लेषित उच्चारांच्या आवाजास प्रभावित करते"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"भाषा"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"सिस्टम भाषा वापरा"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"भाषा निवडलेली नाही"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"वाय-फाय रोम स्‍कॅनला नेहमी अनुमती द्या"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"परंपरागत DHCP क्लायंटचा वापर करा"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा नेहमी सक्रिय"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"संपूर्ण आवाज अक्षम करा"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"या सेटिंग्जचा हेतू फक्त विकास करण्याच्या वापरासाठी आहे. त्यामुळे आपले डिव्हाइस आणि त्यावरील अनुप्रयोग विघटित होऊ शकतात किंवा गैरवर्तन करू शकतात."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB वरील अॅप्स सत्यापित करा"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानीकारक वर्तनासाठी ADB/ADT द्वारे स्थापित अॅप्स तपासा."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूरस्थ डिव्हाइसेसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटुथ संपूर्ण आवाज वैशिष्ट्य अक्षम करते."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानिक टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"स्थानिक शेल प्रवेश देणारा टर्मिनल अॅप सक्षम करा"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP तपासणी"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"मुख्य थ्रेडवर अॅप्स मोठी कार्ये करतात तेव्हा स्क्रीन फ्लॅश करा"</string>
<string name="pointer_location" msgid="6084434787496938001">"पॉइंटर स्थान"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"वर्तमान स्पर्श डेटा दर्शविणारे स्क्रीन आच्छादन"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"टॅप दर्शवा"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"टॅपसाठी दृश्यमान अभिप्राय दर्शवा"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"पृष्ठभाग अद्यतने दर्शवा"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"संपूर्ण विंडो पृष्ठभाग अद्ययावत होतात तेव्हा ते फ्‍लॅश करा"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU दृश्य अद्यतने दर्शवा"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यवर अॅप्सना अनुमती देण्याची सक्ती करा"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्‍यासाठी पात्र बनविते"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"क्र‍ियाकलापाचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करा."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"नवीन बॅक अप संकेतशब्द सेट झाला"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नवीन संकेतशब्द आणि पुष्टीकरण जुळत नाही"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"बॅक अप संकेतशब्द सेट करणे अयशस्वी"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"डिजिटल सामग्रीसाठी ऑप्टिमाइझ केलेले रंग"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"निष्क्रिय अ‍ॅप्स"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"निष्क्रिय. टॉगल करण्यासाठी टॅप करा."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"चालू सेवा"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"सध्या चालत असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"रात्र मोड"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"अक्षम केले"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"नेहमी चालू"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"स्वयंचलित"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"एकाधिक प्रक्रिया WebView सक्षम करा"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एक वेगळ्या प्रक्रियेत WebView प्रस्तुतकर्ते चालवा."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबदृश्य अंमलबजावणी सेट करा"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"निवडलेली WebView अंमलबजावणी अक्षम आहे आणि वापरण्यास सक्षम असणे आवश्यक आहे, आपण ती सक्षम करू इच्छिता?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"अंमलबजावणीची निवडींची सूची जुनी झाली असल्याने निवडलेली WebView अंमलबजावणी अवैध आहे."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फाईल कूटबद्धीकरणावर रूपांतरित करा"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करा..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फाईल आधीपासून कूटबद्ध केली"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"रंग सुधारणा"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"हे वैशिष्‍ट्य प्रायोगिक आहे आणि कदाचित कार्यप्रदर्शन प्रभावित करू शकते."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"अंदाजे. <xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - अंदाजे. <xliff:g id="TIME">%2$s</xliff:g> शिल्लक"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूर्ण होण्यात"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज होत नाही"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज होत नाही"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"प्रशासकाद्वारे अक्षम केलेले"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकाने नियंत्रित केलेले"</string>
+ <string name="home" msgid="8263346537524314127">"मुख्यपृष्ठ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पूर्वी"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> शिल्लक"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 42e9ddd40d6c..01b52c14c9da 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Output teks ke pertuturan"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Kadar pertuturan"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Kelajuan pertuturan teks"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pic"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Mempengaruhi nada pertuturan disintesiskan"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Bahasa"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Gunakan bahasa sistem"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Bahasa tidak dipilih"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sentiasa benarkan Imbasan Perayauan Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gunakan pelanggan DHCP lama"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tetapan ini adalah untuk penggunaan pembangunan sahaja. Peranti dan aplikasi yang terdapat padanya boleh rosak atau tidak berfungsi dengan betul."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Sahkan apl melalui USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Semak apl yang dipasang melalui ADB/ADT untuk tingkah laku yang berbahaya."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Lumpuhkan ciri kelantangan mutlak Bluetooth dalam kes isu kelantangan menggunakan peranti kawalan jauh seperti kelantangan yang sangat kuat atau tidak dapat mengawal."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal setempat"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Dayakan apl terminal yang menawarkan akses shell tempatan"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Penyemakan HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Kelip skrin apabila apl beroperasi lama pada urutan utama"</string>
<string name="pointer_location" msgid="6084434787496938001">"Lokasi penuding"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Tindihan skrin menunjukkan data sentuh semasa"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Tunjukkan ketikan"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Tunjukkan maklum balas visual untuk ketikan"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Tunjuk kemas kini permukaan"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Denyar permukaan tetingkap apabila dikemas kini"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Tunjuk kemas kini GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Benarkan apl secara paksa pada storan luaran"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Menjadikan sebarang apl layak ditulis ke storan luaran, walau apa juga nilai manifesnya"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Menjadikan semua aktiviti boleh diubah saiz untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bolehkan semua saiz aktiviti diubah untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Dayakan tetingkap bentuk bebas"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mendayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Dayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ketik untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh desktop"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Kata laluan sandaran baharu telah ditetapkan"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Kata laluan baharu dan pengesahan tidak sepadan"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menetapkan kata laluan sandaran"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Warna dioptimumkan untuk kandungan digital"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Apl yang tidak aktif"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Tidak aktif. Ketik untuk menogol."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktif. Ketik untuk menogol."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Perkhidmatan dijalankan"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Mod malam"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Dilumpuhkan"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sentiasa hidup"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatik"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Dayakan WebView berbilang proses"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Jalankan pemapar WebView dalam proses terpencil."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Pelaksanaan WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Tetapkan pelaksanaan WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Pelaksanaan WebView pilihan telah dilumpuhkan dan mesti didayakan untuk digunakan, adakah anda mahu mendayakannya?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Pelaksanaan WebView yang dipilih tidak sah kerana senarai pilihan pelaksanaan telah lapuk. Senarai itu seharusnya dikemas kini sekarang."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Tukar kepada penyulitan fail"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Tukar..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sudah disulitkan fail"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Pembetulan warna"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ciri ini adalah percubaan dan boleh menjejaskan prestasi."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kira-kira <xliff:g id="TIME">%1$s</xliff:g> lagi"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira. <xliff:g id="TIME">%2$s</xliff:g> yang tinggal"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga penuh"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Tidak mengecas"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Tidak mengecas"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dilumpuhkan oleh pentadbir"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikawal oleh pentadbir"</string>
+ <string name="home" msgid="8263346537524314127">"Skrin Utama"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> yang lalu"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> lagi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index bace8b645dd4..d3659b76c918 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"စာသားမှ အသံထွက်စေခြင်း"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"စကားပြောနှုန်း"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"စာတမ်းအားပြောဆိုသော အမြန်နှုန်း"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"အသံအနိမ့်အမြင့်"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"စက်ဖြင့်ထုတ်လုပ်ထားသည့် စကားသံကို အကျိုးသက်ရောက်မှုရှိပါမည်။"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ဘာသာစကား"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"စနစ်၏ ဘာသာစကားကို အသုံးပြုရန်"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ဘာသာစကား မရွေးချယ်ထားပါ။"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi ရွမ်းရှာဖွေမှုကို အမြဲတမ်း ခွင့်ပြုမည်"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"DHCP ကလိုင်းယင့် အဟောင်းအားသုံးရန်"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ဆဲလ်လူလာဒေတာ အမြဲတမ်းဖွင့်ထားသည်"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ဤဆက်တင်းများကို တည်ဆောက်ပြုပြင်ရာတွင် သုံးရန်အတွက်သာ ရည်ရွယ်သည်။ ၎င်းတို့သည် သင်၏စက်နှင့် အပလီကေးရှင်းများကို ရပ်စေခြင်း သို့ လုပ်ဆောင်ချက်မမှန်ကန်ခြင်းများ ဖြစ်ပေါ်စေနိုင်သည်။"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USBပေါ်မှ အပလီကေးရှင်းများကို အတည်ပြုစိစစ်ရန်"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT မှတဆင့် ထည့်သွင်းသော အပလီကေးရှင်းများကို အန္တရာယ်ဖြစ်နိုင်ခြင်း ရှိမရှိ စစ်ဆေးရန်။"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ချိတ်ဆက်ထားသည့် ကိရိယာတွင် လက်မခံနိုင်လောက်အောင် ဆူညံ သို့မဟုတ် ထိန်းညှိမရနိုင်သော အသံပိုင်းပြဿနာ ရှိခဲ့လျှင် ဘလူးတုသ် ပကတိ အသံနှုန်းကို ပိတ်ပါ။"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"လိုကယ်တာမီနယ်"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"local shell အသုံးပြုခွင့်ကမ်းလှမ်းသော တာမင်နယ်အပလီကေးရှင်းဖွင့်ပါ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP စစ်ဆေးမှု"</string>
@@ -246,12 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"အပြင်မှာ အတင်း ခွင့်ပြုရန်"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"မန်နီးဖက်စ် တန်ဖိုးမရွေး၊ လုပ်ဆောင်ချက် အားလုံး ဆိုက်ညှိရနိုင်အောင် လုပ်ပေးပါ။"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"မန်နီးဖက်စ်တန်ဖိုးများ မည်မျှပင်ရှိစေကာမူ၊ ဝင်းဒိုးများအတွက် လှုပ်ရှားမှုများအားလုံးကို အရွယ်အစားချိန်ခြင်း ပြုလုပ်ပါ။"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"အခမဲ့ပုံစံ ဝင်းဒိုးကို ဖွင့်ပါ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"စမ်းသပ်မှု အခမဲ့ပုံစံ ဝင်းဒိုးများအတွက် ပံ့ပိုးမှုကို ဖွင့်ပါ။"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ပုံစံမျိုးစုံဝင်းဒိုးများစမ်းသပ်မှုအတွက် အထောက်အပံ့ကိုဖွင့်ပါ"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"အလုပ်ခုံစက် အပြည့်အဝအရံကူးထားရန်အတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"စားပွဲတင်ကွန်ပျူတာကို အပြည့်အဝအရံကူးထားရန်အတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်အသစ်ကို သတ်မှတ်ပြီးပြီ။"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"စကားဝှက်အသစ်နှင့် အတည်ပြုချက် ကွဲလွဲနေသည်။"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်သတ်မှတ်ချက် မအောင်မြင်ပါ။"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"ပွင့်နေသည်။ ပြောင်းရန်တို့ပါ။"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ယခုအလုပ်လုပ်နေသောဝန်ဆောင်မှုကို ကြည့်ခြင်းနှင့် ထိန်းသိမ်းခြင်းအား ပြုလုပ်မည်လား?"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"ညသုံး မုဒ်"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"ပိတ်ထား"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"အမြဲတမ်း ဖွင့်ထားရန်"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"အလိုအလျောက်"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"လုပ်ငန်းဖြစ်စဉ်များစွာကြည့်နိုင်သည့် ဝဘ်မြင်ကွင်းကိုဖွင့်ပါ"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"လုပ်ငန်းဖြစ်စဉ်တစ်ခုတည်းအတွက် ဝဘ်မြင်ကွင်း အဖြစ်ပြုလုပ်ခြင်းကို ဖွင့်ပါ။"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView အကောင်အထည်ဖော်မှု"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView အကောင်အထည်ဖော်မှု သတ်မှတ်ပါ"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ရွေးချယ်ထားသည့် WebView လုပ်ဆောင်ခြင်းကို ပိတ်ထားသည်ပြီး အသုံးပြုရန်အတွက် ဖွင့်ရမည်၊ ဖွင့်လိုပါသလား။"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"ရွေးချယ်ထားသည့် ဝဘ်မြင်ကွင်းထည့်သွင်းမှု မမှန်ကန်ပါ၊ အဘယ့်ကြောင့်ဆိုသော် ရွေးချယ်ရန် ထည့်သွင်းမှုစာရင်းသည် အသစ်မဖြစ်တော့သောကြောင့်ဖြစ်သည်။ စာရင်းကို ယခုအပ်ဒိတ် ဖြစ်နေလောက်ပါပြီ။"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ဖိုင်လုံခြုံအောင်ပြုလုပ်ခြင်းသို့ ပြောင်းပါ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ပြောင်းရန်…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ဖိုင်ကို လုံခြုံအောင်ပြုလုပ်ပြီးပါပြီ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"အရောင်ပြင်ဆင်မှု"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ဒီအင်္ဂါရပ်မှာ စမ်းသပ်မှု ဖြစ်၍ လုပ်ကိုင်မှုကို အကျိုးသက်ရောက်နိုင်သည်။"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ခန့်မှန်းခြေ <xliff:g id="TIME">%1$s</xliff:g> ကျန်ပါသည်"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ခန့်မှန်းခြေ။ <xliff:g id="TIME">%2$s</xliff:g> ကျန်ရှိနေ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> အပြည့်အထိ"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
+ <string name="home" msgid="8263346537524314127">"ပင်မ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"ပြီးခဲ့သည့် <xliff:g id="ID_1">%1$s</xliff:g> က"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်ပါသည်"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 6843839eab2b..6865d5091d86 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Tekst-til-tale"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Talehastighet"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Hvor raskt teksten leses"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Stemmeleie"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Påvirker tonehøyden for syntetisert tale"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Språk"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Bruk systemspråk"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Språk er ikke valgt"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillat alltid skanning for Wi-Fi-roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Bruk eldre DHCP-klient"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse innstillingene er bare beregnet for bruk under programutvikling. De kan forårsake problemer med enheten din og tilhørende apper."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Bekreft apper via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sjekk apper som er installert via ADB/ADT for skadelig adferd."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Slår av funksjonen for absolutt volum via Bluetooth i tilfelle det oppstår volumrelaterte problemer med eksterne enheter, for eksempel uakseptabelt høyt volum eller mangel på kontroll."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktiver terminalappen som gir lokal kommandolistetilgang"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontroll"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Skjermblink ved lange apphandlinger på hovedtråd"</string>
<string name="pointer_location" msgid="6084434787496938001">"Pekerplassering"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Skjermoverlegg viser aktuelle berøringsdata"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Vis trykk"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Vis visuell tilbakemelding for trykk"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Vis overflateoppdateringer"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Fremhev hele vindusoverflater når de oppdateres"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Vis GPU-visningsoppdateringer"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tving frem tillatelse for ekstern lagring av apper"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gjør at apper kan skrives til ekstern lagring, uavhengig av manifestverdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Dette gjør at alle aktivitene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gjør at alle aktivitetene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Slå på vinduer i fritt format"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Slår på støtte for vinduer i eksperimentelt fritt format."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Slå på støtte for vinduer i eksperimentelt fritt format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Nytt passord for sikkerhetskopiering er angitt."</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Gjentakelsen av passordet er ikke identisk med det første du skrev inn"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Kunne ikke angi nytt passord for sikkerhetskopiering"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Farger som er optimalisert for digitalt innhold"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Inaktive apper"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Ikke aktiv. Trykk for å slå av/på."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Trykk for å slå av/på."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Aktive tjenester"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Se og kontrollér tjenester som kjører for øyeblikket"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nattmodus"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Slått av"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Slå på WebView for flere prosesser"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Kjør WebView-gjengivelser i en isolert prosess."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Angi WebView-implementering"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valgte implementeringen av nettvisningen er slått av – den må slås på for å brukes. Vil du slå den på?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Den valgte WebView-implementeringen er ugyldig fordi listen over implementeringsvalg er foreldet. Listen er nå oppdatert."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertér til kryptert fil"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertér …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Allerede kryptert og lagret som fil"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Fargekorrigering"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funksjonen er eksperimentell og kan påvirke ytelsen."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> gjenstår"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> igjen"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Lader ikke"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Lader ikke"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Avslått av administratoren"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrollert av administratoren"</string>
+ <string name="home" msgid="8263346537524314127">"Startside"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> gjenstår"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index a5fd19488f97..7742b9ddb277 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"पाठ-बाट-वाणी उत्पादन"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"वाणी दर"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"पाठ वाचन हुने गति"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"पिच"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"संश्लेषित बोलीको टोनमा प्रभाव पार्छ"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"भाषा"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"प्रणाली भाषा प्रयोग गर्नुहोस्"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"भाषा चयन गरिएको छैन"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"वाइफाइ घुम्ने स्क्यान गर्न सधैँ अनुमति दिनुहोस्"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"लिगेसी DHCP ग्राहक प्रयोग गर्नुहोस्"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"सेलुलर डेटा सधैं सक्रिय"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"यी सेटिङहरू केवल विकास प्रयोगको लागि विचार गरिएको हो। तिनीहरूले तपाईंको उपकरण र अनुप्रयोगहरूलाई विच्छेदन गर्न वा दुर्व्यवहार गर्न सक्दछ।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB मा अनुप्रयोगहरू रुजु गर्नुहोस्"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक व्यवहारको लागि ADB/ADT को माध्यमबाट स्थापित अनुप्रयोगहरूको जाँच गर्नुहोस्।"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"रिमोट यन्त्रहरूमा अस्वीकार्य चर्को आवाज वा नियन्त्रणमा कमी जस्ता आवाज सम्बन्धी समस्याहरूको अवस्थामा ब्लुटुथ निरपेक्ष आवाज सुविधालाई असक्षम गराउँछ।"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"स्थानीय सेल पहुँच प्रदान गर्ने टर्मिनल अनुप्रयोग सक्षम गर्नुहोस्"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जाँच गर्दै"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यमा बल प्रयोगको अनुमति प्राप्त अनुप्रयोगहरू"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउनुहोस्।"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"फ्रिफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थन सक्रिय गर्नुहोस्।"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटप ब्याकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटप पूर्ण जगेडाहरू हाललाई सुरक्षित छैनन्"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन ट्याप गर्नुहोस्"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"चलिरहेका सेवाहरू"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"रात्री मोड"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"असक्षम गरियो"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"सधैं खुल्‍ला"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"मल्टिप्रोसेस वेबभ्यु सक्षम गर्नुहोस्"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एउटा पृथक प्रक्रियामा वेबभ्यु रेन्डररहरू चलाउनुहोस्।"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट गर्नुहोस्"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"छनौट गरिएको WebView को कार्यान्वयन असक्षम गरिएको छ र प्रयोग गर्नका लागि सक्रिय गर्नुपर्छ, तपाईँ यसलाई सक्रिय गर्न चाहनुहुन्छ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"कार्यान्वयनको सूची पुरानो भइसकेको हुनाले छनोट गरिएको WebView को कार्यान्वयन अमान्य छ। सूची अब अद्यावधिक हुनुपर्छ।"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फाइल इन्क्रिप्सनमा रूपान्तरण गर्नुहोस्"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रुपान्तरण गर्नुहोस्…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"पहिल्यै फाइल इन्क्रिप्ट गरिएको छ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"रङ्ग सुधार"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यो सुविधा प्रयोगात्मक छ र प्रदर्शनमा असर गर्न सक्छ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%1$s</xliff:g> बाँकी छ"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग। <xliff:g id="TIME">%2$s</xliff:g> बायाँ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूर्ण नभए सम्म"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"चार्ज भइरहेको छैन"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"चार्ज हुँदै छैन"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"प्रशासकद्वारा असक्षम गरिएको"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकद्वारा नियन्त्रित"</string>
+ <string name="home" msgid="8263346537524314127">"गृह"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> पहिले"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> बाँकी"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 99c09321349e..efee429d9c73 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Spraakuitvoer"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Spreeksnelheid"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Snelheid waarmee de tekst wordt gesproken"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Hoogte"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Is van invloed op de toon van de synthetisch gegenereerde spraak"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Taal"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Systeemtaal gebruiken"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Taal niet geselecteerd"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Oude DHCP-client gebruiken"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele gegevens altijd actief"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Deze instellingen zijn uitsluitend bedoeld voor ontwikkelingsgebruik. Je apparaat en apps kunnen hierdoor vastlopen of anders reageren."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps verifiëren via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Apps die zijn geïnstalleerd via ADB/ADT, controleren op schadelijk gedrag"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Hiermee wordt de functie voor absoluut volume van Bluetooth uitgeschakeld in geval van volumeproblemen met externe apparaten, zoals een onacceptabel hoog volume of geen volumeregeling."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokale terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Terminal-app inschakelen die lokale shell-toegang biedt"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-controle"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Toestaan van apps op externe opslag afdwingen"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hierdoor komt een app in aanmerking om te worden geschreven naar externe opslag, ongeacht de manifestwaarden"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Hiermee wordt het formaat van alle activiteiten aanpasbaar gemaakt, ongeacht de manifestwaarden."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Het formaat van alle activiteiten aanpasbaar maken, ongeacht de manifestwaarden."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Vensters met vrije vorm inschakelen"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Schakelt ondersteuning in voor vensters met experimentele vrije vorm."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ondersteuning voor vensters met experimentele vrije vorm inschakelen."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Wachtwoord desktopback-up"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tik om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Actief. Tik om te schakelen."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Actieve services"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Services die momenteel actief zijn, weergeven en beheren"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nachtmodus"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Uitgeschakeld"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Altijd aan"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Multiproces-WebView aan"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView-weergaveprogramma\'s uitvoeren in geïsoleerd proces."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementatie"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-implementatie instellen"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"De gekozen WebView-implementatie is uitgeschakeld en moet worden ingeschakeld voor gebruik. Wil je deze inschakelen?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"De geselecteerde WebView-implementatie is ongeldig omdat de lijst met implementatiekeuzes was verouderd. De lijst is nu geüpdatet."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converteren naar versleuteling op basis van bestanden"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converteren…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Al versleuteld op basis van bestanden"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kleurcorrectie"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Deze functie is experimenteel en kan invloed hebben op de prestaties."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> resterend"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ca. <xliff:g id="TIME">%2$s</xliff:g> resterend"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot vol"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Wordt niet opgeladen"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Wordt niet opgeladen"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Volledig"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Uitgeschakeld door beheerder"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ingesteld door beheerder"</string>
+ <string name="home" msgid="8263346537524314127">"Startpagina"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> geleden"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> resterend"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 407ec95ca3b2..15e66358c7d7 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"ਟੈਕਸਟ-ਟੂ-ਸਪੀਚ ਆਉਟਪੁਟ"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"ਸਪੀਚ ਰੇਟ"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ਸਪੀਡ ਜਿਸਤੇ ਟੈਕਸਟ ਬੋਲਿਆ ਜਾਂਦਾ ਹੈ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ਪਿਚ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ਬਣਾਵਟੀ ਬੋਲੀ ਦੇ ਲਹਿਜੇ \'ਤੇ ਅਸਰ ਪਾਉਂਦੀ ਹੈ"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ਭਾਸ਼ਾ"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"ਸਿਸਟਮ ਭਾਸ਼ਾ ਵਰਤੋ"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ਭਾਸ਼ਾ ਨਹੀਂ ਚੁਣੀ"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ਹਮੇਸ਼ਾਂ Wi‑Fi Roam Scans ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ਲੀਗੇਸੀ DHCP ਕਲਾਈਂਟ ਵਰਤੋ"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ਸੈਲਿਊਲਰ ਡੇਟਾ ਹਮੇਸ਼ਾ ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਵੌਲਯੂਮ ਨੂੰ ਅਯੋਗ ਬਣਾਓ"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ਇਹ ਸੈਟਿੰਗਾਂ ਕੇਵਲ ਵਿਕਾਸਕਾਰ ਦੀ ਵਰਤੋਂ ਲਈ ਹਨ। ਇਹ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਅਤੇ ਇਸਤੇ ਮੌਜੂਦ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਬ੍ਰੇਕ ਕਰਨ ਜਾਂ ਦੁਰਵਿਵਹਾਰ ਕਰਨ ਦਾ ਕਾਰਨ ਬਣ ਸਕਦੇ ਹਨ।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ਤੇ ਐਪਸ ਨੂੰ ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ਹਾਨੀਕਾਰਕ ਵਿਵਹਾਰ ਲਈ ADB/ADT ਰਾਹੀਂ ਇੰਸਟੌਲ ਕੀਤੇ ਐਪਸ ਦੀ ਜਾਂਚ ਕਰੋ।"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ਰਿਮੋਟ ਡੀਵਾਈਸਾਂ ਨਾਲ ਵੌਲਯੂਮ ਸਮੱਸਿਆਵਾਂ ਜਿਵੇਂ ਕਿ ਨਾ ਪਸੰਦ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਉੱਚੀ ਵੌਲਯੂਮ ਜਾਂ ਕੰਟਰੋਲ ਦੀ ਕਮੀ ਵਰਗੀ ਹਾਲਤ ਵਿੱਚ ਬਲੂਟੁੱਥ ਪੂਰਨ ਵੌਲਯੂਮ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਅਯੋਗ ਬਣਾਉਂਦਾ ਹੈ।"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ਸਥਾਨਕ ਟਰਮੀਨਲ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"ਟਰਮੀਨਲ ਐਪ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ ਜੋ ਸਥਾਨਕ ਸ਼ੈਲ ਪਹੁੰਚ ਆੱਫਰ ਕਰਦਾ ਹੈ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP ਜਾਂਚ"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ਐਪਸ ਨੂੰ ਬਾਹਰਲੇ ਤੇ ਜ਼ਬਰਦਸਤੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ਇੱਕ ਐਪ ਨੂੰ ਬਾਹਰਲੀ ਸਟੋਰੇਜ ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ ਤੇ ਵਿਚਾਰ ਕੀਤੇ ਬਿਨਾਂ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਮੁੜ-ਆਕਾਰ ਵਿੱਚ ਲਿਆਉਂਦੀ ਹੈ, ਚਾਹੇ ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ਼ ਕੁਝ ਵੀ ਹੋਣ।"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ਪ੍ਰਯੋਗਾਤਮਕ freeform windows ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ।"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ਪ੍ਰਯੋਗਮਈ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਓ।"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ਡੈਸਕਟੌਪ ਬੈਕਅਪ ਪਾਸਵਰਡ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ਡੈਸਕਟਾਪ ਦੇ ਮੁਕੰਮਲ ਬੈਕਅੱਪਾਂ ਲਈ ਪਾਸਵਰਡ ਨੂੰ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"ਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"ਰਾਤ ਮੋਡ"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"ਅਸਮਰੱਥ ਬਣਾਇਆ"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ਹਮੇਸ਼ਾ ਚਾਲੂ"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ਆਟੋਮੈਟਿਕ"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"ਬਹੁ-ਮੰਤਵ WebView ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ਕਿਸੇ ਵੱਖ ਕੀਤੀ ਗਈ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ WebView ਰੈਂਡਰਰਾਂ ਨੂੰ ਚਲਾਓ।"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ਅਮਲ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ਅਮਲ ਸੈੱਟ ਕਰੋ"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ਚੁਣਿਆ ਗਿਆ WebView ਅਮਲ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ, ਅਤੇ ਵਰਤੋਂ ਕਰਨ ਲਈ ਇਸ ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਜਾਣਾ ਜ਼ਰੂਰੀ ਹੈ, ਕੀ ਤੁਸੀਂ ਇਸ ਨੂੰ ਯੋਗ ਬਣਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"ਚੁਣਿਆ ਗਿਆ WebView ਅਮਲ ਅਵੈਧ ਹੈ ਕਿਉਂਕਿ ਅਮਲ ਚੋਣਾਂ ਦੀ ਸੂਚੀ ਪੁਰਾਣੀ ਹੋ ਗਈ ਹੈ। ਸੂਚੀ ਨੂੰ ਹੁਣ ਅੱਪਡੇਟ ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ।"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ਫ਼ਾਈਲ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕਰੋ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ਰੰਗ ਸੰਸ਼ੋਧਨ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਾਤਮਿਕ ਹੈ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਤੇ ਅਸਰ ਪਾ ਸਕਦੀ ਹੈ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਲਗਭਗ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ਪੂਰੀ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
+ <string name="home" msgid="8263346537524314127">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ਪਹਿਲਾਂ"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ਬਾਕੀ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 9902ad7df141..9d8d97a1bf34 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Zamiana tekstu na mowę"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Szybkość mowy"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Szybkość czytania tekstu"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tony"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Wpływa na dźwięk syntezatora mowy"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Język"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Użyj języka systemu"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nie wybrano języka"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Zawsze szukaj Wi-Fi w roamingu"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Użyj starszego klienta DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Te ustawienia są przeznaczone wyłącznie dla programistów. Ich użycie może spowodować uszkodzenie lub nieprawidłowe działanie urządzenia i zainstalowanych na nim aplikacji."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Zweryfikuj aplikacje przez USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sprawdź, czy aplikacje zainstalowane przez ADB/ADT nie zachowują się w szkodliwy sposób"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Wyłącza funkcję Głośność bezwzględna Bluetooth, jeśli występują problemy z urządzeniami zdalnymi, np. zbyt duża głośność lub brak kontroli."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokalny"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Włącz terminal, który umożliwia dostęp do powłoki lokalnej"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Sprawdzanie HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Wymuś zezwalanie na aplikacje w pamięci zewn."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Pozwala na zapis aplikacji w pamięci zewn. niezależnie od wartości w pliku manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Wymuś zmianę rozmiaru okien aktywności"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Umożliwia zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Zezwól na zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Włącz dowolny rozmiar okien"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Włącza obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Włącz obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Hasło kopii zapasowej"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dotknij, by zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze."</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktywna. Dotknij, by zmienić."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Uruchomione usługi"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Wyświetl obecnie uruchomione usługi i zarządzaj nimi"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Tryb nocny"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Wyłączone"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Zawsze włączone"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatycznie"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Włącz wieloprocesowy WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Uruchom WebView jako izolowany proces."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacja WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ustaw implementację WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Wybrana implementacja WebView jest wyłączona. Aby jej używać, musisz ją włączyć. Chcesz to zrobić?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Wybrana implementacja WebView jest nieprawidłowa – lista implementacji do wyboru straciła ważność. Musisz zaktualizować listę."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Przekształć na szyfrowanie plików"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Przekształć…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Pliki są już zaszyfrowane"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcja kolorów"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To jest funkcja eksperymentalna i może wpływać na działanie urządzenia."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Pozostało około <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostało ok. <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nie podłączony"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nie podłączony"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Naładowana"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Wyłączone przez administratora"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolowane przez administratora"</string>
+ <string name="home" msgid="8263346537524314127">"Ekran główny"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> temu"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Pozostało <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 923482bdd4cc..844ae4182ab1 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Frequência do som"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP legado"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ativar o app terminal que oferece acesso ao shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Ativo. Tocar para alternar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Visualizar e controlar os serviços em execução no momento"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modo noturno"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ativar WebView de vários processos"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executar renderizadores de WebView em um processo isolado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação do WebView escolhida está desativada e deve ser ativada para ser usada. Deseja ativá-la?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"A implementação de WebView escolhida é inválida, porque a lista de opções de implementação estava desatualizada. A lista deve estar atualizada agora."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para criptografia de arquivos"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Já criptografado com base em arquivos"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção de cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está carregando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativada pelo administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
+ <string name="home" msgid="8263346537524314127">"Início"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 840bd4179bed..115f9518421d 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Saída de texto para voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de voz"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade a que o texto é falado"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonalidade"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizar idioma do sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre a deteção de Wi-Fi em roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Utilizar cliente DHCP antigo"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estas definições destinam-se apenas a programação. Podem fazer com que o seu aparelho e as aplicações nele existentes falhem ou funcionem mal."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicações de USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar as aplicações instaladas via ADB/ADT para detetar comportamento perigoso."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa a funcionalidade de volume absoluto do Bluetooth caso existam problemas de volume com dispositivos remotos, como um volume insuportavelmente alto ou a ausência de controlo."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ativar aplicação terminal que oferece acesso local à shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forçar perm. de aplicações no armazenamento ext."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualquer aplic. pode ser gravada no arm. ext., independ. dos valores do manif."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Palavra-passe cópia do comp."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tocar para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Ativo. Toque para ativar/desativar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ver e controlar os serviços actualmente em execução"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modo noturno"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Desativado"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativado"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ativar WebView multiprocessos"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executar renderizadores WebView num processo isolado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementação WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação WebView escolhida foi desativada e tem de ser ativada para poder ser utilizada. Pretende ativá-la?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"A implementação WebView escolhida é inválida porque a lista de opções de implementação encontra-se desatualizada. A lista deve ser atualizada agora."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para a encriptação de ficheiros"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Os ficheiros já estão encriptados"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção da cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta funcionalidade é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Resta(m) aproximadamente <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – resta(m) aprox. <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar completa"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Não está a carregar"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está a carregar"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completo"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativado pelo administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlado pelo administrador"</string>
+ <string name="home" msgid="8263346537524314127">"Página inicial"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Há <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Resta(m) <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 923482bdd4cc..844ae4182ab1 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Frequência do som"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma não selecionado"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Usar cliente DHCP legado"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Ativar o app terminal que oferece acesso ao shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificação HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Ativo. Tocar para alternar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Visualizar e controlar os serviços em execução no momento"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modo noturno"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Ativar WebView de vários processos"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Executar renderizadores de WebView em um processo isolado."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação do WebView escolhida está desativada e deve ser ativada para ser usada. Deseja ativá-la?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"A implementação de WebView escolhida é inválida, porque a lista de opções de implementação estava desatualizada. A lista deve estar atualizada agora."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para criptografia de arquivos"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Já criptografado com base em arquivos"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção de cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Não está carregando"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativada pelo administrador"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
+ <string name="home" msgid="8263346537524314127">"Início"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index 30d6cf3a7819..1f0e05b1156e 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -125,7 +125,7 @@
<item msgid="3191973083884253830">"Niciuna"</item>
<item msgid="9089630089455370183">"Logcat"</item>
<item msgid="5397807424362304288">"Systrace (imagini)"</item>
- <item msgid="1340692776955662664">"Apelaţi stiva pentru glGetError"</item>
+ <item msgid="1340692776955662664">"Apelați stiva pentru glGetError"</item>
</string-array>
<string-array name="show_non_rect_clip_entries">
<item msgid="993742912147090253">"Dezactivat"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 02cc80eecf54..0faf848c8c25 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -85,7 +85,7 @@
<string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Semnal Wi-Fi: complet."</string>
<string name="process_kernel_label" msgid="3916858646836739323">"Sistem de operare Android"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicații eliminate"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaţii și utilizatori eliminaţi"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicații și utilizatori eliminați"</string>
<string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering prin USB"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portabil"</string>
<string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering prin Bluetooth"</string>
@@ -101,8 +101,10 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Transformare text în vorbire"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Ritmul vorbirii"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Viteza cu care este vorbit textul"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Înălțime"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afectează tonalitatea vorbirii sintetizate"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Limbă"</string>
- <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizaţi limba sistemului"</string>
+ <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizați limba sistemului"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nu ați selectat limba"</string>
<string name="tts_default_lang_summary" msgid="5219362163902707785">"Setează vocea caracteristică limbii pentru textul vorbit"</string>
<string name="tts_play_example_title" msgid="7094780383253097230">"Ascultați un exemplu"</string>
@@ -110,7 +112,7 @@
<string name="tts_install_data_title" msgid="4264378440508149986">"Instalați date vocale"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"Instalați datele vocale necesare pentru sintetizarea vorbirii"</string>
<string name="tts_engine_security_warning" msgid="8786238102020223650">"Acest motor de sintetizare a vorbirii poate culege în întregime textul vorbit, inclusiv datele personale cum ar fi parolele și numerele cărților de credit. Metoda provine de la motorul <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Permiteți utilizarea acestui motor de sintetizare a vorbirii?"</string>
- <string name="tts_engine_network_required" msgid="1190837151485314743">"Pentru rezultatul transformării textului în vorbire pentru această limbă este necesară o conexiune de rețea care să funcţioneze."</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"Pentru rezultatul transformării textului în vorbire pentru această limbă este necesară o conexiune de rețea care să funcționeze."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Acesta este un exemplu de sintetizare a vorbirii"</string>
<string name="tts_status_title" msgid="7268566550242584413">"Starea limbii prestabilite"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> este acceptată integral"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Se permite întotdeauna scanarea traficului Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Folosiți vechiul client DHCP"</string>
<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="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>
@@ -174,7 +177,7 @@
<string name="select_usb_configuration_title" msgid="2649938511506971843">"Selectați configurația USB"</string>
<string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Selectați configurația USB"</string>
<string name="allow_mock_location" msgid="2787962564578664888">"Permiteți locațiile fictive"</string>
- <string name="allow_mock_location_summary" msgid="317615105156345626">"Permiteți locaţiile fictive"</string>
+ <string name="allow_mock_location_summary" msgid="317615105156345626">"Permiteți locațiile fictive"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Activați inspectarea atributelor de vizualizare"</string>
<string name="legacy_dhcp_client_summary" msgid="163383566317652040">"Folosiți clientul DHCP din Lollipop în locul noului client Android DHCP."</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Păstrați întotdeauna conexiunea de date mobile activată, chiar și atunci când funcția Wi‑Fi este activată (pentru comutarea rapidă între rețele)."</string>
@@ -182,9 +185,10 @@
<string name="adb_warning_message" msgid="7316799925425402244">"Depanarea USB are exclusiv scopuri de dezvoltare. Utilizați-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Revocați accesul la remedierea erorilor prin USB de pe toate computerele pe care le-ați autorizat anterior?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Permiteți setările pentru dezvoltare?"</string>
- <string name="dev_settings_warning_message" msgid="2298337781139097964">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcţioneze sau să funcţioneze necorespunzător."</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcționeze sau să funcționeze necorespunzător."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificați aplicațiile prin USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificați aplicațiile instalate utilizând ADB/ADT, pentru a detecta un comportament dăunător."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dezactivează funcția Bluetooth de volum absolut în cazul problemelor de volum apărute la dispozitivele la distanță, cum ar fi volumul mult prea ridicat sau lipsa de control asupra acestuia."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Aplicație terminal locală"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Activați aplicația terminal care oferă acces la shell local"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Verificare HDCP"</string>
@@ -192,11 +196,11 @@
<string name="debug_debugging_category" msgid="6781250159513471316">"Depanare"</string>
<string name="debug_app" msgid="8349591734751384446">"Selectați aplicația de depanare"</string>
<string name="debug_app_not_set" msgid="718752499586403499">"Nu ați setat o aplicație de depanare"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"Aplicaţie de depanare: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="select_application" msgid="5156029161289091703">"Selectaţi o aplicație"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"Aplicație de depanare: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"Selectați o aplicație"</string>
<string name="no_application" msgid="2813387563129153880">"Niciuna"</string>
- <string name="wait_for_debugger" msgid="1202370874528893091">"Aşteptaţi depanatorul"</string>
- <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Înaintea executării, aplicația aşteaptă atașarea depanatorului"</string>
+ <string name="wait_for_debugger" msgid="1202370874528893091">"Așteptați depanatorul"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Înaintea executării, aplicația așteaptă atașarea depanatorului"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Intrare"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Desen"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Redare accelerată hardware"</string>
@@ -216,7 +220,7 @@
<string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Straturile hardware clipesc verde la actualizare"</string>
<string name="debug_hw_overdraw" msgid="2968692419951565417">"Depanați suprapunerea"</string>
<string name="disable_overlays" msgid="2074488440505934665">"Dezactivați suprapun. HW"</string>
- <string name="disable_overlays_summary" msgid="3578941133710758592">"Utilizaţi mereu GPU pentru compunerea ecranului"</string>
+ <string name="disable_overlays_summary" msgid="3578941133710758592">"Utilizați mereu GPU pentru compunerea ecranului"</string>
<string name="simulate_color_space" msgid="6745847141353345872">"Simulați spațiu culoare"</string>
<string name="enable_opengl_traces_title" msgid="6790444011053219871">"Monitorizări OpenGL"</string>
<string name="usb_audio_disable_routing" msgid="8114498436003102671">"Dezactivați rutarea audio USB"</string>
@@ -237,7 +241,7 @@
<string name="transition_animation_scale_title" msgid="387527540523595875">"Scară tranziție animații"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Scară durată Animator"</string>
<string name="overlay_display_devices_title" msgid="5364176287998398539">"Simulați afișaje secundare"</string>
- <string name="debug_applications_category" msgid="4206913653849771549">"Aplicaţii"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"Aplicații"</string>
<string name="immediately_destroy_activities" msgid="1579659389568133959">"Nu păstrați activitățile"</string>
<string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Elimină activitățile imediat ce utilizatorul le închide"</string>
<string name="app_process_limit_title" msgid="4280600650253107163">"Limită procese fundal"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forțați accesul aplicațiilor la stocarea externă"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permiteți redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activați ferestrele cu formă liberă"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activează compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activați compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Parolă copie rez. desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"În prezent, copiile de rezervă complete pe desktop nu sunt protejate"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Atingeți ca să modificați sau să eliminați parola pentru backupurile complete pe desktop"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Activă. Atingeți pentru a comuta."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Servicii în curs de funcționare"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Vedeți și controlați serviciile care funcționează în prezent"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modul Noapte"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Dezactivată"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Activată permanent"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automat"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Activați WebView cu mai multe procese"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Rulați programele de redare WebView într-un proces izolat."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementare WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setați implementarea WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Implementarea WebView aleasă este dezactivată. Pentru a fi folosită, trebuie să fie activată. Doriți să o activați?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Implementarea WebView aleasă nu este validă, deoarece lista cu alegerile pentru implementare s-a învechit. Lista ar trebui să fie actualizată acum."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Faceți conversia la criptarea bazată pe sistemul de fișiere"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertiți…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Criptarea bazată pe sistemul de fișiere este finalizată"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corecția culorii"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Această funcție este experimentală și poate afecta performanțele."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Timp rămas: aproximativ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – timp rămas: aproximativ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcare completă"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nu se încarcă"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nu încarcă"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Complet"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dezactivată de administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlată de administrator"</string>
+ <string name="home" msgid="8263346537524314127">"Ecranul principal"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Acum <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Timp rămas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 57d288332478..09f792e696cf 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Синтез речи"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Скорость речи"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Скорость чтения текста"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Тон"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Влияет на высоту синтезированной речи"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Язык"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Язык системы"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Язык не выбран"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Всегда включать поиск сетей Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Использовать устаревший DHCP-клиент"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Не отключать передачу данных"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Отключить абсолютный уровень громкости"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Только для разработчиков. Изменение этих настроек может привести к сбоям или неправильной работе устройства и приложений."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Установка через USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверка безопасности приложений, устанавливаемых через ADB/ADT"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Отключить абсолютный уровень громкости Bluetooth при возникновении проблем на удаленных устройствах, например при слишком громком звучании или невозможности контролировать настройку."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локальный терминальный доступ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Разрешить терминальный доступ к локальной оболочке"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Проверка HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Подсвечивать экран во время длительных операций"</string>
<string name="pointer_location" msgid="6084434787496938001">"Отображать касания"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Визуализировать на экране нажатия и жесты"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Визуальный отклик"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Показывать места нажатия на экране"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Показ. обнов. поверхности"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Подсвечивать окна полностью при их обновлении"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Показывать обнов. экрана"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Разрешить сохранение на внешние накопители"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Позволяет менять размер в многооконном режиме (независимо от значений манифеста)"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Разрешить изменение размера в многооконном режиме (независимо от значений манифеста)"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Разрешить создание окон произвольной формы"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Включить экспериментальную функцию создания окон произвольной формы"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Включить экспериментальную функцию создания окон произвольной формы"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Нажмите, чтобы изменить или удалить пароль для резервного копирования"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Новый пароль для резервной копии установлен"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Пароли не совпадают"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Не удалось установить пароль для резервной копии"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Цвета, оптимизированные для цифрового контента"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивные приложения"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Выключено. Нажмите, чтобы включить."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Включено. Нажмите, чтобы отключить."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Работающие приложения"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Просмотр и управление работающими приложениями"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Ночной режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Отключено"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Всегда включено"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Автоматическое переключение"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Включить многопроц. WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Выполнять обработчики WebView в изолированном процессе"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Сервис WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Настройки сервиса WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Чтобы использовать сервис WebView, включите его. Сделать это?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Выбранный сервис WebView не поддерживается. Список сервисов устарел и сейчас будет обновлен."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Переход к шифрованию файлов"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Перейти…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шифрование файлов уже включено"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Коррекция цвета"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Это экспериментальная функция, она может снизить производительность устройства."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Осталось примерно <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – осталось около <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Не заряжается"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не заряжается"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Батарея заряжена"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Отключено администратором"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролируется администратором"</string>
+ <string name="home" msgid="8263346537524314127">"Главная"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> назад"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Осталось <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index 6d178a90162b..20cff85482ee 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"පෙළ-සිට-කථන ප්‍රතිදානය"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"කථන ශීඝ්‍රතාව"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"පෙළ කථා කරනා වේගය"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"තාරතාව"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"සංශ්ලේෂණය කළ කථනයෙහි ස්වරයට බලපායි"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"භාෂාව"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"පද්ධති භාෂාව භාවිතා කරන්න"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"භාෂාව තෝරා ගෙන නැත"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi රෝම් පරිලෝකන වෙතට සැමවිට අවසර දෙන්න"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ලෙගසි DHCP සේවාලාභියා භාවිත කරන්න"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"සෙලියුලර් දත්ත සැමවිට ක්‍රියාකාරීය"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"මෙම සැකසීම් වර්ධක භාවිතය සඳහා පමණි. ඔබගේ උපාංගයේ සහ යෙදුම්වල අක්‍රිය වීමට හෝ වැරදි ක්‍රියා කෙරුමකට ඒවා බලපෑ හැක."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ඔස්සේ යෙදුම් සත්‍යාපනය කරගන්න"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT හරහා ස්ථාපනය වූ යෙදුම්, විනාශකාරී ක්‍රියාවන් ඇත්දැයි පරික්ෂාකර බලන්න."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"පිළිගත නොහැකි ලෙස වැඩි හඩ පරිමාව හෝ පාලනය නොමැති වීම යනාදී දුරස්ථ උපාංග සමගින් වන හඬ පරිමා ගැටලුවලදී බ්ලූටූත් නිරපේක්ෂ හඬ පරිමා විශේෂාංගය අබල කරයි."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"අභ්‍යන්තර අන්තය"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"දේශීය ෂෙල් ප්‍රවේශනය පිරිනමන ටර්මිනල් යෙදුම සබල කරන්න"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP පරික්ෂාව"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"මූලික පොටේ යෙදුම්, දිගු මෙහෙයුම් කරන විට තිරය ෆ්ලෑෂ් කරන්න"</string>
<string name="pointer_location" msgid="6084434787496938001">"සූචක පිහිටීම"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"තිර උඩැතිරිය වර්තමාන ස්පර්ශ දත්ත පෙන්වයි"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"තට්ටු කිරීම් පෙන්වන්න"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"තට්ටු කිරීම් සඳහා දෘශ්‍ය ප්‍රතිපෝෂණ පෙන්වන්න"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"පෘෂ්ඨ යාවත්කාලීන පෙන්වන්න"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"යාවත්කාලින වනවිට මුළු කවුළු තලයම දැල්වෙන්න"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU පෙනුම් යාවත්කාලීන පෙන්වන්න"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"බාහිර මත යෙදුම් ඉඩ දීම බල කරන්න"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්‍යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ක්‍රියාකාරකම් ප්‍රතිප්‍රමාණ කළ හැකි බවට බල කරන්න"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළු සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරයි."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළුව සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරන්න."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරයි."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරන්න."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට තට්ටු කරන්න"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"නව උපස්ථ මුරපදය සකසන ලදි"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"නව මුරපදය සහ සත්‍යාපනය නොගැළපුනි"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"උපස්ථ මුරපදය පිහිටුවීම අසාර්ථකය"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"ඩිජිටල් අන්තර්ගතය සඳහා වර්ණ ප්‍රශස්ත කරන ලද"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"අක්‍රිය යෙදුම්"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"අක්‍රියයි. ටොගල කිරීමට තට්ටු කරන්න."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"සක්‍රියයි. ටොගල කිරීමට තට්ටු කරන්න."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"ධාවනය වන සේවා"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"රාත්‍රී ප්‍රකාරය"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"අබලයි"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"සැමවිට ක්‍රියාත්මක"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"ස්වයංක්‍රීය"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"බහු සැකසීම් WebView සබල කරන්න"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"හුදකලා වූ ක්‍රියාවලියක WebView විදහා දැක්වීම් ධාවනය කරන්න."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ක්‍රියාත්මක කිරීම"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ක්‍රියාත්මක කිරීම සකසන්න"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"තෝරන ලද WebView ක්‍රියාත්මක කිරීම අබල අතර, භාවිත කිරීමට සබල කළ යුතුය, ඔබ එය සබල කිරීමට අදහස් කරන්නේද?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"තෝරන ලද WebView ක්‍රියාත්මක කිරීම ක්‍රියාත්මක කිරීම් තේරීම් ලැයිස්තු යල් පැන ඇති නිසා වලංගු නැත. ලැයිස්තුව දැන් යාවත්කාලීන කළ යුතුය."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ගොනු සංකේතනයට පරිවර්තනය කරන්න"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"පරිවර්තනය කරන්න..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"දැනටමත් ගොනුව සංකේතනය කර ඇත"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"වර්ණ නිවැරදි කිරීම"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"මෙම විශේෂාංගය පරීක්ෂණාත්මක සහ ඇතැම් විට ක්‍රියාකාරිත්වයට බලපෑ හැක."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"දළ වශයෙන් <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරිය"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආසන්න <xliff:g id="TIME">%2$s</xliff:g> වම"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පුර්ණ වන තෙක්"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ආරෝපණය නොවේ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ආරෝපණය නොවෙමින්"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"පූර්ණ"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"පරිපාලක විසින් අබල කරන ලදී"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
+ <string name="home" msgid="8263346537524314127">"මුල් පිටුව"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>කට පෙර"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g>ක් ඉතිරිය"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 658b01440070..5640b1371ccd 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Výstup prevodu textu na reč"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Rýchlosť reči"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Rýchlosť hovoreného textu"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Výška"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Určuje zvuk syntetizovaného hlasu"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Jazyk"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Používať jazyk systému"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nebol vybratý jazyk"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povoliť funkciu Wi-Fi Roam Scans"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Použiť starý klient DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tieto nastavenia sú určené len pre vývojárov. Môžu spôsobiť poruchu alebo nesprávne fungovanie zariadenia a nainštalovaných aplikácií."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Overovať aplikácie z USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovať škodlivosť aplikácií nainštalovaných pomocou nástroja ADB alebo ADT"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Umožňuje zakázať funkciu absolútnej hlasitosti rozhrania Bluetooth v prípade problémov s hlasitosťou na vzdialených zariadeniach, ako je napríklad neprijateľne vysoká hlasitosť alebo absencia ovládacích prvkov."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Miestny terminál"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Povoliť terminálovú apl. na miestny prístup k prostrediu shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrola HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Vynútiť povolenie aplikácií na externom úložisku"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Povoliť okná s voľným tvarom"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Povolenie podpory pre experimentálne okná s voľným tvarom."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Povolenie podpory pre experimentálne okná s voľným tvarom."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pre zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy na počítači nie sú momentálne chránené"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Klepnutím zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktívne. Prepnite klepnutím."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Spustené služby"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Zobrazenie a ovládanie aktuálne spustených služieb"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nočný režim"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Vypnuté"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuté"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Povoliť viacprocesové moduly WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Spúšťať vykresľovacie moduly WebView v izolovanom procese."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementácia komponenta WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavenie implementácie komponenta WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Zvolená implementácia technológie WebView je zakázaná. Ak ju chcete použiť, musíte ju najprv povoliť. Chcete ju povoliť?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Zvolená implementácia komponenta WebView nie je platná, pretože zoznam volieb implementácie nie je aktuálny. Zoznam by už mal byť aktualizovaný."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertovať na šifrovanie súborov"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertovať…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Súbory sú už šifrované"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Úprava farieb"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkcia je experimentálna a môže mať vplyv na výkonnosť."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zostáva cca. <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostáva približne <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nenabíja sa"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nenabíja sa"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Zakázané správcom"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ovládané správcom"</string>
+ <string name="home" msgid="8263346537524314127">"Domov"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"pred <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Zostáva <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 7b63d5d6e943..ffe794e0fad9 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Besedilo v govor"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Hitrost govora"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Hitrost govorjenega besedila"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Višina tona"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Vpliva na ton sintetiziranega govora"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Uporabi sistemski jezik"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik ni izbran"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vedno omogoči iskanje omrežij Wi-Fi za gostovanje"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Uporaba starejšega odjemalca DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Te nastavitve so namenjene samo za razvijanje in lahko povzročijo prekinitev ali napačno delovanje naprave in aplikacij v njej."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Preveri aplikacije prek USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogoči funkcijo absolutnega praga glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Preverjanje HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Vsili omogočanje aplikacij v zunanji shrambi"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Omogočanje oken svobodne oblike"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogočanje podpore za poskusna okna svobodne oblike"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogočanje podpore za poskusna okna svobodne oblike"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Geslo za varn. kop. rač."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Popolne varnostne kopije namizja trenutno niso zaščitene"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dotaknite se za preklop."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Zagnane storitve"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Preglejte in nadzorujte storitve, ki so trenutno zagnane"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nočni način"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Onemogočeno"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Vedno vklopljeno"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Samodejno"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogoči večprocesni WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Izvajanje upodabljalnikov za WebView v ločenem procesu."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Izvedba spletnega pogleda"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavitev izvedbe spletnega pogleda"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izbrana izvedba spletnega pogleda je onemogočena in jo morate omogočiti, če jo želite uporabljati. Ali jo želite omogočiti?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Izbrana izvedba komponente WebView je neveljavna zaradi zastaranja seznama izbir za izvedbo. Seznam bi zdaj moral biti posodobljen."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Preklop na šifriranje podatkov"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Preklop …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Šifriranje podatkov je že uveljavljeno"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Popravljanje barv"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To je preskusna funkcija in lahko vpliva na učinkovitost delovanja."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Še približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – še približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Se ne polni"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Se ne polni"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Poln"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogočil skrbnik"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Nadzira skrbnik"</string>
+ <string name="home" msgid="8263346537524314127">"Začetni zaslon"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Pred toliko časa: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Še <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index f5f3cf2c2031..c84430c6c42a 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Dalja \"tekst-në-ligjërim\""</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Shpejtësia e të folurit"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Shpejtësia me të cilën thuhet teksti"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tonaliteti"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ndikon te toni i ligjërimit të sintetizuar"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Gjuha"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Përdor gjuhën e sistemit"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nuk është përzgjedhur gjuha"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Lejo gjithmonë skanimet për Wi-Fi edhe kur je në lëvizje"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Përdor klientin DHCP të versionit paraprak"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Këto cilësime janë të projektuara vetëm për përdorim në programim. Ato mund të shkaktojnë që pajisja dhe aplikacionet në të, të mos punojnë ose të veprojnë në mënyrë të gabuar."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifiko apl. përmes USB-së"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollo aplikacionet e instaluara nëpërmjet ADB/ADT për sjellje të dëmshme."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Çaktivizon funksionin e volumit absolut të Bluetooth në rast të problemeve të volumit me pajisjet në largësi, si p.sh. një volum i lartë i papranueshëm ose mungesa e kontrollit."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminali lokal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivizo aplikacionin terminal që ofron qasje në guaskën lokale"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kontrolli HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Ndriço ekranin kur aplikacionet kryejnë operacione të gjata teksa bashkëveprojnë"</string>
<string name="pointer_location" msgid="6084434787496938001">"Vendndodhja e treguesit"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Mbivendosja e ekranit tregon të dhënat e prekjes"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Shfaq trokitjet"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Shfaq reagimet vizuale për trokitjet"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Shfaq përditësimet e sipërfaqes"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Ndriço të gjitha sipërfaqet e dritares kur ato të përditësohen"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Shfaq përditësimet e pamjes së GPU-së"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Detyro lejimin në hapësirën e jashtme"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bën që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bëj që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivizo dritaret me formë të lirë"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivizon mbështetjen për dritaret eksperimentale me formë të lirë."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivizo mbështetjen për dritaret eksperimentale me formë të lirë."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Fjalëkalimi rezervë i kompjuterit"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Trokit për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Fjalëkalimi i ri u vendos"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Fjalëkalimi i ri dhe konfirmimi nuk përputhen"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Vendosja e fjalëkalimit dështoi"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Ngjyra të optimizuara për përmbajtjet dixhitale"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Aplikacionet joaktive"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Joaktiv. Trokit për ta ndryshuar."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Trokit për ta ndryshuar."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Shërbimet në ekzekutim"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Modaliteti i natës"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Çaktivizuar"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Gjithmonë aktive"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatike"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktivizo WebView të multiprocesit"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ekzekuto renderizuesit e WebView në një proces të izoluar."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Zbatimi i WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Cakto zbatimin e WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Është çaktivizuar zbatimi i zgjedhur i WebView dhe duhet të aktivizohet për t\'u përdorur, dëshiron ta aktivizosh?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Zbatimi i WebView të zgjedhur është i pavlefshëm sepse lista e zgjedhjeve të zbatimit është bërë e pavlefshme. Lista duhet të përditësohet tani."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konverto në enkriptimin e skedarit"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konverto..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Enkriptimi i skedarit është kryer tashmë"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korrigjimi i ngjyrës"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ky funksion është eksperimental dhe mund të ndikojë në veprimtari."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Afërsisht <xliff:g id="TIME">%1$s</xliff:g> të mbetura"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - afërsisht <xliff:g id="TIME">%2$s</xliff:g> të mbetura"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të jetë e plotë"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Nuk po ngarkohet"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Nuk po ngarkohet"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"E mbushur"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Çaktivizuar nga administratori"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolluar nga administratori"</string>
+ <string name="home" msgid="8263346537524314127">"Kreu"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> më parë"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> të mbetura"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index e7b66f4ff41a..af3dabadb134 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Излаз за претварање текста у говор"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Брзина говора"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Брзина изговарања текста"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ниво"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Утиче на тон синтетизованог говора"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Језик"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Користи језик система"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Језик није изабран"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Увек дозволи скенирање Wi‑Fi-ја у ромингу"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Користи застарели DHCP клијент"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Подаци за мобилне уређаје су увек активни"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Онемогући главно подешавање јачине звука"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ова подешавања су намењена само за програмирање. Могу да изазову престанак функционисања или неочекивано понашање уређаја и апликација на њему."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Верификуј апликације преко USB-а"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверава да ли су апликације инсталиране преко ADB-а/ADT-а штетне."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Онемогућава главно подешавање јачине звука на Bluetooth уређају у случају проблема са јачином звука на даљинским уређајима, као што су изузетно велика јачина звука или недостатак контроле."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локални терминал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Омогући аплик. терминала за приступ локалном командном окружењу"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP провера"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Нека екран трепери када апликације обављају дуге операције на главној нити"</string>
<string name="pointer_location" msgid="6084434787496938001">"Локација показивача"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Постав. елемент са тренутним подацима о додиру"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Приказуј додире"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Приказуј визуелне повратне информације за додире"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Прикажи ажурирања површине"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Осветли све површине прозора када се ажурирају"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Прикажи ажур. GPU приказа"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Принудно дозволи апликације у спољној"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Омогући промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Омогући прозоре произвољног формата"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Омогућава подршку за експерименталне прозоре произвољног формата."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Омогућите подршку за експерименталне прозоре произвољног формата."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Постављена је нова лозинка резервне копије"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Нова лозинка и њена потврда се не подударају"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Постављање лозинке резервне копије није успело"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Боје оптимизоване за дигитални садржај"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Неактивне апликације"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивна. Додирните да бисте је активирали."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Активна. Додирните да бисте је деактивирали."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Покренуте услуге"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Приказ и контрола тренутно покренутих услуга"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Ноћни режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Онемогућено"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Увек укључено"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Аутоматски"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Омогући вишепроцесни WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Покрећите WebView приказиваче у оквиру изолованог процеса."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Изабрана примена WebView-а је онемогућена, а мора да буде омогућена ради коришћења. Желите ли да је омогућите?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Изабрана примена WebView-а је неважећа зато што је листа могућности за примену застарела. Сада би требало да ажурирате листу."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертуј у шифровање датотека"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертуј..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Већ се користи шифровање датотека"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекција боја"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ова функција је експериментална и може да утиче на перформансе."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Још отприлике <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостало око <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> док се не напуни"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Не пуни се"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не пуни се"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пуно"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Онемогућио је администратор"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролише администратор"</string>
+ <string name="home" msgid="8263346537524314127">"Почетни"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Пре <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Још <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 35c2e33d40da..1cd9b6f20ed5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Text-till-tal"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Talhastighet"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Talhastighet för texten"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Påverkar tonen i det syntetiska talet"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Språk"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Använd systemspråk"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Inget språk valt"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillåt alltid sökning efter Wi-Fi-roaming"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Använd äldre DHCP-klient"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Inställningarna är endast avsedda att användas för utvecklingsändamål. De kan orsaka problem med enheten eller apparna som finns installerade på den."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifiera appar via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollera om appar som installeras via ADB/ADT kan vara skadliga."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inaktivera Bluetooth-funktionen Absolute volume om det skulle uppstå problem med volymen på fjärrenheter, t.ex. alldeles för hög volym eller brist på kontroll."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Aktivera en terminalapp som ger åtkomst till hyllor lokalt"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP-kontroll"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tillåt appar i externt lagringsutrymme"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen kan skrivas till extern lagring, oavsett manifestvärden"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Framtvinga storleksanpassning för aktiviteter"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Detta gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivera frihandsfönster"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverar stöd för experimentella frihandsfönster."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivera stöd för experimentella frihandsfönster."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Lösenord för säkerhetskopia av datorn"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Tryck om du vill inaktivera."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Aktiva tjänster"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Visa och styr aktiva tjänster"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Nattläge"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Inaktiverad"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Automatiskt"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Aktivera WebView-multibearb."</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Kör WebView-renderare i en isolerad bearbetning."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ange WebView-implementering"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valda WebView-implementeringen har inaktiverats och måste aktiveras om du ska kunna använda den. Vill du aktivera den?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Den valda WebView-implementeringen är ogiltig eftersom listan med implementeringsalternativ blev inaktuell. Listan ska nu ha uppdaterats."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertera till filkryptering"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertera …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Filkryptering används redan"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Färgkorrigering"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Den här funktionen är experimentell och kan påverka prestandan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca <xliff:g id="TIME">%1$s</xliff:g> kvar"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca <xliff:g id="TIME">%2$s</xliff:g> kvar"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till fulladdat"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Laddar inte"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Laddar inte"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Har inaktiverats av administratören"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Strys av administratören"</string>
+ <string name="home" msgid="8263346537524314127">"Startsida"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"för <xliff:g id="ID_1">%1$s</xliff:g> sedan"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kvar"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index de30b764b3d9..24d626c10b29 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Kubadilisha maandishi hadi usemi"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Kiwango cha usemaji"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Kasi ya kutamkwa kwa maneno"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Giza"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Huathiri sauti ya matamshi yaliyounganishwa"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Lugha"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Tumia lugha ya mfumo"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Lugha haijachaguliwa"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Ruhusu Uchanganuzi wa Matumizi ya Mitandao mingine"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Tumia kiteja cha DHCP kilichopitwa na wakati"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Mipangilio hii imekusudiwa kwa matumizi ya usanidi tu. Inaweza kusababisha kifaa chako na programu zilizoko kuvunjika au kutofanya kazi vizuri."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Thibitisha programu kupitia USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kagua programu zilizosakinishwa kupitia ADB/ADT kwa tabia ya kudhuru."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Huzima kipengele cha Bluetooth cha sauti kamili kunapotokea matatizo ya sauti katika vifaa vya mbali kama vile sauti ya juu mno au inaposhindikana kuidhibiti."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Kituo cha karibu"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Washa programu ya mwisho inayotoa ufikiaji mkuu wa karibu"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Inakagua HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Lazima uruhusu programu kwenye hifadhi ya nje"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwa ajili ya dirisha nyingi, bila kujali thamani za faili ya maelezo."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwenye madirisha mengi, bila kuzingatia thamani za faili ya maelezo."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Washa madirisha yenye muundo huru"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Huwasha uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ruhusu uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Gonga ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Inatumika. Gonga ili ugeuze."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Huduma zinazoendeshwa"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Onyesha na dhibiti huduma zinazoendeshwa kwa sasa"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Hali ya usiku"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Imezimwa"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Imewashwa kila wakati"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Otomatiki"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Washa WebView ya michakato mingi"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Tekeleza vitoaji huduma vya WebView katika mchakato mahususi."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Utekelezaji wa WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Weka utekelezaji wa WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Kipengee ulichochagua cha utekelezaji wa WebView kimezimwa. Ni lazima ukiwashe ili kitumike. Ungependa kukiwasha?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Utekelezaji wa WebView uliochaguliwa si sahihi kwa sababu orodha ya chaguo za utekelezaji imepitwa na muda. Ni sharti usasishe orodha sasa."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Badilisha kuwa usimbaji fiche wa faili"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Badilisha..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Tayari faili imesimbwa kwa njia fiche"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Usahihishaji wa rangi"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Kipengele hiki ni cha majaribio na huenda kikaathiri utendaji."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zimesalia takribani <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia takriban <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Haichaji"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Haichaji"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Imejaa"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Msimamizi amezima mapendeleo ya mipangilio"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Imedhibitiwa na msimamizi"</string>
+ <string name="home" msgid="8263346537524314127">"Mwanzo"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"Zimepita <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Zimesalia <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index af2d9c3a3405..adc75e99e9d4 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"உரையிலிருந்து பேச்சாக மாற்றுதல்"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"பேச்சு வீதம்"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"பேசப்படும் உரையின் வேகம்"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ஒலித்திறன்"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"தொகுக்கப்பட்ட உரையின் டோன் பாதிக்கப்படும்"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"மொழி"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"முறைமையின் மொழியைப் பயன்படுத்து"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"மொழி தேர்ந்தெடுக்கப்படவில்லை"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"எப்போதும் வைஃபை ரோமிங் ஸ்கேன்களை அனுமதி"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"அதிகாரப்பூர்வ DHCP க்ளையன்ட்டைப் பயன்படுத்து"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"செல்லுலார் தரவு எப்போதும் இயக்கத்தில்"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"இந்த அமைப்பு மேம்பட்டப் பயன்பாட்டிற்காக மட்டுமே. உங்கள் சாதனம் மற்றும் அதில் உள்ள பயன்பாடுகளைச் சிதைக்கும் அல்லது தவறாகச் செயல்படும் வகையில் பாதிப்பை ஏற்படுத்தும்."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB பயன்பாடுகளை சரிபார்"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"தீங்கு விளைவிக்கும் செயல்பாட்டை அறிய ADB/ADT மூலம் நிறுவப்பட்டப் பயன்பாடுகளைச் சரிபார்."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"மிகவும் அதிகமான ஒலியளவு அல்லது கட்டுப்பாடு இழப்பு போன்ற தொலைநிலைச் சாதனங்களில் ஏற்படும் ஒலி தொடர்பான சிக்கல்கள் இருக்கும் சமயங்களில், புளூடூத் அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கும்."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"அக முனையம்"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் பயன்பாட்டை இயக்கு"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP சரிபார்ப்பு"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"முக்கிய தொடரிழையில் நீண்ட நேரம் செயல்படும்போது திரையைக் காட்சிப்படுத்து"</string>
<string name="pointer_location" msgid="6084434787496938001">"குறிப்பான் இடம்"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"திரையின் மேல் அடுக்கானது தற்போது தொடப்பட்டிருக்கும் தரவைக் காண்பிக்கிறது"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"தட்டல்களைக் காட்டு"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"தட்டல்கள் குறித்த காட்சி வடிவக் கருத்தைக் காட்டு"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"மேலோட்ட புதுப்பிப்புகளைக் காட்டு"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"சாளரத்தின் பரப்புநிலைகள் புதுப்பிக்கப்படும்போது, அவற்றை முழுவதுமாகக் காட்டு"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU காட்சி புதுப்பிப்புகளைக் காட்டு"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"பயன்பாடுகளை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமைக்கும்."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"பரிசோதனைக்குரிய குறிப்பிட்ட வடிவமில்லாத சாளரங்களுக்கான ஆதரவை இயக்கும்."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"சாளரங்களை அளவுமாற்ற மற்றும் எங்கும் நகர்த்த அனுமதிக்கும் பரிசோதனைக்குரிய அம்சத்திற்கான ஆதரவை இயக்கு."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"டெஸ்க்டாப்பின் முழுக் காப்புப் பிரதிகளுக்கான கடவுச்சொல்லை மாற்ற அல்லது அகற்ற, தட்டவும்"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"புதிய காப்புப் பிரதியின் கடவுச்சொல் அமைக்கப்பட்டது"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"புதிய கடவுச்சொல்லும், உறுதிப்படுத்தலுக்கான கடவுச்சொல்லும் பொருந்தவில்லை"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"காப்புப் பிரதி கடவுச்சொல்லை அமைப்பதில் தோல்வி"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"டிஜிட்டல் உள்ளடக்கத்திற்கு ஏற்ப மேம்படுத்தப்பட்ட வண்ணங்கள்"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"செயலில் இல்லாத பயன்பாடுகள்"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"செயலில் இல்லை. மாற்ற, தட்டவும்."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"செயலில் உள்ளது. மாற்ற, தட்டவும்."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"இயங்கும் சேவைகள்"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"இரவு பயன்முறை"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"முடக்கப்பட்டது"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"எப்போதும் இயக்கத்தில் வை"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"தானியங்கு"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"பல செயல்முறை WebViewஐ இயக்கு"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"தனிப்படுத்தப்பட்ட செயல்முறையில் WebView ரெண்டரர்களை இயக்கு."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView செயல்படுத்தல்"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView செயல்படுத்தலை அமை"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"தேர்வுசெய்த WebView செயல்படுத்தல் முடக்கப்பட்டுள்ளது, பயன்படுத்த வேண்டுமெனில் அதைக் கண்டிப்பாக இயக்க வேண்டும். இயக்க விரும்புகிறீர்களா?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"தேர்வுசெய்த WebView செயல்படுத்தல் தவறானது. ஏனெனில் செயல்படுத்தல் விருப்பங்கள் பட்டியல் காலாவதியாகியுள்ளது. பட்டியலை இப்போது புதுப்பிக்க வேண்டும்."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"கோப்பு முறைமையாக்கத்திற்கு மாற்று"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"மாற்று…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ஏற்கனவே கோப்பு முறைமையாக்கப்பட்டது"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"வண்ணத்திருத்தம்"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"இது சோதனை முறையிலான அம்சம், இது செயல்திறனைப் பாதிக்கலாம்."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"தோராயமாக <xliff:g id="TIME">%1$s</xliff:g> உள்ளது"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"தோராயம்: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> உள்ளது"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"முழு சார்ஜிற்கு: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"சார்ஜ் செய்யப்படவில்லை"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"சார்ஜ் ஏறவில்லை"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"முழுமை"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"நிர்வாகி முடக்கியுள்ளார்"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
+ <string name="home" msgid="8263346537524314127">"முகப்பு"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> முன்"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> உள்ளது"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index e7de5b5f7e6a..4b4aabfad808 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"వచనం నుండి ప్రసంగం అవుట్‌పుట్"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"ప్రసంగం రేట్"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"వచనాన్ని చదివి వినిపించాల్సిన వేగం"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"పిచ్"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"సమన్వయం చేసిన ప్రసంగం యొక్క టోన్‌ను ప్రభావితం చేస్తుంది"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"భాష"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"సిస్టమ్ భాషను ఉపయోగించు"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"భాష ఎంచుకోబడలేదు"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi సంచార స్కాన్‌లను ఎల్లప్పుడూ అనుమతించు"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"లెగసీ DHCP క్లయింట్‌ను ఉపయోగించు"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"ఎల్లప్పుడూ సెల్యులార్ డేటాను సక్రియంగా ఉంచు"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ఈ సెట్టింగ్‌లు అభివృద్ధి వినియోగం కోసం మాత్రమే ఉద్దేశించబడినవి. వీటి వలన మీ పరికరం మరియు దీనిలోని అనువర్తనాలు విచ్ఛిన్నం కావచ్చు లేదా తప్పుగా ప్రవర్తించవచ్చు."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ద్వారా అనువర్తనాలను ధృవీకరించు"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"హానికరమైన ప్రవర్తన కోసం ADB/ADT ద్వారా ఇన్‌స్టాల్ చేయబడిన అనువర్తనాలను తనిఖీ చేయి."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"రిమోట్ పరికరాల్లో ఆమోదించలేని స్థాయిలో అధిక వాల్యూమ్ ఉండటం లేదా వాల్యూమ్ నియంత్రణ లేకపోవడం వంటి సమస్యలు ఉంటే బ్లూటూత్ సంపూర్ణ వాల్యూమ్ లక్షణాన్ని నిలిపివేస్తుంది."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"స్థానిక టెర్మినల్"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"స్థానిక షెల్ ప్రాప్యతను అందించే టెర్మినల్ అనువర్తనాన్ని ప్రారంభించు"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP తనిఖీ"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"అనువర్తనాలను బాహ్య నిల్వలో నిర్బంధంగా అనుమతించు"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయగలిగేలా అనుమతిస్తుంది"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"కార్యాచరణలను పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను బహుళ విండోల్లో సరిపోయేటట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను పలు రకాల విండోల్లో సరిపోయేట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ప్రయోగాత్మక స్వతంత్ర రూప విండోలకు మద్దతును ప్రారంభిస్తుంది."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ప్రయోగాత్మక స్వతంత్ర రూప విండోల కోసం మద్దతును ప్రారంభిస్తుంది."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"డెస్క్‌టాప్ బ్యాకప్ పాస్‌వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"సక్రియంగా ఉంది. టోగుల్ చేయడానికి నొక్కండి."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"అమలులో ఉన్న సేవలు"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ప్రస్తుతం అమలులో ఉన్న సేవలను వీక్షించండి మరియు నియంత్రించండి"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"రాత్రి మోడ్"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"నిలిపివేయబడింది"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ఎల్లప్పుడూ ఆన్‌లో ఉంచు"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"స్వయంచాలకం"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"మల్టీప్రాసెస్ వెబ్ వీక్షణ ఆరం."</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ప్రత్యేకప్రాసెస్‌లో వెబ్ వీక్షణ రెండెరెర్‌లను అమలుచేస్తుంది."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"వెబ్ వీక్షణ అమలు"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ఎంచుకున్న వెబ్ వీక్షణ అమలు నిలిపివేయబడింది, కానీ ఉపయోగించడానికి తప్పనిసరిగా ప్రారంభించాల్సి ఉంటుంది, మీరు దీన్ని ప్రారంభించాలనుకుంటున్నారా?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"అమలు ఎంపికల జాబితా కాలం చెల్లినది అయినందున ఎంచుకున్న వెబ్ వీక్షణ అమలు చెల్లదు. జాబితా ఇప్పుడు నవీకరించబడుతుంది."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ఫైల్ గుప్తీకరణకు మార్చు"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"మార్చండి…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ఫైల్ ఇప్పటికే గుప్తీకరించబడింది"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"రంగు సవరణ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ఈ లక్షణం ప్రయోగాత్మకమైనది మరియు పనితీరుపై ప్రభావం చూపవచ్చు."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"సుమారు <xliff:g id="TIME">%1$s</xliff:g> మిగిలి ఉంది"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - సుమారు <xliff:g id="TIME">%2$s</xliff:g> మిగిలి ఉంది"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - పూర్తిగా నిండటానికి <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"నిండింది"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"నిర్వాహకుడు నిలిపివేసారు"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"నిర్వాహకుని ద్వారా నియంత్రించబడింది"</string>
+ <string name="home" msgid="8263346537524314127">"హోమ్"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> క్రితం"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> మిగిలి ఉంది"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 0e7ab5eaf86e..69066717c915 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"เอาต์พุตการอ่านออกเสียง"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"ความเร็วของคำพูด"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"ความเร็วในการพูดข้อความ"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"ความสูง-ต่ำของเสียง"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"มีผลต่อโทนเสียงของข้อความสังเคราะห์"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"ภาษา"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"ใช้ภาษาของระบบ"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"ไม่ได้เลือกภาษา"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ใช้การสแกน Wi-Fi ข้ามเครือข่ายเสมอ"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"ใช้ไคลเอ็นต์ DHCP เดิม"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"เปิดใช้ข้อมูลมือถือเสมอ"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"การตั้งค่านี้มีไว้เพื่อการพัฒนาเท่านั้น จึงอาจทำให้อุปกรณ์และแอปพลิเคชันที่มีอยู่เสียหายหรือทำงานผิดพลาดได้"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ยืนยันแอปพลิเคชันผ่าน USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ตรวจสอบแอปพลิเคชันที่ติดตั้งผ่าน ADB/ADT เพื่อตรวจดูพฤติกรรมที่เป็นอันตราย"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ปิดใช้คุณลักษณะการควบคุมระดับเสียงของอุปกรณ์อื่นผ่านบลูทูธในกรณีที่มีปัญหาเกี่ยวกับระดับเสียงของอุปกรณ์ระยะไกล เช่น ระดับเสียงที่ดังเกินไปหรือระดับเสียงที่ไม่มีการควบคุม"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"เทอร์มินัลในตัวเครื่อง"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"เปิดใช้งานแอปเทอร์มินัลที่ให้การเข้าถึงเชลล์ในตัวเครื่อง"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"การตรวจสอบ HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"บังคับให้แอปสามารถใช้ที่เก็บภายนอก"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"แตะเพื่อเปลี่ยนแปลงหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"ใช้งานอยู่ แตะเพื่อสลับ"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"บริการที่ทำงานอยู่"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"โหมดกลางคืน"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"ปิดใช้แล้ว"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"เปิดใช้เสมอ"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"อัตโนมัติ"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"เปิดใช้ WebView แบบหลายขั้นตอน"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"เรียกใช้โหมดแสดงภาพ WebView ในการดำเนินการที่แยกออกมา"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"การใช้งาน WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ตั้งค่าการใช้งาน WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"การใช้งาน WebView ที่เลือกไว้ถูกปิดใช้อยู่ คุณต้องการเปิดใช้เพื่อที่จะใช้งานไหม"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"การใช้งาน WebView ที่เลือกไม่สามารถใช้ได้เนื่องจากรายการตัวเลือกการนำไปใช้ล้าสมัยแล้ว ควรอัปเดตรายการนี้ได้แล้ว"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"แปลงเป็นการเข้ารหัสไฟล์"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"แปลง…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"เข้ารหัสไฟล์แล้ว"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"การแก้สี"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"คุณลักษณะนี้เป็นแบบทดลองและอาจส่งผลต่อประสิทธิภาพการทำงาน"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"เหลืออีกประมาณ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลือประมาณ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็ม"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ปิดใช้โดยผู้ดูแลระบบ"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ผู้ดูแลระบบเป็นผู้ควบคุม"</string>
+ <string name="home" msgid="8263346537524314127">"หน้าแรก"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>ที่ผ่านมา"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"เหลือ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 77da07bc1a77..a472075d1ddf 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Output ng text-to-speech"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Rate ng pagsasalita"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Bilis ng pagsambit sa teksto"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Pitch"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Nakakaapekto sa tono ng naka-synthesize na pananalita"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Wika"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Gamitin ang wika ng system"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Walang napiling wika"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Palaging payagan ang Mga Pag-scan sa Roaming ng Wi‑Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Gumamit ng legacy na DHCP client"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Nilalayon ang mga setting na ito para sa paggamit sa pag-develop lamang. Maaaring magsanhi ang mga ito ng pagkasira o hindi paggana nang maayos ng iyong device at mga application na nandito."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"I-verify ang mga app sa USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tingnan kung may nakakahamak na pagkilos sa apps na na-install sa pamamagitan ng ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dini-disable ang absolute volume feature ng Bluetooth kung may mga isyu sa volume ang mga malayong device gaya ng hindi katanggap-tanggap na malakas na volume o kawalan ng kontrol."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal na terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Paganahin ang terminal app na nag-aalok ng lokal na shell access"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Pagsusuring HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Pwersahang payagan ang mga app sa external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mara-write na sa external storage ang anumang app, anuman ang manifest value"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gawing resizable para sa multi-window ang lahat ng aktibidad, anuman ang mga manifest value."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gawing nare-resize ang lahat ng aktibidad para sa multi-window, anuman ang mga value ng manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"I-enable ang mga freeform window"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ine-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"I-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Password ng pag-backup ng desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"I-tap upang baguhin o alisin ang password para sa mga kumpletong pag-back up sa desktop"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktibo. I-tap upang i-toggle."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Mga tumatakbong serbisyo"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Night mode"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Naka-disable"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Palaging naka-on"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Awtomatiko"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"I-enable, multiprocess WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Tagapag-render ng WebView, patakbuhin sa hiwalay na proseso."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Pagpapatupad sa WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Itakda ang pagpapatupad sa WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Naka-disable ang napiling pagpapatupad sa WebView, at dapat itong i-enable upang magamit, gusto mo ba itong i-enable?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Di-wasto ang piniling pag-implement ng WebView dahil luma na ang mga pagpipian ng pag-implement. Dapat na na-update na ngayon ang listahan."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"I-convert at gawing pag-encrypt ng file"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"I-convert..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Na-encrypt na ang file"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Pagtatama ng kulay"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ang feature na ito ay pinag-eeksperimentuhan at maaaring makaapekto sa pagganap."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> na lang ang natitira"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - humigit kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> bago mapuno"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Hindi nagcha-charge"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hindi nagkakarga"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Na-disable ng administrator"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pinapamahalaan ng admin"</string>
+ <string name="home" msgid="8263346537524314127">"Home"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> na ang nakalipas"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> na lang"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 9780953a7c37..85b6080b222f 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Metin-konuşma çıktısı"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Konuşma hızı"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Metnin konuşulduğu hız"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Perde"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Sentezlenmiş konuşma sesini etkiler"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Dil"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Sistemin dilini kullan"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Dil seçilmedi"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Kablosuz Dolaşım Taramalarına daima izin ver"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Eski DHCP istemcisini kullan"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu ayarlar yalnızca geliştirme amaçlıdır. Cihazınızın veya cihazdaki uygulamaların bozulmasına veya hatalı çalışmasına neden olabilir."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB\'den yüklenen uygulamaları doğrula"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT üzerinden yüklenen uygulamaları zararlı davranışlara karşı denetle."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Uzak cihazda sesin aşırı yüksek olması veya kontrol edilememesi gibi ses sorunları olması ihtimaline karşı Bluetooh mutlak ses özelliğini iptal eder."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Yerel terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Yerel kabuk erişimi sunan terminal uygulamasını etkinleştir"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP denetimi"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Uyg. ana işlem parçasında uzun işlem yap. ekr. yakıp söndür"</string>
<string name="pointer_location" msgid="6084434787496938001">"İşaretçi konumu"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Mevcut dokunmatik verilerini gösteren yer paylaşımı"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Hafifçe dokunmayı göster"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Hafifçe dokunmalarda görsel geri bildirim göster"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Yüzey güncellemelerini göster"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Güncelleme sırasında tüm pencere yüzeylerini çiz"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"GPU görünüm güncellemelerini göster"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Harici birimdeki uygulamalara izin vermeye zorla"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bildirilen değerlerden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir hale getirir."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir yap."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Serbest biçimli pencereleri etkinleştir"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Deneysel serbest biçimli pencereleri etkinleştirir."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Deneysel serbest biçimli pencere desteğini etkinleştir."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için hafifçe dokunun"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni yedekleme şifresi ayarlandı"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni şifre ve onayı eşleşmiyor."</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedekleme şifresi ayarlanamadı"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Dijital içerik için optimize edilmiş renkler"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Devre dışı uygulamalar"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Etkin değil. Geçiş yapmak için hafifçe dokunun."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Etkin. Geçiş yapmak için hafifçe dokunun."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Çalışan hizmetler"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Gece modu"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Devre dışı"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Her zaman açık"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Otomatik"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Çoklu işlem WebView\'ı etkinleştir"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView oluşturucuları yalıtılmış bir işlemde çalıştırın."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView kullanımı"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView kullanımını ayarla"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Seçilen WebView uygulama şekli devre dışı. Bu uygulama şeklinin kullanılabilmesi için etkinleştirilmesi gerekir. Etkinleştirmek istiyor musunuz?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Seçilen WebView uygulaması, uygulama seçenekleri listesi eskidiği için geçersiz. Listenin şimdi güncellenmesi gerekiyor."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Dosya şifrelemeye dönüştür"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Dönüştür…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dosya şifreleme zaten uygulandı"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Renk düzeltme"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu özellik deneyseldir ve performansı etkileyebilir."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Yaklaşık <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - yaklaşık <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Şarj olmuyor"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Şarj etmiyor"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Dolu"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Yönetici tarafından devre dışı bırakıldı"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Yönetici tarafından denetleniyor"</string>
+ <string name="home" msgid="8263346537524314127">"Ana Ekran"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> önce"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kaldı"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 15419bd42fce..32cd58603732 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Вивід синтезу мовлення з тексту"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Темп мовлення"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Швидкість відтворення тексту"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Вис. зв."</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Впливає на тон синтезованого мовлення"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Мова"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Використовувати мову системи"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Мову не вибрано"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Завжди шукати мережі Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Використовувати старий клієнт DHCP"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"Не вимикати передавання даних"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Вимкнути абсолютну гучність"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ці налаштування застосовуються лише з метою розробки. Вони можуть спричиняти вихід з ладу або неправильне функціонування вашого пристрою чи програм у ньому."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Встановлення через USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Перевіряти безпеку додатків, установлених через ADB/ADT."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Функція абсолютної гучності Bluetooth вимикається, якщо на віддалених пристроях виникають проблеми, як-от надто висока гучність або втрата контролю."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локальний термінал"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Увімк. програму-термінал, що надає локальний доступ до оболонки"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Перевірка HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Примусово записувати додатки в зовнішню пам’ять"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Додатки можна записувати на зовнішню пам’ять незалежно від значень маніфесту"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Примусово масштабувати активність"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Активність масштабуватиметься на кілька вікон, незалежно від значень у файлі маніфесту."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Масштабувати активність на кілька вікон, незалежно від значень у файлі маніфесту."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Увімкнуться експериментальні вікна довільного формату."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Увімкнути експериментальні вікна довільного формату."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль резерв.копії на ПК"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Повні резервні копії на комп’ютері наразі не захищені"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Торкніться, щоб змінити або видалити пароль для повного резервного копіювання на комп’ютер"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Активний додаток. Торкніться, щоб дезактивувати."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Запущені служби"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Перегляд і керування запущеними службами"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Нічний режим"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Вимкнено"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Завжди ввімкнено"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Увімк. багатопроцесний WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запустити засоби обробки відео WebView окремим процесом."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Застосування WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Налаштувати застосування WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Вибране застосування WebView вимкнено. Увімкнути його?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Недійсне застосування WebView, оскільки список вибору застосувань застарів. Тепер список оновлено."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертувати в зашифрований файл"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертація…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Уже конвертовано в зашифрований файл"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекція кольору"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Це експериментальна функція. Вона може вплинути на продуктивність."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Залишилося приблизно <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – залишилось близько <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного зарядження"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Не заряджається"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Не заряджається"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Акумулятор заряджено"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Вимкнено адміністратором"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Керується адміністратором"</string>
+ <string name="home" msgid="8263346537524314127">"Головний екран"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> тому"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Залишилося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index e2eac3f8d4cc..0eaead8a9858 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"ٹیکسٹ ٹو اسپیچ آؤٹ پٹ"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"اسپیچ کی شرح"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"متن بولے جانے کی رفتار"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"پچ"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"تصنعی اسپیچ کی ٹون کو متاثر کرتا ہے"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"زبان"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"سسٹم کی زبان استعمال کریں"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"زبان منتخب نہیں کی گئی"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏ہمیشہ Wi‑Fi روم اسکینز کی اجازت دیں"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"‏پرانا DHCP کلائنٹ استعمال کریں"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"سیلولر ڈیٹا کو ہمیشہ فعال رکھیں"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"یہ ترتیبات صرف ڈویلپمنٹ استعمال کے ارادے سے ہیں۔ ان سے آپ کا آلہ اور اس پر موجود ایپلیکیشنز بریک ہو سکتی یا غلط برتاؤ کر سکتی ہیں۔"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏USB پر ایپس کی توثیق کریں"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏نقصان دہ رویے کے مدنظر ADB/ADT کی معرفت انسٹال شدہ ایپس کی جانچ کریں۔"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ریموٹ آلات کے ساتھ والیوم کے مسائل مثلاً نا قابل قبول حد تک بلند والیوم یا کنٹرول نہ ہونے کی صورت میں بلو ٹوتھ مطلق والیوم والی خصوصیت کو غیر فعال کریں۔"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"مقامی ٹرمینل"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"مقامی شیل رسائی پیش کرنے والی ٹرمینل ایپ فعال کریں"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"‏HDCP چیکنگ"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"ایپس کے اصل تھریڈ پر طویل اعمال انجام دیتے وقت اسکرین کو فلیش کریں"</string>
<string name="pointer_location" msgid="6084434787496938001">"پوائنٹر مقام"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"موجودہ ٹچ ڈیٹا دکھانے والا اسکرین اوور لے"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"تھپتھپاہٹیں دکھائیں"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"تھپتھپاہٹوں کیلئے بصری تاثرات دکھائیں"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"سطح کے اپ ڈیٹس دکھائیں"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"اپ ڈیٹ ہونے پر ونڈو کی پوری سطحیں جھلملائیں"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"‏GPU منظر اپ ڈیٹس دکھائیں"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"بیرونی پر ایپس کو زبردستی اجازت دیں"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"‏manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"‏manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بناتا ہے۔"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"‏manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بنائیں۔"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"‏freeform ونڈوز فعال کریں"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"‏تجرباتی freeform ونڈوز کے لئے سپورٹ فعال کرتا ہے۔"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"‏تجرباتی freeform ونڈوز کیلئے سپورٹ فعال کریں۔"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے تھپتھپائیں"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"بیک اپ کا نیا پاس ورڈ سیٹ کر دیا گیا"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"نیا پاس ورڈ اور تصدیق مماثل نہیں ہے"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"بیک اپ پاس ورڈ ترتیب دینے میں ناکامی"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"ڈیجیٹیل مواد کیلئے بہترین کردہ رنگ"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"غیر فعال ایپس"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"غیر فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"چل رہی سروسز"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"رات موڈ"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"‎%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"غیر فعال"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"ہمیشہ آن"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"‏ملٹی پراسیس WebView بحال کریں"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"‏WebView رینڈررز کو ایک علیحدہ پراسیس میں چلائیں۔"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"‏WebView کا نفاذ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏WebView کا نفاذ سیٹ کریں"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"‏منتخب کردہ WebView کا نفاذ غیر فعال ہے اور استعمال کرنے کیلئے اسے فعال ہونا چاہئیے، کیا آپ اسے فعال کرنا چاہتے ہیں؟"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"‏WebView کا منتخب کردہ نفاذ غلط ہے کیونکہ نفاذ کے انتخابات کی فہرست باسی ہو گئی ہے۔ اب فہرست کو اپ ڈیٹ ہونا چاہئیے۔"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"فائل مرموز کاری میں بدلیں"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"بدلیں…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"فائل پہلے ہی مرموز شدہ ہے"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"رنگ کی اصلاح"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"یہ خصوصیت تجرباتی ہے اور اس کی وجہ سے کاکردگی متاثر ہو سکتی ہے۔"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"تقریبا <xliff:g id="TIME">%1$s</xliff:g> باقی ہیں"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎ - تقریبا <xliff:g id="TIME">%2$s</xliff:g> باقی"</string>
<string name="power_charging" msgid="1779532561355864267">"‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>‎"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>‎ پورا ہونے تک"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"چارج نہیں ہو رہا ہے"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"چارج نہیں ہو رہا ہے"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"مکمل"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"منتظم نے غیر فعال کر دیا"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"کنٹرول کردہ بذریعہ منتظم"</string>
+ <string name="home" msgid="8263346537524314127">"ہوم"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی ہیں"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 12d0e8c659bc..30a85765d58e 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -78,7 +78,7 @@
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Quyidagi qurilma javob bermayapti: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> biriktirish so‘rovini rad qildi."</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi o‘chiq."</string>
- <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi o‘chirilgan."</string>
+ <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi o‘chiq."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: bitta ustun"</string>
<string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: ikkita ustun"</string>
<string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: uchta ustun"</string>
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Nutq sintezi"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Nutq tezligi"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Matnni o‘qish tezligi"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Chimdish"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Sintezlangan nutq balandligiga ta’sir qiladi"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Til"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Tizim tili"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Til tanlanmagan"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi tarmoqlarini qidirishga doim ruxsat"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Eski DHCP mijoz-dasturidan foydalanish"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu sozlamalar faqat dasturlash maqsadlariga mo‘ljallangan. Shuning uchun, ular qurilmangizga va undagi ilovalariga shikast yetkazib, noto‘g‘ri ishlashiga sabab bo‘lishi mumkin."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB orqali o‘rnatish"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT orqali o‘rnatilgan ilovalar xavfsizligini tekshiring"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Masofadan ulanadigan qurilmalar bilan muammolar yuz berganda, jumladan, juda baland ovoz yoki sozlamalarni boshqarib bo‘lmaydigan holatlarda Bluetooth ovozi balandligining mutlaq darajasini o‘chirib qo‘yadi."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Mahalliy terminal"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Mahalliy terminalga kirishga ruxsat beruvchi terminal ilovani faollashtirish"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP tekshiruvi"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Uzun amallar vaqtida ekranni miltillatish"</string>
<string name="pointer_location" msgid="6084434787496938001">"Kursor joylashuvi"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Ekranda bosilgan va tegilgan joylarni vizuallashtirish"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Bosishlarni ko‘rsatish"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Ekranda bosilgan joylardagi nuqtalarni ko‘rsatish"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Yuza yangilanishlarini ko‘rsatish"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Yangilangandan so‘ng to‘liq oyna sirtlarini miltillatish"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Ekran yangilanishlarini ko‘rsatish"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tashqi xotira qurilmasidagi ilova dasturlariga majburiy ruxsat berish"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtiradi."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtirish."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Erkin shakldagi oynalarni yoqish"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqadi"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Erkin shakldagi oynalar yaratish uchun mo‘ljallangan tajribaviy funksiyani yoqish."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Yangi zaxira paroli o‘rnatildi"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parollar bir-biriga mos kelmadi"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Zaxira parolini o‘rnatib bo‘lmadi"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Raqamli kontentga moslashtirilgan ranglar"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Nofaol ilovalar"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Nofaol. O‘zgartirish uchun bu yerga bosing."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Faol. O‘zgartirish uchun bu yerga bosing."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Ishlab turgan ilovalar"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Tungi rejim"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"O‘chiq"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Har doim yoniq tursin"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"WebView multiprocess’ni yoqish"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView renderlovchilarini alohida jarayonda ishga tushirish."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ta’minotchisini sozlash"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Tanlangan WebView ta’minotchisi o‘chirilgan va foydalanish uchun yoqilishi zarur. Yoqilsinmi?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Tanlangan WebView xizmati qo‘llab-quvvatlanmaydi. Xizmatlar ro‘yxati eskirgan va hozir ular yangilanadi."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Faylli shifrga o‘girish"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"O‘girish…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl allaqachon shifrlangan"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rangni tuzatish"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya tajribaviy bo‘lib, u qurilma unumdorligiga ta’sir qilishi mumkin."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, to‘lguncha"</string>
@@ -310,10 +307,11 @@
<string name="battery_info_status_charging_ac" msgid="2909861890674399949">"Quvvat olmoqda (AC)"</string>
<string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Quvvat olmoqda (USB)"</string>
<string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Simsiz quvvat olmoqda"</string>
- <string name="battery_info_status_discharging" msgid="310932812698268588">"Quvvatlantirilmayapti"</string>
+ <string name="battery_info_status_discharging" msgid="310932812698268588">"Quvvat olmayapti"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Quvvatlanmayapti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administrator tomonidan o‘chirib qo‘yilgan"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administrator tomonidan boshqariladi"</string>
+ <string name="home" msgid="8263346537524314127">"Bosh ekran"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> oldin"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qoldi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index a1499691c7c5..38ddcc0ccf0e 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Đầu ra v.bản thành giọng nói"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Tốc độ nói"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Tốc độ đọc văn bản"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Độ cao"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ảnh hưởng đến âm điệu giọng nói được tổng hợp"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Ngôn ngữ"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Sử dụng ngôn ngữ hệ thống"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Không thể chọn ngôn ngữ"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luôn cho phép quét chuyển vùng Wi‑Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Sử dụng ứng dụng DHCP cũ"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Những cài đặt này chỉ dành cho mục đích phát triển. Chúng có thể làm cho thiết bị và ứng dụng trên thiết bị của bạn bị lỗi và hoạt động sai."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Xác minh ứng dụng qua USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kiểm tra các ứng dụng được cài đặt qua ADB/ADT để xem có hoạt động gây hại hay không."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Vô hiệu hóa tính năng âm lượng tuyệt đối qua Bluetooth trong trường hợp xảy ra sự cố về âm lượng với các thiết bị từ xa, chẳng hạn như âm lượng lớn không thể chấp nhận được hoặc thiếu kiểm soát."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Dòng lệnh cục bộ"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Bật ứng dụng dòng lệnh cung cấp quyền truy cập vỏ cục bộ"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Kiểm tra HDCP"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Buộc cho phép các ứng dụng trên bộ nhớ ngoài"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Giúp ứng dụng bất kỳ đủ điều kiện được ghi vào bộ nhớ ngoài bất kể giá trị tệp kê khai là gì"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Buộc các hoạt động có thể thay đổi kích thước"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Bật cửa sổ dạng tự do"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mật khẩu sao lưu của máy tính"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sao lưu toàn bộ máy tính hiện không được bảo vệ"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Nhấn để thay đổi hoặc xóa mật khẩu dành cho sao lưu toàn bộ tới máy tính"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Hiện hoạt. Nhấn để chuyển đổi."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Các dịch vụ đang hoạt động"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Xem và kiểm soát các dịch vụ hiện đang hoạt động"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Chế độ ban đêm"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Đã tắt"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Luôn bật"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Tự động"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Bật WebView đa quy trình"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Chạy kết xuất đồ họa WebView trong quy trình tách biệt."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Triển khai WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Đặt triển khai WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Triển khai WebView đã chọn bị vô hiệu hóa và bạn phải bật để sử dụng tính năng này. Bạn có muốn bật tính năng này không?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Triển khai WebView đã chọn không hợp lệ vì danh sách lựa chọn triển khai đã cũ. Phải cập nhật danh sách ngay bây giờ."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Chuyển đổi sang mã hóa tệp"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Chuyển đổi..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Đã mã hóa tệp"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Sửa màu"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tính năng này là tính năng thử nghiệm và có thể ảnh hưởng đến hoạt động."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Còn khoảng <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - còn khoảng <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho đến khi đầy"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Hiện không sạc"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Hiện không sạc"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Bị tắt bởi quản trị viên"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Do quản trị viên kiểm soát"</string>
+ <string name="home" msgid="8263346537524314127">"Màn hình chính"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> trước"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Còn <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 27e89720806a..53bd985436ee 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"文字转语音 (TTS) 输出"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"语速"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"文字转换成语音后的播放速度"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"音高"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"会影响合成语音的音调"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"语言"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"使用系统语言"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"未选择语言"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允许WLAN漫游扫描"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"使用旧版 DHCP 客户端"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"始终开启移动数据网络"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用绝对音量功能"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"这些设置仅适用于开发工作。一旦启用,会导致您的设备以及设备上的应用崩溃或出现异常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"通过USB验证应用"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"通过 ADB/ADT 检查安装的应用是否存在有害行为。"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"停用蓝牙绝对音量功能,即可避免在连接到远程设备时出现音量问题(例如音量高得让人无法接受或无法控制音量等)。"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"本地终端"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"启用终端应用,以便在本地访问 Shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 检查"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"强制允许将应用写入外部存储设备"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"将所有活动设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"将所有 Activity 设为可配合多窗口环境调整大小(忽略清单值)。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"启用可自由调整的窗口"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"启用可自由调整的窗口这一实验性功能。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"启用可自由调整的窗口这一实验性功能。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面备份密码"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"点按即可更改或移除用于保护桌面完整备份的密码"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"已启用。点按即可切换。"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"正在运行的服务"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"查看和控制当前正在运行的服务"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"夜间模式"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"始终开启"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"自动"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"启用多进程 WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在独立进程中运行 WebView 渲染程序。"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 实现"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"设置 WebView 实现"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"所选的 WebView 实现已停用,您必须先启用 WebView 实现才能加以使用。要启用该 WebView 实现吗?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"所选的 WebView 实现无效,因为相关的实现选项列表已过时。请立即更新这份列表。"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"转换为文件加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"转换…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"文件已加密"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色彩校正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"此功能为实验性功能,可能会影响性能。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"还剩大约 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还可用大约<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"未在充电"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"未在充电"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"电量充足"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已被管理员禁用"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"由管理员控制"</string>
+ <string name="home" msgid="8263346537524314127">"主屏幕"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"还剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index af1223c549f6..02be1605ecdd 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"文字轉語音輸出"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"語音速率"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"文字轉語音的播放速度"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"音調"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"影響合成語音的音調"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"語言"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"使用系統語言"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"未選取語言"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"永遠允許 Wi-Fi 漫遊掃瞄"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"使用舊的 DHCP 用戶端"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"經常啟用流動數據"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"這些設定僅供開發用途,可能會導致您的裝置及應用程式損毀或運作不正常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"透過 USB 驗證應用程式"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"透過 ADB/ADT 檢查安裝的應用程式有否有害的行為。"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"連線至遠端裝置時,如發生音量過大或無法控制音量等問題,請停用藍牙絕對音量功能。"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 檢查"</string>
@@ -206,8 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"當應用程式在主執行緒中進行長時間作業時,讓螢幕閃爍"</string>
<string name="pointer_location" msgid="6084434787496938001">"指標位置"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"在螢幕上重疊顯示目前的觸控資料"</string>
- <string name="show_touches" msgid="2642976305235070316">"顯示觸控回應"</string>
- <string name="show_touches_summary" msgid="6101183132903926324">"顯示觸控位置的視覺回應"</string>
+ <string name="show_touches" msgid="2642976305235070316">"顯示輕按回應"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"顯示輕按位置的視覺回應"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"顯示表層更新"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"更新表層時閃動整個視窗表層"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"顯示 GPU 畫面更新"</string>
@@ -246,12 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"強制允許應用程式寫入到外部儲存空間"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"在任何資訊清單值下,允許為多個視窗變更所有活動的尺寸。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"在任何資訊清單值下,允許系統配合多重視窗環境調整所有活動的尺寸。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形態視窗"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形態視窗的支援功能。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"啟用實驗版自由形態視窗的支援功能。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除電腦完整備份的密碼"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除桌上電腦完整備份的密碼"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"已設定新備份密碼"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密碼與確認密碼不符"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"無法設定備份密碼"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"已啟用。輕按即可切換。"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"執行中的服務"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"查看並控制目前正在執行中的服務"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"夜間模式"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"永遠開啟"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"啟用多重處理程序 WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在獨立的處理程序中執行 WebView 轉譯器。"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 設置"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 設置"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"您選擇的 WebView 設定已停用,您必須先啟用此設定才能加以使用。要啟用此設定嗎?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"WebView 的設定選項清單已過時,因此您所選的 WebView 設定無效。請立即更新這份清單。"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"轉換為檔案加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"轉換…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"已加密檔案"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色彩校正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會影響效能。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"尚餘大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 尚餘大約 <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 後完成充電"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"未開始充電"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理員已停用此設定"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
+ <string name="home" msgid="8263346537524314127">"主畫面"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"尚餘 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index f268ff94e365..7407e28cc0ef 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"文字轉語音輸出"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"語音速率"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"文字轉語音的播放速度"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"音調"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"會影響合成語音的音調"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"語言"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"使用系統設定"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"未選取語言"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允許 Wi-Fi 漫遊掃描"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"使用舊版 DHCP 用戶端"</string>
<string name="mobile_data_always_on" msgid="7745605759775320362">"行動數據連線一律保持啟用狀態"</string>
+ <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"這些設定僅供開發之用,可能導致您的裝置及裝置中的應用程式毀損或運作異常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"透過 USB 驗證應用程式"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"透過 ADB/ADT 檢查安裝的應用程式是否出現有害的行為。"</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"只要停用藍牙絕對音量功能,即可避免在連線到遠端裝置時,發生音量過大或無法控制音量等問題。"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"啟用可提供本機命令介面存取權的終端機應用程式"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP 檢查"</string>
@@ -246,9 +250,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"強制允許將應用程式寫入外部儲存空間"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形式視窗"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形式視窗的支援功能。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"啟用實驗版自由形式視窗的支援功能。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"電腦完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除電腦完整備份的密碼"</string>
@@ -270,14 +274,11 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"已啟用。輕按即可切換。"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"正在運作的服務"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"查看並管理目前正在執行的服務"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"夜間模式"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"一律開啟"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"啟用多重處理程序 WebView"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在獨立的處理程序中執行 WebView 轉譯器。"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 實作"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 實作"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"您所選的 WebView 實作已停用,您必須先啟用 WebView 實作才能加以使用。要啟用該 WebView 實作嗎?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"您所選的 WebView 實作無效,這是因為相關的實作選項清單已過時。請立即更新這份清單。"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"轉換成檔案加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"轉換..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"已將檔案加密"</string>
@@ -294,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色彩校正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會對效能造成影響。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"還剩大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 大約還剩 <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
@@ -308,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"非充電中"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已由管理員停用"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
+ <string name="home" msgid="8263346537524314127">"主畫面"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"還剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index f372057a3dda..e563bff1dd0e 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -101,6 +101,8 @@
<string name="tts_settings_title" msgid="1237820681016639683">"Umbhalo-uya-kokukhishwa ngokukhuluma"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Ukukala izwi"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Isivinini leso umbhalo okhulunywe ngaso"</string>
+ <string name="tts_default_pitch_title" msgid="6135942113172488671">"Ukuphakama"</string>
+ <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Ithinta amathoni enkulumo akhiqiziwe"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Ulimi"</string>
<string name="tts_lang_use_system" msgid="2679252467416513208">"Sebenzisa ulimi lwesistimu"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Ulimi alukhethwanga"</string>
@@ -165,6 +167,7 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vumela njalo ukuskena kokuzula kwe-Wi-Fi"</string>
<string name="legacy_dhcp_client" msgid="694426978909127287">"Sebenzisa iklayenti le-legacy le-DHCP"</string>
<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="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>
@@ -185,6 +188,7 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Lezi zilungiselelo zenzelwe ukusetshenziswa ukuthuthukisa kuphela. Zingadala ukuthi idivayisi yakho kanye nensiza ekuyona ukuthi iphuke noma iziphathe kabi."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Qiniseka izinhlelo zokusebenza nge-USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Hlola izinhlelo zokusebenza ezifakiwe nge-ADB/ADT ngokuziphatha okuyingozi."</string>
+ <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Ikhubaza isici esiphelele sevolumu ye-Bluetooth uma kuba nezinkinga zevolumu ngamadivayisi esilawuli kude ezifana nevolumu ephezulu noma eshoda ngokulawuleka."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Itheminali yasendaweni"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"Nika amandla uhlelo lokusebenza letheminali olunikeza ukufinyelela kwasendaweni kwe-shell"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"Ihlola i-HDCP"</string>
@@ -206,10 +210,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Ukuphazimisa isikrini uma izinhlelo zokusebenza ziyenza umsebenzi ngesikhathi eside kuchungechunge olukhulu"</string>
<string name="pointer_location" msgid="6084434787496938001">"Isikhombi sendawo"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Imbondela yesikrini ibonisa idatha yokuthinta yamanje"</string>
- <!-- no translation found for show_touches (2642976305235070316) -->
- <skip />
- <!-- no translation found for show_touches_summary (6101183132903926324) -->
- <skip />
+ <string name="show_touches" msgid="2642976305235070316">"Bonisa amathebhu"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Bonisa izmpendulo ebukekayo ngamathebhu"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Buka izibuyekezo ezibonakalayo"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Khanyisa ukubonakala kwalo lonke iwindi uma libuyekezwa"</string>
<string name="show_hw_screen_updates" msgid="5036904558145941590">"Buka izibuyekezo ze-GPU"</string>
@@ -248,13 +250,12 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Phoqelela ukuvumela izinhlelo zokusebenza ngaphandle"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Yenza yonke imisebenzi ibe nosayizi abasha kuwindi lokuningi, ngokunganaki amanani we-manifest."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Yenza yonke imisebenzi ibe nosayizi abasha kumawindi amaningi, ngokunganaki amavelu e-manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Nika amandla amawindi e-freeform"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Inika amandla usekelo lwamawindi okuhlola e-freeform."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Nika amandla usekelo lwe-windows yokuhlola kwe-freeform."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
- <!-- no translation found for local_backup_password_summary_change (5376206246809190364) -->
- <skip />
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Thepha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"Iphasiwedi entsha eyisipele isethiwe"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Iphasiwedi entsha nokuqinisekisa akufani"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ukungaphumeleli kokusetha iphasiwedi eyisipele"</string>
@@ -269,20 +270,15 @@
<item msgid="5363960654009010371">"Imibala elungiselelwe yokuqukethwe kwedijithali"</item>
</string-array>
<string name="inactive_apps_title" msgid="1317817863508274533">"Izinhlelo zokusebenza ezingasebenzi"</string>
- <!-- no translation found for inactive_app_inactive_summary (5091363706699855725) -->
- <skip />
- <!-- no translation found for inactive_app_active_summary (4174921824958516106) -->
- <skip />
+ <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Akusebenzi. Thepha ukuze ushintshe."</string>
+ <string name="inactive_app_active_summary" msgid="4174921824958516106">"Kuyasebenza. Thepha ukuze ushintshe."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Amasevisi asebenzayo"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Buka futhi ulawule amasevisi asebenzayo okwamanje"</string>
- <string name="night_mode_title" msgid="2594133148531256513">"Imodi yasebusuku"</string>
- <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <string name="night_mode_no" msgid="9171772244775838901">"Kukhutshaziwe"</string>
- <string name="night_mode_yes" msgid="2218157265997633432">"Njalo ivuliwe"</string>
- <string name="night_mode_auto" msgid="7508348175804304327">"Okuzenzakalelayo"</string>
+ <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Nika amandla i-WebView kokucubungula okuningi"</string>
+ <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Sebenzisa abasebenzeli be-WebView kwinqubo ekhethiwe."</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Ukufakwa ke-WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Sesba ukufakwa kwe-WebView"</string>
- <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Ukusetshenziswa kwe-WebView okukhethiwe kukhutshaziwe, futhi kuzomele kunikwe amandla ukuze kusetshenziswe, ingabe ufisa ukukunika amandla?"</string>
+ <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Ukusetshenziswa okukhethiwe kwe-WebView akuvumelekile ngoba uhlu lokukhetha ukusetshenziswa lukhule lwaba ludala. Uhlu kumele manje libuyekezwe."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Phendulisela ekubethelweni kwefayela"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Iyaphendulela..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sekuvele kubethelwe ngefayela"</string>
@@ -299,6 +295,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Ukulungiswa kombala"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Lesi sici esesilingo futhi singathinta ukusebenza."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Cishe ngu-<xliff:g id="TIME">%1$s</xliff:g> osele"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - isilinganiso esingu-<xliff:g id="TIME">%2$s</xliff:g> esisele"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze igcwale"</string>
@@ -313,7 +310,8 @@
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ayishaji"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ayishaji"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
- <string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Ikhutshazwe umlawuli"</string>
- <!-- no translation found for home (8263346537524314127) -->
- <skip />
+ <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kulawulwa umqondisi"</string>
+ <string name="home" msgid="8263346537524314127">"Ekhaya"</string>
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> edlule"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> osele"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 1bce7f9ac3ae..525d6f421d71 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -344,28 +344,6 @@
<item>midi</item>
</string-array>
- <!-- Possible values for user theme in Display Settings.
- Do not translate. -->
- <string-array name="night_mode_entries" translatable="false">
- <!-- Do not translate. -->
- <item>@string/night_mode_no</item>
- <!-- Do not translate. -->
- <item>@string/night_mode_yes</item>
- <!-- Do not translate. -->
- <item>@string/night_mode_auto</item>
- </string-array>
-
- <!-- These values should match up with the MODE_NIGHT constants in UiModeManager.
- Do not translate. -->
- <string-array name="night_mode_values" translatable="false">
- <!-- Do not translate. -->
- <item>1</item>
- <!-- Do not translate. -->
- <item>2</item>
- <!-- Do not translate. -->
- <item>0</item>
- </string-array>
-
<!-- Display color space adjustment modes for developers -->
<string-array name="simulate_color_space_entries" translatable="false">
<item>@string/daltonizer_mode_disabled</item>
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index 3e1fc4a4e343..4484613d0ee2 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -24,4 +24,12 @@
</declare-styleable>
<attr name="wifi_signal" format="reference" />
+ <declare-styleable name="UsageView">
+ <attr name="android:colorAccent" />
+ <attr name="sideLabels" format="reference" />
+ <attr name="bottomLabels" format="reference" />
+ <attr name="textColor" format="color" />
+ <attr name="android:gravity" />
+ </declare-styleable>
+
</resources>
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index c090468c3e8f..796273dc36a9 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -16,4 +16,6 @@
<resources>
<color name="disabled_text_color">#66000000</color> <!-- 38% black -->
+
+ <color name="usage_graph_dots">#455A64</color>
</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 811751cd00a5..9f78e87d1231 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -38,4 +38,18 @@
<dimen name="wifi_preference_badge_padding">8dip</dimen>
+ <!-- Usage graph dimens -->
+ <dimen name="usage_graph_area_height">122dp</dimen>
+ <dimen name="usage_graph_margin_top_bottom">9dp</dimen>
+ <dimen name="usage_graph_labels_width">56dp</dimen>
+ <dimen name="usage_graph_labels_padding">16dp</dimen>
+
+ <dimen name="usage_graph_divider_size">1dp</dimen>
+
+ <dimen name="usage_graph_line_width">3dp</dimen>
+ <dimen name="usage_graph_line_corner_radius">6dp</dimen>
+
+ <dimen name="usage_graph_dot_size">.75dp</dimen>
+ <dimen name="usage_graph_dot_interval">7dp</dimen>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 32699ebacdc7..72fa9397e898 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -236,10 +236,14 @@
<string name="tts_settings">Text-to-speech settings</string>
<!-- TTS option item name in the main settings screen -->
<string name="tts_settings_title">Text-to-speech output</string>
- <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
+ <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
<string name="tts_default_rate_title">Speech rate</string>
<!-- On main TTS Settings screen, summary for default speech rate for synthesized voice -->
<string name="tts_default_rate_summary">Speed at which the text is spoken</string>
+ <!-- On main TTS Settings screen, in default settings section, setting default pitch for synthesized voice -->
+ <string name="tts_default_pitch_title">Pitch</string>
+ <!-- On main TTS Settings screen, summary for default pitch for synthesized voice -->
+ <string name="tts_default_pitch_summary">Affects the tone of the synthesized speech</string>
<!-- On main TTS Settings screen, in default settings section, setting default language for synthesized voice -->
<string name="tts_default_lang_title">Language</string>
<!-- Entry in the TTS engine language/locale picker, when selected will try to default to the system language [CHAR LIMIT=50] -->
@@ -416,6 +420,8 @@
<string name="legacy_dhcp_client">Use legacy DHCP client</string>
<!-- Setting Checkbox title whether to always keep cellular data active. [CHAR LIMIT=80] -->
<string name="mobile_data_always_on">Cellular data always active</string>
+ <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
+ <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
<!-- setting Checkbox summary whether to show options for wireless display certification -->
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
@@ -456,6 +462,8 @@
<string name="verify_apps_over_usb_title">Verify apps over USB</string>
<!-- Summary of checkbox setting to perform package verification on apps installed over USB/ADT/ADB [CHAR LIMIT=NONE] -->
<string name="verify_apps_over_usb_summary">Check apps installed via ADB/ADT for harmful behavior.</string>
+ <!-- Summary of checkbox for disabling Bluetooth absolute volume -->
+ <string name="bluetooth_disable_absolute_volume_summary">Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control.</string>
<!-- Title of checkbox setting that enables the terminal app. [CHAR LIMIT=32] -->
<string name="enable_terminal_title">Local terminal</string>
@@ -622,12 +630,12 @@
<!-- UI debug setting: force all activites to be resizable for multiwindow [CHAR LIMIT=50] -->
<string name="force_resizable_activities">Force activities to be resizable</string>
<!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
- <string name="force_resizable_activities_summary">Makes all activities resizable for multi-window, regardless of manifest values.</string>
+ <string name="force_resizable_activities_summary">Make all activities resizable for multi-window, regardless of manifest values.</string>
<!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
<string name="enable_freeform_support">Enable freeform windows</string>
<!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
- <string name="enable_freeform_support_summary">Enables support for experimental freeform windows.</string>
+ <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
<!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
<string name="local_backup_password_title">Desktop backup password</string>
@@ -669,23 +677,17 @@
<!-- Services settings screen, setting option summary for the user to go to the screen to view running services -->
<string name="runningservices_settings_summary">View and control currently running services</string>
- <!-- Sound & display settings screen, setting option name to change the user interface theme [CHAR LIMIT=30] -->
- <string name="night_mode_title">Night mode</string>
- <!-- Sound & display settings screen, setting option summary to change the user interface theme [CHAR LIMIT=100] -->
- <string name="night_mode_summary">%s</string>
- <!-- Sound & display settings screen, theme setting value to prefer a light-colored user interface [CHAR LIMIT=30] -->
- <string name="night_mode_no">Disabled</string>
- <!-- Sound & display settings screen, theme setting value to prefer a dark-colored user interface [CHAR LIMIT=30] -->
- <string name="night_mode_yes">Always on</string>
- <!-- Sound & display settings screen, theme setting value to automatically switch between a light- or dark-colored user interface [CHAR LIMIT=30] -->
- <string name="night_mode_auto">Automatic</string>
-
- <!-- Developer settings: select WebView provider title -->
+ <!-- Developer settings: enable WebView multiprocess name [CHAR LIMIT=30] -->
+ <string name="enable_webview_multiprocess">Enable multiprocess WebView</string>
+ <!-- Developer settings: enable WebView multiprocess summary [CHAR LIMIT=60] -->
+ <string name="enable_webview_multiprocess_desc">Run WebView renderers in an isolated process.</string>
+
+ <!-- Developer settings: select WebView provider title [CHAR LIMIT=30] -->
<string name="select_webview_provider_title">WebView implementation</string>
- <!-- Developer settings: select WebView provider dialog title -->
+ <!-- Developer settings: select WebView provider dialog title [CHAR LIMIT=30] -->
<string name="select_webview_provider_dialog_title">Set WebView implementation</string>
- <!-- Developer settings: confirmation dialog text for the WebView provider selection dialog -->
- <string name="select_webview_provider_confirmation_text">The chosen WebView implementation is disabled, and must be enabled to be used, do you wish to enable it?</string>
+ <!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
+ <string name="select_webview_provider_toast_text">The chosen WebView implementation is invalid because the list of implementation choices grew stale. The list should now be updated.</string>
<!-- Developer settings screen, convert userdata to file encryption option name -->
<string name="convert_to_file_encryption">Convert to file encryption</string>
@@ -728,6 +730,9 @@
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
+ <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging/discharging -->
+ <string name="power_remaining_duration_only">Approx. <xliff:g id="time">%1$s</xliff:g> left</string>
+
<!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
<string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g>
- approx. <xliff:g id="time">%2$s</xliff:g> left</string>
@@ -766,9 +771,21 @@
<string name="battery_info_status_full">Full</string>
<!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
- <string name="disabled_by_admin_summary_text">Disabled by administrator</string>
+ <string name="disabled_by_admin_summary_text">Controlled by admin</string>
<!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
<string name="home">Home</string>
+ <string-array name="battery_labels" translatable="false">
+ <item>0%</item>
+ <item>50%</item>
+ <item>100%</item>
+ </string-array>
+
+ <!-- Label for length of time since the battery graph started [CHAR LIMIT=20] -->
+ <string name="charge_length_format"><xliff:g name="time" example="3 hours">%1$s</xliff:g> ago</string>
+
+ <!-- Label for length of time until battery is charged [CHAR LIMIT=20] -->
+ <string name="remaining_length_format"><xliff:g name="time" example="3 hours">%1$s</xliff:g> left</string>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
index d81bdebda33c..6b29e2165c54 100644
--- a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
@@ -17,13 +17,17 @@ package com.android.settingslib;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.BatteryStats;
+import android.os.BatteryStats.HistoryItem;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.format.Formatter;
+import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHelper;
+import com.android.settingslib.graph.UsageView;
public class BatteryInfo {
@@ -31,11 +35,65 @@ public class BatteryInfo {
public int mBatteryLevel;
public boolean mDischarging = true;
public long remainingTimeUs = 0;
+ public String batteryPercentString;
+ public String remainingLabel;
+ private BatteryStats mStats;
+ private boolean mCharging;
+ private long timePeriod;
public interface Callback {
void onBatteryInfoLoaded(BatteryInfo info);
}
+ public void bindHistory(final UsageView view, BatteryDataParser... parsers) {
+ BatteryDataParser parser = new BatteryDataParser() {
+ SparseIntArray points = new SparseIntArray();
+
+ @Override
+ public void onParsingStarted(long startTime, long endTime) {
+ timePeriod = endTime - startTime - remainingTimeUs / 1000;
+ view.clearPaths();
+ view.configureGraph((int) (endTime - startTime), 100, remainingTimeUs != 0,
+ mCharging);
+ }
+
+ @Override
+ public void onDataPoint(long time, HistoryItem record) {
+ points.put((int) time, record.batteryLevel);
+ }
+
+ @Override
+ public void onDataGap() {
+ if (points.size() > 1) {
+ view.addPath(points);
+ }
+ points.clear();
+ }
+
+ @Override
+ public void onParsingDone() {
+ if (points.size() > 1) {
+ view.addPath(points);
+ }
+ }
+ };
+ BatteryDataParser[] parserList = new BatteryDataParser[parsers.length + 1];
+ for (int i = 0; i < parsers.length; i++) {
+ parserList[i] = parsers[i];
+ }
+ parserList[parsers.length] = parser;
+ parse(mStats, remainingTimeUs, parserList);
+ final Context context = view.getContext();
+ String timeString = context.getString(R.string.charge_length_format,
+ Formatter.formatShortElapsedTime(context, timePeriod));
+ String remaining = "";
+ if (remainingTimeUs != 0) {
+ remaining = context.getString(R.string.remaining_length_format,
+ Formatter.formatShortElapsedTime(context, remainingTimeUs / 1000));
+ }
+ view.setBottomLabels(new CharSequence[]{timeString, remaining});
+ }
+
public static void getBatteryInfo(final Context context, final Callback callback) {
new AsyncTask<Void, Void, BatteryStats>() {
@Override
@@ -60,23 +118,29 @@ public class BatteryInfo {
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
BatteryStats stats, long elapsedRealtimeUs) {
BatteryInfo info = new BatteryInfo();
+ info.mStats = stats;
info.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast);
- String batteryPercentString = Utils.formatPercentage(info.mBatteryLevel);
- if (batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) == 0) {
+ info.batteryPercentString = Utils.formatPercentage(info.mBatteryLevel);
+ info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+ final Resources resources = context.getResources();
+ if (!info.mCharging) {
final long drainTime = stats.computeBatteryTimeRemaining(elapsedRealtimeUs);
if (drainTime > 0) {
info.remainingTimeUs = drainTime;
String timeString = Formatter.formatShortElapsedTime(context,
drainTime / 1000);
- info.mChargeLabelString = context.getResources().getString(
- R.string.power_discharging_duration, batteryPercentString, timeString);
+ info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
+ timeString);
+ info.mChargeLabelString = resources.getString(R.string.power_discharging_duration,
+ info.batteryPercentString, timeString);
} else {
- info.mChargeLabelString = batteryPercentString;
+ info.remainingLabel = null;
+ info.mChargeLabelString = info.batteryPercentString;
}
} else {
final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
final String statusLabel = Utils.getBatteryStatus(
- context.getResources(), batteryBroadcast);
+ resources, batteryBroadcast);
final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
@@ -95,13 +159,131 @@ public class BatteryInfo {
} else {
resId = R.string.power_charging_duration;
}
- info.mChargeLabelString = context.getResources().getString(
- resId, batteryPercentString, timeString);
+ info.remainingLabel = resources.getString(R.string.power_remaining_duration_only,
+ timeString);
+ info.mChargeLabelString = resources.getString(
+ resId, info.batteryPercentString, timeString);
} else {
- info.mChargeLabelString = context.getResources().getString(
- R.string.power_charging, batteryPercentString, statusLabel);
+ info.remainingLabel = statusLabel;
+ info.mChargeLabelString = resources.getString(
+ R.string.power_charging, info.batteryPercentString, statusLabel);
}
}
return info;
}
+
+ public interface BatteryDataParser {
+ void onParsingStarted(long startTime, long endTime);
+
+ void onDataPoint(long time, HistoryItem record);
+
+ void onDataGap();
+
+ void onParsingDone();
+ }
+
+ private static void parse(BatteryStats stats, long remainingTimeUs,
+ BatteryDataParser... parsers) {
+ long startWalltime = 0;
+ long endDateWalltime = 0;
+ long endWalltime = 0;
+ long historyStart = 0;
+ long historyEnd = 0;
+ byte lastLevel = -1;
+ long curWalltime = startWalltime;
+ long lastWallTime = 0;
+ long lastRealtime = 0;
+ int lastInteresting = 0;
+ int pos = 0;
+ boolean first = true;
+ if (stats.startIteratingHistoryLocked()) {
+ final HistoryItem rec = new HistoryItem();
+ while (stats.getNextHistoryLocked(rec)) {
+ pos++;
+ if (first) {
+ first = false;
+ historyStart = rec.time;
+ }
+ if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+ || rec.cmd == HistoryItem.CMD_RESET) {
+ // If there is a ridiculously large jump in time, then we won't be
+ // able to create a good chart with that data, so just ignore the
+ // times we got before and pretend like our data extends back from
+ // the time we have now.
+ // Also, if we are getting a time change and we are less than 5 minutes
+ // since the start of the history real time, then also use this new
+ // time to compute the base time, since whatever time we had before is
+ // pretty much just noise.
+ if (rec.currentTime > (lastWallTime + (180 * 24 * 60 * 60 * 1000L))
+ || rec.time < (historyStart + (5 * 60 * 1000L))) {
+ startWalltime = 0;
+ }
+ lastWallTime = rec.currentTime;
+ lastRealtime = rec.time;
+ if (startWalltime == 0) {
+ startWalltime = lastWallTime - (lastRealtime - historyStart);
+ }
+ }
+ if (rec.isDeltaData()) {
+ if (rec.batteryLevel != lastLevel || pos == 1) {
+ lastLevel = rec.batteryLevel;
+ }
+ lastInteresting = pos;
+ historyEnd = rec.time;
+ }
+ }
+ }
+ stats.finishIteratingHistoryLocked();
+ endDateWalltime = lastWallTime + historyEnd - lastRealtime;
+ endWalltime = endDateWalltime + (remainingTimeUs / 1000);
+
+ int i = 0;
+ final int N = lastInteresting;
+
+ for (int j = 0; j < parsers.length; j++) {
+ parsers[j].onParsingStarted(startWalltime, endWalltime);
+ }
+ if (endDateWalltime > startWalltime && stats.startIteratingHistoryLocked()) {
+ final HistoryItem rec = new HistoryItem();
+ while (stats.getNextHistoryLocked(rec) && i < N) {
+ if (rec.isDeltaData()) {
+ curWalltime += rec.time - lastRealtime;
+ lastRealtime = rec.time;
+ long x = (curWalltime - startWalltime);
+ if (x < 0) {
+ x = 0;
+ }
+ for (int j = 0; j < parsers.length; j++) {
+ parsers[j].onDataPoint(x, rec);
+ }
+ } else {
+ long lastWalltime = curWalltime;
+ if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+ || rec.cmd == HistoryItem.CMD_RESET) {
+ if (rec.currentTime >= startWalltime) {
+ curWalltime = rec.currentTime;
+ } else {
+ curWalltime = startWalltime + (rec.time - historyStart);
+ }
+ lastRealtime = rec.time;
+ }
+
+ if (rec.cmd != HistoryItem.CMD_OVERFLOW
+ && (rec.cmd != HistoryItem.CMD_CURRENT_TIME
+ || Math.abs(lastWalltime - curWalltime) > (60 * 60 * 1000))) {
+ for (int j = 0; j < parsers.length; j++) {
+ parsers[j].onDataGap();
+ }
+ }
+ }
+ i++;
+ }
+ }
+
+ stats.finishIteratingHistoryLocked();
+
+ for (int j = 0; j < parsers.length; j++) {
+ parsers[j].onParsingDone();
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index f8851101abc2..6d29c5f1a98e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -21,10 +21,8 @@ import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
@@ -115,6 +113,12 @@ public class RestrictedLockUtils {
return admin;
}
+ public static boolean hasBaseUserRestriction(Context context,
+ String userRestriction, int userId) {
+ UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId));
+ }
+
/**
* Checks if keyguard features are disabled by policy.
*
@@ -227,8 +231,7 @@ public class RestrictedLockUtils {
int userId) {
IPackageManager ipm = AppGlobals.getPackageManager();
try {
- ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
- if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
+ if (ipm.isPackageSuspendedForUser(packageName, userId)) {
return getProfileOrDeviceOwner(context, userId);
}
} catch (RemoteException e) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 9bd4eb185bee..227b1e8e1b4d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -70,6 +70,12 @@ public class RestrictedPreferenceHelper {
}
}
mAttrUserRestriction = data == null ? null : data.toString();
+ // If the system has set the user restriction, then we shouldn't add the padlock.
+ if (RestrictedLockUtils.hasBaseUserRestriction(mContext, mAttrUserRestriction,
+ UserHandle.myUserId())) {
+ mAttrUserRestriction = null;
+ return;
+ }
final TypedValue useAdminDisabledSummary =
attributes.peekValue(R.styleable.RestrictedPreference_useAdminDisabledSummary);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 1c032fac00de..a57805512a7e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -18,6 +18,7 @@ package com.android.settingslib.drawer;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -235,20 +236,24 @@ public class SettingsDrawerActivity extends Activity {
Intent.FLAG_ACTIVITY_CLEAR_TASK));
return true;
}
- int numUserHandles = tile.userHandle.size();
- if (numUserHandles > 1) {
- ProfileSelectDialog.show(getFragmentManager(), tile);
- return false;
- } else if (numUserHandles == 1) {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivityAsUser(tile.intent, tile.userHandle.get(0));
- } else {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(tile.intent);
+ try {
+ int numUserHandles = tile.userHandle.size();
+ if (numUserHandles > 1) {
+ ProfileSelectDialog.show(getFragmentManager(), tile);
+ return false;
+ } else if (numUserHandles == 1) {
+ // Show menu on top level items.
+ tile.intent.putExtra(EXTRA_SHOW_MENU, true);
+ tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivityAsUser(tile.intent, tile.userHandle.get(0));
+ } else {
+ // Show menu on top level items.
+ tile.intent.putExtra(EXTRA_SHOW_MENU, true);
+ tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(tile.intent);
+ }
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Couldn't find tile " + tile.intent, e);
}
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
index 73171c70d856..1d6197a9333f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
@@ -65,7 +65,7 @@ public class SettingsDrawerAdapter extends BaseAdapter {
}
public Tile getTile(int position) {
- return mItems.get(position).tile;
+ return mItems.get(position) != null ? mItems.get(position).tile : null;
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
new file mode 100644
index 000000000000..530ec16d5cca
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settingslib.graph;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.CornerPathEffect;
+import android.graphics.DashPathEffect;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Paint.Cap;
+import android.graphics.Paint.Join;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Shader.TileMode;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.SparseIntArray;
+import android.util.TypedValue;
+import android.view.View;
+import com.android.settingslib.R;
+
+public class UsageGraph extends View {
+
+ private static final int PATH_DELIM = -1;
+
+ private final Paint mLinePaint;
+ private final Paint mFillPaint;
+ private final Paint mDottedPaint;
+
+ private final Drawable mDivider;
+ private final int mDividerSize;
+
+ private final Path mPath = new Path();
+
+ // Paths in coordinates they are passed in.
+ private final SparseIntArray mPaths = new SparseIntArray();
+ // Paths in local coordinates for drawing.
+ private final SparseIntArray mLocalPaths = new SparseIntArray();
+
+ private int mAccentColor;
+ private boolean mShowProjection;
+ private boolean mProjectUp;
+
+ private float mMaxX = 100;
+ private float mMaxY = 100;
+
+ public UsageGraph(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ final Resources resources = context.getResources();
+
+ mLinePaint = new Paint();
+ mLinePaint.setStyle(Style.STROKE);
+ mLinePaint.setStrokeCap(Cap.ROUND);
+ mLinePaint.setStrokeJoin(Join.ROUND);
+ mLinePaint.setAntiAlias(true);
+ mLinePaint.setPathEffect(new CornerPathEffect(resources.getDimensionPixelSize(
+ R.dimen.usage_graph_line_corner_radius)));
+ mLinePaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.usage_graph_line_width));
+
+ mFillPaint = new Paint(mLinePaint);
+ mFillPaint.setStyle(Style.FILL);
+
+ mDottedPaint = new Paint(mLinePaint);
+ mDottedPaint.setStyle(Style.STROKE);
+ float dots = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_size);
+ float interval = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_interval);
+ mDottedPaint.setStrokeWidth(dots * 3);
+ mDottedPaint.setPathEffect(new DashPathEffect(new float[] {dots, interval}, 0));
+ mDottedPaint.setColor(context.getColor(R.color.usage_graph_dots));
+
+ TypedValue v = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.listDivider, v, true);
+ mDivider = context.getDrawable(v.resourceId);
+ mDividerSize = resources.getDimensionPixelSize(R.dimen.usage_graph_divider_size);
+ }
+
+ void clearPaths() {
+ mPaths.clear();
+ }
+
+ void setMax(int maxX, int maxY) {
+ mMaxX = maxX;
+ mMaxY = maxY;
+ }
+
+ public void addPath(SparseIntArray points) {
+ for (int i = 0; i < points.size(); i++) {
+ mPaths.put(points.keyAt(i), points.valueAt(i));
+ }
+ mPaths.put(points.keyAt(points.size() - 1) + 1, PATH_DELIM);
+ calculateLocalPaths();
+ postInvalidate();
+ }
+
+ void setAccentColor(int color) {
+ mAccentColor = color;
+ mLinePaint.setColor(mAccentColor);
+ updateGradient();
+ postInvalidate();
+ }
+
+ void setShowProjection(boolean showProjection, boolean projectUp) {
+ mShowProjection = showProjection;
+ mProjectUp = projectUp;
+ postInvalidate();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ updateGradient();
+ calculateLocalPaths();
+ }
+
+ private void calculateLocalPaths() {
+ if (getWidth() == 0) return;
+ mLocalPaths.clear();
+ int pendingXLoc = 0;
+ int pendingYLoc = PATH_DELIM;
+ for (int i = 0; i < mPaths.size(); i++) {
+ int x = mPaths.keyAt(i);
+ int y = mPaths.valueAt(i);
+ if (y == PATH_DELIM) {
+ if (i == mPaths.size() - 1 && pendingYLoc != PATH_DELIM) {
+ // Connect to the end of the graph.
+ mLocalPaths.put(pendingXLoc, pendingYLoc);
+ }
+ // Clear out any pending points.
+ pendingYLoc = PATH_DELIM;
+ mLocalPaths.put(pendingXLoc + 1, PATH_DELIM);
+ } else {
+ final int lx = getX(x);
+ final int ly = getY(y);
+ pendingXLoc = lx;
+ if (mLocalPaths.size() > 0) {
+ int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1);
+ int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1);
+ if (lastY != PATH_DELIM && (lastX == lx || lastY == ly)) {
+ pendingYLoc = ly;
+ continue;
+ }
+ }
+ mLocalPaths.put(lx, ly);
+ }
+ }
+ }
+
+ private int getX(float x) {
+ return (int) (x / mMaxX * getWidth());
+ }
+
+ private int getY(float y) {
+ return (int) (getHeight() * (1 - (y / mMaxY)));
+ }
+
+ private void updateGradient() {
+ mFillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(),
+ getColor(mAccentColor, .2f), 0, TileMode.CLAMP));
+ }
+
+ private int getColor(int color, float alphaScale) {
+ return (color & (((int) (0xff * alphaScale) << 24) | 0xffffff));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // Draw lines across the top, middle, and bottom.
+ drawDivider(0, canvas);
+ drawDivider((canvas.getHeight() - mDividerSize) / 2, canvas);
+ drawDivider(canvas.getHeight() - mDividerSize, canvas);
+
+ if (mLocalPaths.size() == 0) {
+ return;
+ }
+ if (mShowProjection) {
+ drawProjection(canvas);
+ }
+ drawFilledPath(canvas);
+ drawLinePath(canvas);
+ }
+
+ private void drawProjection(Canvas canvas) {
+ mPath.reset();
+ int x = mLocalPaths.keyAt(mLocalPaths.size() - 2);
+ int y = mLocalPaths.valueAt(mLocalPaths.size() - 2);
+ mPath.moveTo(x, y);
+ mPath.lineTo(canvas.getWidth(), mProjectUp ? 0 : canvas.getHeight());
+ canvas.drawPath(mPath, mDottedPaint);
+ }
+
+ private void drawLinePath(Canvas canvas) {
+ mPath.reset();
+ mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
+ for (int i = 1; i < mLocalPaths.size(); i++) {
+ int x = mLocalPaths.keyAt(i);
+ int y = mLocalPaths.valueAt(i);
+ if (y == PATH_DELIM) {
+ if (++i < mLocalPaths.size()) {
+ mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
+ }
+ } else {
+ mPath.lineTo(x, y);
+ }
+ }
+ canvas.drawPath(mPath, mLinePaint);
+ }
+
+ private void drawFilledPath(Canvas canvas) {
+ mPath.reset();
+ float lastStartX = mLocalPaths.keyAt(0);
+ mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
+ for (int i = 1; i < mLocalPaths.size(); i++) {
+ int x = mLocalPaths.keyAt(i);
+ int y = mLocalPaths.valueAt(i);
+ if (y == PATH_DELIM) {
+ mPath.lineTo(mLocalPaths.keyAt(i - 1), getHeight());
+ mPath.lineTo(lastStartX, getHeight());
+ mPath.close();
+ if (++i < mLocalPaths.size()) {
+ lastStartX = mLocalPaths.keyAt(i);
+ mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
+ }
+ } else {
+ mPath.lineTo(x, y);
+ }
+ }
+ canvas.drawPath(mPath, mFillPaint);
+ }
+
+ private void drawDivider(int y, Canvas canvas) {
+ mDivider.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
+ mDivider.draw(canvas);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
new file mode 100644
index 000000000000..f95a97ad0072
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settingslib.graph;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.SparseIntArray;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.settingslib.R;
+
+public class UsageView extends FrameLayout {
+
+ private final UsageGraph mUsageGraph;
+ private final TextView[] mLabels;
+ private final TextView[] mBottomLabels;
+
+ public UsageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ LayoutInflater.from(context).inflate(R.layout.usage_view, this);
+ mUsageGraph = (UsageGraph) findViewById(R.id.usage_graph);
+ mLabels = new TextView[] {
+ (TextView) findViewById(R.id.label_bottom),
+ (TextView) findViewById(R.id.label_middle),
+ (TextView) findViewById(R.id.label_top),
+ };
+ mBottomLabels = new TextView[] {
+ (TextView) findViewById(R.id.label_start),
+ (TextView) findViewById(R.id.label_end),
+ };
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UsageView, 0, 0);
+ if (a.hasValue(R.styleable.UsageView_sideLabels)) {
+ setSideLabels(a.getTextArray(R.styleable.UsageView_sideLabels));
+ }
+ if (a.hasValue(R.styleable.UsageView_bottomLabels)) {
+ setBottomLabels(a.getTextArray(R.styleable.UsageView_bottomLabels));
+ }
+ if (a.hasValue(R.styleable.UsageView_textColor)) {
+ int color = a.getColor(R.styleable.UsageView_textColor, 0);
+ for (TextView v : mLabels) {
+ v.setTextColor(color);
+ }
+ for (TextView v : mBottomLabels) {
+ v.setTextColor(color);
+ }
+ }
+ if (a.hasValue(R.styleable.UsageView_android_gravity)) {
+ int gravity = a.getInt(R.styleable.UsageView_android_gravity, 0);
+ if (gravity == Gravity.END) {
+ LinearLayout layout = (LinearLayout) findViewById(R.id.graph_label_group);
+ LinearLayout labels = (LinearLayout) findViewById(R.id.label_group);
+ // Swap the children order.
+ layout.removeView(labels);
+ layout.addView(labels);
+ // Set gravity.
+ labels.setGravity(Gravity.END);
+ // Swap the bottom label padding
+ LinearLayout bottomLabels = (LinearLayout) findViewById(R.id.bottom_label_group);
+ bottomLabels.setPadding(bottomLabels.getPaddingRight(), bottomLabels.getPaddingTop(),
+ bottomLabels.getPaddingLeft(), bottomLabels.getPaddingBottom());
+ } else if (gravity != Gravity.START) {
+ throw new IllegalArgumentException("Unsupported gravity " + gravity);
+ }
+ }
+ mUsageGraph.setAccentColor(a.getColor(R.styleable.UsageView_android_colorAccent, 0));
+ }
+
+ public void clearPaths() {
+ mUsageGraph.clearPaths();
+ }
+
+ public void addPath(SparseIntArray points) {
+ mUsageGraph.addPath(points);
+ }
+
+ public void configureGraph(int maxX, int maxY, boolean showProjection, boolean projectUp) {
+ mUsageGraph.setMax(maxX, maxY);
+ mUsageGraph.setShowProjection(showProjection, projectUp);
+ }
+
+ public void setAccentColor(int color) {
+ mUsageGraph.setAccentColor(color);
+ }
+
+ public void setSideLabels(CharSequence[] labels) {
+ if (labels.length != mLabels.length) {
+ throw new IllegalArgumentException("Invalid number of labels");
+ }
+ for (int i = 0; i < mLabels.length; i++) {
+ mLabels[i].setText(labels[i]);
+ }
+ }
+
+ public void setBottomLabels(CharSequence[] labels) {
+ if (labels.length != mBottomLabels.length) {
+ throw new IllegalArgumentException("Invalid number of labels");
+ }
+ for (int i = 0; i < mBottomLabels.length; i++) {
+ mBottomLabels[i].setText(labels[i]);
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
index f03e94d4b342..231fc695d344 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
@@ -63,14 +63,15 @@ public class RecentLocationApps {
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps(LOCATION_OPS);
+ final int appOpsCount = appOps != null ? appOps.size() : 0;
+
// Process the AppOps list and generate a preference list.
- ArrayList<Request> requests = new ArrayList<>(appOps.size());
+ ArrayList<Request> requests = new ArrayList<>(appOpsCount);
final long now = System.currentTimeMillis();
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final List<UserHandle> profiles = um.getUserProfiles();
- final int appOpsN = appOps.size();
- for (int i = 0; i < appOpsN; ++i) {
+ for (int i = 0; i < appOpsCount; ++i) {
AppOpsManager.PackageOps ops = appOps.get(i);
// Don't show the Android System in the list - it's not actionable for the user.
// Also don't show apps belonging to background users except managed users.
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 5b8ed28e6997..380fcd4c30ba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -110,6 +110,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
private final Context mContext;
private String ssid;
+ private String bssid;
private int security;
private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
@@ -335,6 +336,10 @@ public class AccessPoint implements Comparable<AccessPoint> {
return ssid;
}
+ public String getBssid() {
+ return bssid;
+ }
+
public CharSequence getSsid() {
SpannableString str = new SpannableString(ssid);
str.setSpan(new TtsSpan.VerbatimBuilder(ssid).build(), 0, ssid.length(),
@@ -657,6 +662,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
else
ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+ bssid = config.BSSID;
security = getSecurity(config);
networkId = config.networkId;
mConfig = config;
@@ -664,6 +670,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
private void initWithScanResult(ScanResult result) {
ssid = result.SSID;
+ bssid = result.BSSID;
security = getSecurity(result);
if (security == SECURITY_PSK)
pskType = getPskType(result);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index b270dd86bb8e..029a1259cd1b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -24,6 +24,8 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -34,6 +36,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.BackupUtils;
import android.util.Log;
import com.android.internal.widget.LockPatternUtils;
@@ -81,36 +84,49 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private static final String KEY_GLOBAL = "global";
private static final String KEY_LOCALE = "locale";
private static final String KEY_LOCK_SETTINGS = "lock_settings";
+ private static final String KEY_SOFTAP_CONFIG = "softap_config";
+ private static final String KEY_NETWORK_POLICIES = "network_policies";
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
- private static final int STATE_VERSION = 4;
+ private static final int STATE_VERSION = 6;
+
+ // Versioning of the Network Policies backup payload.
+ private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
+
// Slots in the checksum array. Never insert new items in the middle
// of this array; new slots must be appended.
- private static final int STATE_SYSTEM = 0;
- private static final int STATE_SECURE = 1;
- private static final int STATE_LOCALE = 2;
- private static final int STATE_WIFI_SUPPLICANT = 3;
- private static final int STATE_WIFI_CONFIG = 4;
- private static final int STATE_GLOBAL = 5;
- private static final int STATE_LOCK_SETTINGS = 6;
-
- private static final int STATE_SIZE = 7; // The current number of state items
+ private static final int STATE_SYSTEM = 0;
+ private static final int STATE_SECURE = 1;
+ private static final int STATE_LOCALE = 2;
+ private static final int STATE_WIFI_SUPPLICANT = 3;
+ private static final int STATE_WIFI_CONFIG = 4;
+ private static final int STATE_GLOBAL = 5;
+ private static final int STATE_LOCK_SETTINGS = 6;
+ private static final int STATE_SOFTAP_CONFIG = 7;
+ private static final int STATE_NETWORK_POLICIES = 8;
+
+ private static final int STATE_SIZE = 9; // The current number of state items
// Number of entries in the checksum array at various version numbers
private static final int STATE_SIZES[] = {
- 0,
- 4, // version 1
- 5, // version 2 added STATE_WIFI_CONFIG
- 6, // version 3 added STATE_GLOBAL
- STATE_SIZE // version 4 added STATE_LOCK_SETTINGS
+ 0,
+ 4, // version 1
+ 5, // version 2 added STATE_WIFI_CONFIG
+ 6, // version 3 added STATE_GLOBAL
+ 7, // version 4 added STATE_LOCK_SETTINGS
+ 8, // version 5 added STATE_SOFTAP_CONFIG
+ STATE_SIZE // version 6 added STATE_NETWORK_POLICIES
};
// Versioning of the 'full backup' format
- private static final int FULL_BACKUP_VERSION = 3;
+ // Increment this version any time a new item is added
+ private static final int FULL_BACKUP_VERSION = 5;
private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
+ private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
+ private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
@@ -119,8 +135,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private static final String TAG = "SettingsBackupAgent";
private static final String[] PROJECTION = {
- Settings.NameValueTable.NAME,
- Settings.NameValueTable.VALUE
+ Settings.NameValueTable.NAME,
+ Settings.NameValueTable.VALUE
};
private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
@@ -146,7 +162,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private SettingsHelper mSettingsHelper;
private WifiManager mWfm;
- private static String mWifiConfigFile;
+ private String mWifiConfigFile;
// Chain of asynchronous operations used when rewriting the wifi supplicant config file
WifiDisableRunnable mWifiDisable = null;
@@ -338,7 +354,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
continue;
}
- if (! mKnownNetworks.contains(net)) {
+ if (!mKnownNetworks.contains(net)) {
if (DEBUG_BACKUP) {
Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
}
@@ -405,26 +421,34 @@ public class SettingsBackupAgent extends BackupAgentHelper {
byte[] locale = mSettingsHelper.getLocaleData();
byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
byte[] wifiConfigData = getFileData(mWifiConfigFile);
+ byte[] softApConfigData = getSoftAPConfiguration();
+ byte[] netPoliciesData = getNetworkPolicies();
long[] stateChecksums = readOldChecksums(oldState);
stateChecksums[STATE_SYSTEM] =
- writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
stateChecksums[STATE_SECURE] =
- writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
stateChecksums[STATE_GLOBAL] =
- writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
stateChecksums[STATE_LOCALE] =
- writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
+ writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
stateChecksums[STATE_WIFI_SUPPLICANT] =
- writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
- wifiSupplicantData, data);
+ writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+ wifiSupplicantData, data);
stateChecksums[STATE_WIFI_CONFIG] =
- writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
- data);
+ writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+ data);
stateChecksums[STATE_LOCK_SETTINGS] =
- writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
- lockSettingsData, data);
+ writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+ lockSettingsData, data);
+ stateChecksums[STATE_SOFTAP_CONFIG] =
+ writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
+ softApConfigData, data);
+ stateChecksums[STATE_NETWORK_POLICIES] =
+ writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
+ netPoliciesData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -503,8 +527,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
restoredSupplicantData, restoredSupplicantData.length);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
- FileUtils.S_IRUSR | FileUtils.S_IWUSR |
- FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Process.myUid(), Process.WIFI_UID);
}
if (restoredWifiConfigFile != null) {
@@ -516,8 +540,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
Settings.Global.putInt(getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways);
}
- enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
- retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
+ || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
}
}
}
@@ -542,27 +566,55 @@ public class SettingsBackupAgent extends BackupAgentHelper {
while (data.readNextHeader()) {
final String key = data.getKey();
final int size = data.getDataSize();
- if (KEY_SYSTEM.equals(key)) {
- restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
- mSettingsHelper.applyAudioSettings();
- } else if (KEY_SECURE.equals(key)) {
- restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
- } else if (KEY_GLOBAL.equals(key)) {
- restoreSettings(data, Settings.Global.CONTENT_URI, null);
- } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
- initWifiRestoreIfNecessary();
- mWifiRestore.incorporateWifiSupplicant(data);
- } else if (KEY_LOCALE.equals(key)) {
- byte[] localeData = new byte[size];
- data.readEntityData(localeData, 0, size);
- mSettingsHelper.setLocaleData(localeData, size);
- } else if (KEY_WIFI_CONFIG.equals(key)) {
- initWifiRestoreIfNecessary();
- mWifiRestore.incorporateWifiConfigFile(data);
- } else if (KEY_LOCK_SETTINGS.equals(key)) {
- restoreLockSettings(data);
- } else {
- data.skipEntityData();
+ switch (key) {
+ case KEY_SYSTEM :
+ restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
+ mSettingsHelper.applyAudioSettings();
+ break;
+
+ case KEY_SECURE :
+ restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+ break;
+
+ case KEY_GLOBAL :
+ restoreSettings(data, Settings.Global.CONTENT_URI, null);
+ break;
+
+ case KEY_WIFI_SUPPLICANT :
+ initWifiRestoreIfNecessary();
+ mWifiRestore.incorporateWifiSupplicant(data);
+ break;
+
+ case KEY_LOCALE :
+ byte[] localeData = new byte[size];
+ data.readEntityData(localeData, 0, size);
+ mSettingsHelper.setLocaleData(localeData, size);
+ break;
+
+ case KEY_WIFI_CONFIG :
+ initWifiRestoreIfNecessary();
+ mWifiRestore.incorporateWifiConfigFile(data);
+ break;
+
+ case KEY_LOCK_SETTINGS :
+ restoreLockSettings(data);
+ break;
+
+ case KEY_SOFTAP_CONFIG :
+ byte[] softapData = new byte[size];
+ data.readEntityData(softapData, 0, size);
+ restoreSoftApConfiguration(softapData);
+ break;
+
+ case KEY_NETWORK_POLICIES:
+ byte[] netPoliciesData = new byte[size];
+ data.readEntityData(netPoliciesData, 0, size);
+ restoreNetworkPolicies(netPoliciesData);
+ break;
+
+ default :
+ data.skipEntityData();
+
}
}
@@ -589,6 +641,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
byte[] locale = mSettingsHelper.getLocaleData();
byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
byte[] wifiConfigData = getFileData(mWifiConfigFile);
+ byte[] softApConfigData = getSoftAPConfiguration();
+ byte[] netPoliciesData = getNetworkPolicies();
// Write the data to the staging file, then emit that as our tarfile
// representation of the backed-up settings.
@@ -605,16 +659,22 @@ public class SettingsBackupAgent extends BackupAgentHelper {
if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
out.writeInt(systemSettingsData.length);
out.write(systemSettingsData);
- if (DEBUG_BACKUP) Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
+ if (DEBUG_BACKUP) {
+ Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
+ }
out.writeInt(secureSettingsData.length);
out.write(secureSettingsData);
- if (DEBUG_BACKUP) Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+ if (DEBUG_BACKUP) {
+ Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+ }
out.writeInt(globalSettingsData.length);
out.write(globalSettingsData);
if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
out.writeInt(locale.length);
out.write(locale);
- if (DEBUG_BACKUP) Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
+ if (DEBUG_BACKUP) {
+ Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
+ }
out.writeInt(wifiSupplicantData.length);
out.write(wifiSupplicantData);
if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
@@ -623,6 +683,12 @@ public class SettingsBackupAgent extends BackupAgentHelper {
if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
out.writeInt(lockSettingsData.length);
out.write(lockSettingsData);
+ if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
+ out.writeInt(softApConfigData.length);
+ out.write(softApConfigData);
+ if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of net policies data");
+ out.writeInt(netPoliciesData.length);
+ out.write(netPoliciesData);
out.flush(); // also flushes downstream
@@ -691,12 +757,12 @@ public class SettingsBackupAgent extends BackupAgentHelper {
int retainedWifiState = enableWifi(false);
restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
- FileUtils.S_IRUSR | FileUtils.S_IWUSR |
- FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Process.myUid(), Process.WIFI_UID);
// retain the previous WIFI state.
- enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
- retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
+ || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
// wifi config
nBytes = in.readInt();
@@ -714,7 +780,26 @@ public class SettingsBackupAgent extends BackupAgentHelper {
restoreLockSettings(buffer, nBytes);
}
}
-
+ // softap config
+ if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ if (nBytes > 0) {
+ in.readFully(buffer, 0, nBytes);
+ restoreSoftApConfiguration(buffer);
+ }
+ }
+ // network policies
+ if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ if (nBytes > 0) {
+ in.readFully(buffer, 0, nBytes);
+ restoreNetworkPolicies(buffer);
+ }
+ }
if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
} else {
data.close();
@@ -904,7 +989,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
if (DEBUG) {
- Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
+ Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
}
}
}
@@ -1036,12 +1121,12 @@ public class SettingsBackupAgent extends BackupAgentHelper {
//Will truncate read on a very long file,
//should not happen for a config file
- byte[] bytes = new byte[(int)file.length()];
+ byte[] bytes = new byte[(int) file.length()];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
- && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
@@ -1062,7 +1147,6 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
}
-
}
private void restoreFileData(String filename, byte[] bytes, int size) {
@@ -1165,6 +1249,87 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
+ private byte[] getSoftAPConfiguration() {
+ WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ try {
+ return wifiManager.getWifiApConfiguration().getBytesForBackup();
+ } catch (IOException ioe) {
+ Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
+ return new byte[0];
+ }
+ }
+
+ private void restoreSoftApConfiguration(byte[] data) {
+ WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ try {
+ WifiConfiguration config = WifiConfiguration
+ .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
+ if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
+ wifiManager.setWifiApConfiguration(config);
+ } catch (IOException | BackupUtils.BadVersionException e) {
+ Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
+ }
+ }
+
+ private byte[] getNetworkPolicies() {
+ NetworkPolicyManager networkPolicyManager =
+ (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
+ NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if (policies != null && policies.length != 0) {
+ DataOutputStream out = new DataOutputStream(baos);
+ try {
+ out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
+ out.writeInt(policies.length);
+ for (NetworkPolicy policy : policies) {
+ if (policy != null) {
+ byte[] marshaledPolicy = policy.getBytesForBackup();
+ out.writeByte(BackupUtils.NOT_NULL);
+ out.writeInt(marshaledPolicy.length);
+ out.write(marshaledPolicy);
+ } else {
+ out.writeByte(BackupUtils.NULL);
+ }
+ }
+ } catch (IOException ioe) {
+ Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
+ baos.reset();
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ private void restoreNetworkPolicies(byte[] data) {
+ NetworkPolicyManager networkPolicyManager =
+ (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
+ if (data != null && data.length != 0) {
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+ try {
+ int version = in.readInt();
+ if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException(
+ "Unknown Backup Serialization Version");
+ }
+ int length = in.readInt();
+ NetworkPolicy[] policies = new NetworkPolicy[length];
+ for (int i = 0; i < length; i++) {
+ byte isNull = in.readByte();
+ if (isNull == BackupUtils.NULL) continue;
+ int byteLength = in.readInt();
+ byte[] policyData = new byte[byteLength];
+ in.read(policyData, 0, byteLength);
+ policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
+ new DataInputStream(new ByteArrayInputStream(policyData)));
+ }
+ // Only set the policies if there was no error in the restore operation
+ networkPolicyManager.setNetworkPolicies(policies);
+ } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
+ // NPE can be thrown when trying to instantiate a NetworkPolicy
+ Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
+ }
+ }
+ }
+
/**
* Write an int in BigEndian into the byte array.
* @param out byte array
@@ -1186,11 +1351,10 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
private int readInt(byte[] in, int pos) {
- int result =
- ((in[pos ] & 0xFF) << 24) |
- ((in[pos + 1] & 0xFF) << 16) |
- ((in[pos + 2] & 0xFF) << 8) |
- ((in[pos + 3] & 0xFF) << 0);
+ int result = ((in[pos] & 0xFF) << 24)
+ | ((in[pos + 1] & 0xFF) << 16)
+ | ((in[pos + 2] & 0xFF) << 8)
+ | ((in[pos + 3] & 0xFF) << 0);
return result;
}
@@ -1207,4 +1371,4 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
return WifiManager.WIFI_STATE_UNKNOWN;
}
-}
+} \ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 57d495f6f936..9842e28ffdba 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -49,6 +49,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SELinux;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -457,8 +458,28 @@ public class SettingsProvider extends ContentProvider {
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- throw new FileNotFoundException("Direct file access no longer supported; "
- + "ringtone playback is available through android.media.Ringtone");
+ final String cacheName;
+ if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
+ cacheName = Settings.System.RINGTONE_CACHE;
+ } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) {
+ cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
+ } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) {
+ cacheName = Settings.System.ALARM_ALERT_CACHE;
+ } else {
+ throw new FileNotFoundException("Direct file access no longer supported; "
+ + "ringtone playback is available through android.media.Ringtone");
+ }
+
+ final File cacheFile = new File(
+ getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+ return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
+ }
+
+ private File getRingtoneCacheDir(int userId) {
+ final File cacheDir = new File(Environment.getDataSystemDeDirectory(userId), "ringtones");
+ cacheDir.mkdir();
+ SELinux.restorecon(cacheDir);
+ return cacheDir;
}
@Override
@@ -901,6 +922,21 @@ public class SettingsProvider extends ContentProvider {
return false;
}
+ // Invalidate any relevant cache files
+ String cacheName = null;
+ if (Settings.System.RINGTONE.equals(name)) {
+ cacheName = Settings.System.RINGTONE_CACHE;
+ } else if (Settings.System.NOTIFICATION_SOUND.equals(name)) {
+ cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
+ } else if (Settings.System.ALARM_ALERT.equals(name)) {
+ cacheName = Settings.System.ALARM_ALERT_CACHE;
+ }
+ if (cacheName != null) {
+ final File cacheFile = new File(
+ getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+ cacheFile.delete();
+ }
+
// Mutate the value.
synchronized (mLock) {
switch (operation) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7416fb564e27..5b865f97281b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -40,6 +40,7 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
@@ -109,6 +110,7 @@
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<application android:label="@string/app_label"
android:forceDeviceEncrypted="true"
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index b9a7c24f0363..9d399c193a31 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Tuisskerm"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Foutverslag word tans gegenereer"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutverslag vasgevang"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Foutverslag <xliff:g id="ID">#%d</xliff:g> word tans geskep"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Foutverslag <xliff:g id="ID">#%d</xliff:g> is vasgevang"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Voeg tans besonderhede by die foutverslag"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Wag asseblief …"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swiep na links om jou foutverslag te deel"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak om jou foutverslag te deel"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tik om jou foutverslag te deel"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Foutverslae bevat data van die stelsel se verskillende loglêers af, insluitend persoonlike en private inligting. Deel foutverslae net met programme en mense wat jy vertrou."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Wys hierdie boodskap volgende keer"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Foutverslae"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Besonderhede"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skermkiekie"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skermkiekie suksesvol geneem."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skermkiekie is suksesvol geneem."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Foutverslagbesonderhede"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Foutverslag <xliff:g id="ID">#%d</xliff:g> se besonderhede"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Lêernaam"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beskrywing"</string>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 7c5519ef2403..254522218678 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ቀፎ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"የሳንካ ሪፓርት እየመነጨ ነው"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"የሳንካ ሪፖርት ተይዟል"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> እየተመነጨ ነው"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ተወስዷል"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ዝርዝሮችን ወደ የሳንካ ሪፖርቱ በማከል ላይ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"እባክዎ ይጠብቁ…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"የሳንካ ሪፖርትዎን ለማጋራት ወደ ግራ ያንሸራትቱ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"የሳንካ ሪፖርትዎን ለማጋራት ይንክኩ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"የሳንካ ሪፖርትዎን ለማጋራት መታ ያድርጉ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"የሳንካ ሪፖርቶች የግል መረጃን ጨምሮ ከበርካታ የስርዓቱ ምዝግብ ማስታወሻዎች የመጣ ውሂብን ይዟል። የሳንካ ሪፖርቶች ለሚያምኗቸው መተግበሪያዎችን እና ሰዎችን ብቻ ያጋሩ።"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ይህን መልዕክት በሚቀጥለው ጊዜ አሳይ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"የሳንካ ሪፖርቶች"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ያልተሰየመ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ዝርዝሮች"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ቅጽበታዊ ገጽ እይታ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ቅጽበታዊ ገጽ እይታ በስኬት ተነስቷል።"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ቅጽበታዊ ገጽ እይታ በተሳካ ሁኔታ ተነስቷል"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"የሳንካ ሪፖርት ዝርዝሮች"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ዝርዝሮች"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"የፋይል ስም"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ርዕስ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ዝርዝር መግለጫ"</string>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index b10793199e6c..7593110a0d00 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"جارٍ إنشاء تقرير الخطأ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"تم الحصول على تقرير الأخطاء"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"جارٍ إنشاء تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>."</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"تم تسجيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>."</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"إضافة تفاصيل إلى تقرير الخطأ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"الرجاء الانتظار…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"مرر بسرعة لليمين لمشاركة تقرير الخطأ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"المس لمشاركة تقرير الأخطاء"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"انقر لمشاركة تقرير الخطأ."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"تحتوي تقارير الأخطاء على بيانات من ملفات سجلات النظام المتنوعة، بما في ذلك معلومات شخصية وخاصة. لا تشارك تقارير الأخطاء إلا مع التطبيقات والأشخاص الموثوق بهم."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"إظهار هذه الرسالة في المرة القادمة"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"تقارير الأخطاء"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"بدون اسم"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"التفاصيل"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"لقطة شاشة"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"تم التقاط لقطة الشاشة بنجاح."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"تم تسجيل لقطة الشاشة بنجاح."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"تفاصيل تقرير الخطأ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"تفاصيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"اسم الملف"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"العنوان"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"وصف تفصيلي"</string>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index d01ae2af8ed7..9130255fd18b 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug hesabat yaradıldı"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Baq raport alındı"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> yaradıldı"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> alındı"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Detallar baq hesabatına əlavə olunur"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfən, gözləyin..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Baq raportunu paylaşmaq üçün sola sürüşdürün"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xətanı şikayətini paylaşmaq üçün toxunun"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Baq hesabatınızı paylaşmaq üçün tıklayın"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Baq raportları sistemin müxtəlif jurnal fayllarından data içərir ki, buna şəxsi və konfidensial məlumatlar da aiddir. Yalnız inandığınız adamlarla baq raportlarını paylaşın."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bu mesajı növbəti dəfə göstər"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detallar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"displey görüntüsü"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Displey görüntüsü uğurla çəkildi."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Displey görüntüsü uğurla çəkildi."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Baq hesabat detalları"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> detalları"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fayl adı"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Başlıq"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Ətraflı təsvir"</string>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index f39dbcb37a4e..597e5457ce6c 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Izveštaj o grešci se generiše"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveštaj o grešci je snimljen"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> se generiše"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Izveštaj o grešci <xliff:g id="ID">#%d</xliff:g> je snimljen"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaju se detalji u izveštaj o grešci"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sačekajte..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prevucite ulevo da biste delili izveštaj o greškama"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite da biste delili izveštaj o grešci"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste delili izveštaj o grešci"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Izveštaji o greškama sadrže podatke iz različitih sistemskih datoteka evidencije, uključujući lične i privatne podatke. Delite izveštaje o greškama samo sa aplikacijama i ljudima u koje imate poverenja."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži ovu poruku sledeći put"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Izveštaji o greškama"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimci ekrana"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snimanje ekrana je uspelo."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Snimak ekrana je napravljen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalji izveštaja o grešci"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izveštaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljni opis"</string>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index 068bcd35492d..6ca791409773 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Команден ред"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Сигналът за програмна грешка се генерира"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчетът за програмни грешки е записан"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Сигналът за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“ се генерира"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Сигналът за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“ е заснет"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Подробностите се добавят към сигнала за пр. грешка"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Моля, изчакайте…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Прекарайте пръст наляво, за да споделите сигнала си за програмна грешка"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Докоснете, за да споделите отчета си за програмни грешки"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Докоснете, за да споделите сигнала си за програмна грешка"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчетите за програмни грешки съдържат данни от различни регистрационни файлове на системата, включително лична и поверителна информация. Споделяйте ги само с приложения и хора, на които имате доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Това съобщение да се показва следващия път"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Отчети за прогр. грешки"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"без име"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Подробности"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Екранна снимка"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Екранната снимка бе направена успешно."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Екранната снимка бе направена успешно."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Подробности за сигнала за програмна грешка"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Подробности за сигнала за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на файла"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Заглавие"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Подробно описание"</string>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index a97358624fc2..5390315737f5 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"শেল"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ত্রুটির প্রতিবেদন তৈরি করা হচ্ছে"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ত্রুটির প্রতিবেদন নেওয়া হয়েছে"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> তৈরি করা হচ্ছে"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> ক্যাপচার করা হয়েছে"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ত্রুটির প্রতিবেদনে বিশদ বিবরণ যোগ করা হচ্ছে"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"অনুগ্রহ করে অপেক্ষা করুন..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"আপনার বাগ রিপোর্ট শেয়ার করতে বামে সোয়াইপ করুন"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"আপনার ত্রুটির প্রতিবেদন শেয়ার করতে স্পর্শ করুন"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"আপনার ত্রুটির প্রতিবেদন শেয়ার করতে আলতো চাপ দিন"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ত্রুটির প্রতিবেদনগুলিতে থাকা ডেটা, সিস্টেমের বিভিন্ন লগ ফাইলগুলি থেকে আসে, যাতে ব্যক্তিগত এবং গোপনীয় তথ্য অন্তর্ভুক্ত থাকে৷ আপনি বিশ্বাস করেন শুধুমাত্র এমন অ্যাপ্লিকেশান এবং ব্যক্তিদের সাথে ত্রুটির প্রতিবেদনগুলি ভাগ করুন৷"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"এই বার্তাটি পরের বার দেখান"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ত্রুটির প্রতিবেদনগুলি"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"নামবিহীন"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"বিশদ বিবরণ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"স্ক্রীনশট"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"স্ক্রীনশট সফলভাবে নেওয়া হয়েছে৷"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"স্ক্রীনশট সফলভাবে নেওয়া হয়েছে৷"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ত্রুটি প্রতিবেদনের বিবরণ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> এর বিশদ বিবরণ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ফাইলের নাম"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"শীর্ষক"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"বিস্তারিত বিবরণ"</string>
diff --git a/packages/Shell/res/values-bs-rBA/strings.xml b/packages/Shell/res/values-bs-rBA/strings.xml
index 55a9341ce9c7..903c2ab05d72 100644
--- a/packages/Shell/res/values-bs-rBA/strings.xml
+++ b/packages/Shell/res/values-bs-rBA/strings.xml
@@ -16,42 +16,24 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (3701846017049540910) -->
- <skip />
- <!-- no translation found for bugreport_in_progress_title (7409917338223386637) -->
- <skip />
- <!-- no translation found for bugreport_finished_title (2293711546892863898) -->
- <skip />
+ <string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Izvještaj o grešci <xliff:g id="ID">#%d</xliff:g> se generira"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Izvještaj o grešci <xliff:g id="ID">#%d</xliff:g> je snimljen"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje detalja u izvještaj o greškama"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
- <!-- no translation found for bugreport_finished_text (8389172248433597683) -->
- <skip />
- <!-- no translation found for bugreport_finished_text (3559904746859400732) -->
- <skip />
- <!-- no translation found for bugreport_confirm (5130698467795669780) -->
- <skip />
- <!-- no translation found for bugreport_confirm_repeat (4926842460688645058) -->
- <skip />
- <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
- <skip />
- <!-- no translation found for bugreport_unreadable_text (586517851044535486) -->
- <skip />
- <!-- no translation found for bugreport_unnamed (2800582406842092709) -->
- <skip />
- <!-- no translation found for bugreport_info_action (2158204228510576227) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_action (8677781721940614995) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_taken (7175343181767429088) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failed (5853049140806834601) -->
- <skip />
- <!-- no translation found for bugreport_info_dialog_title (3113549839798564645) -->
- <skip />
- <!-- no translation found for bugreport_info_name (4414036021935139527) -->
- <skip />
- <!-- no translation found for bugreport_info_title (5599558206004371052) -->
- <skip />
- <!-- no translation found for bugreport_info_description (4117088998733546784) -->
- <skip />
+ <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prevucite lijevo da podijelite izvještaj o greškama"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvještaj o grešci"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Izvještaji o greškama sadrže podatke iz raznih zapisnika sistema, uključujući lične i privatne informacije. Podijelite izvještaje o greškama samo sa aplikacijama i osobama kojima vjerujete."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži ovu poruku sljedeći put"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvještaji o greškama"</string>
+ <string name="bugreport_unreadable_text" msgid="586517851044535486">"Nije moguće pročitati izvještaj o grešci"</string>
+ <string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimak ekrana"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekran je uspješno snimljen."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran nije moguće snimiti."</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izvještaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv fajla"</string>
+ <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
</resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 14c21dac44cd..08369461eaa4 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Protecció"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"S\'està generant l\'informe d\'errors"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"S\'ha registrat l\'informe d\'error"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"S\'està generant l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"S\'ha capturat l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"S\'estan afegint detalls a l\'informe d\'errors"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Llisca cap a l\'esquerra per compartir l\'informe d\'errors."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca per compartir l\'informe d\'errors"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Els informes d\'error contenen dades dels diferents fitxers de registre del sistema, inclosa informació privada i personal. Comparteix els informes d\'error només amb les aplicacions i amb les persones en qui confies."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra aquest missatge la propera vegada"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'error"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sense nom"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalls"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla s\'ha fet correctament."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"La captura de pantalla s\'ha fet correctament."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalls de l\'informe d\'errors"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalls de l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom del fitxer"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Títol"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descripció detallada"</string>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index 19a4453b367e..215ec87b09e2 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Vytváří se zpráva o chybě"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bylo vytvořeno chybové hlášení"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Zpráva o chybě <xliff:g id="ID">#%d</xliff:g> se vytváří"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Zpráva o chybě <xliff:g id="ID">#%d</xliff:g> byla vytvořena"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Přidávání podrobností do zprávy o chybě"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Čekejte prosím…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Chcete-li hlášení chyby sdílet, přejeďte doleva."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chybové hlášení můžete sdílet klepnutím."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Zprávu o chybě můžete sdílet klepnutím"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Chybová hlášení obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Chybová hlášení sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Zprávy o chybách"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímek obrazovky"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímek obrazovky byl úspěšně pořízen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Snímek obrazovky byl úspěšně pořízen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti zprávy o chybě"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti zprávy o chybě <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Název souboru"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Název"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index a03276a9d508..e956d3a177e6 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Fejlrapport genereres"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Fejlrapporten er registreret"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Fejlrapporten <xliff:g id="ID">#%d</xliff:g> genereres"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Fejrapporten <xliff:g id="ID">#%d</xliff:g> blev gemt"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Tilføjelse af oplysninger til fejlrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent et øjeblik…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Stryg til venstre for at dele din fejlrapport"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryk for at dele din fejlrapport"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tryk for at dele din fejlrapport"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Fejlrapporter indeholder data fra systemets forskellige logfiler, f.eks. personlige og private oplysninger. Del kun fejlrapporter med apps og personer, du har tillid til."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne underretning næste gang"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fejlrapporter"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ikke navngivet"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Oplysninger"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skærmbillede"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Der blev taget et skærmbillede."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Der blev taget et skærmbillede."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Fejlrapportoplysninger"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Oplysninger om fejlrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljeret beskrivelse"</string>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 4f5e6c5cf5e8..07f889890ba5 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Fehlerbericht wird generiert"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Fehlerbericht erfasst"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> wird generiert"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Fehlerbericht <xliff:g id="ID">#%d</xliff:g> erfasst"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Informationen werden zum Fehlerbericht hinzugefügt"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Bitte warten…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Wische nach links, um deinen Fehlerbericht zu teilen."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tippen, um Fehlerbericht zu teilen"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Zum Teilen des Fehlerberichts tippen"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Fehlerberichte enthalten Daten aus verschiedenen Protokolldateien des Systems, darunter auch personenbezogene und private Daten. Teile Fehlerberichte nur mit Apps und Personen, denen du vertraust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Diese Nachricht nächstes Mal zeigen"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fehlerberichte"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"Unbenannt"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot wurde aufgenommen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot wurde aufgenommen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details des Fehlerberichts"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details zum Fehlerbericht <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Dateiname"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaillierte Beschreibung"</string>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 71debd7e52cb..674697685dd5 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Δημιουργείται αναφορά σφάλματος"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Δημιουργείται η αναφορά σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Έγινε λήψη της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Προσθήκη λεπτομερειών στην αναφορά σφάλματος"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Περιμένετε…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Σύρετε προς τα αριστερά για κοινή χρήση της αναφοράς σφαλμάτων"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Πατήστε για κοινή χρήση της αναφοράς σφάλματος"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Εμφάνιση αυτού του μηνύματος την επόμενη φορά"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Αναφορές σφαλμάτων"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ανώνυμη"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Λεπτομέρειες"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Στιγμιότυπο οθόνης"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Η λήψη του στιγμιότυπου οθόνης ολοκληρώθηκε με επιτυχία."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Η λήψη του στιγμιότυπου οθόνης ολοκληρώθηκε με επιτυχία."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Λεπτομέρειες αναφοράς σφαλμάτων"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Λεπτομέρειες της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Όνομα αρχείου"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Τίτλος"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Αναλυτική περιγραφή"</string>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index a1bd9799df8b..ac681e27bc94 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bug report <xliff:g id="ID">#%d</xliff:g> is being generated"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Bug report <xliff:g id="ID">#%d</xliff:g> captured"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tap to share your bug report"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot taken successfully."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index a1bd9799df8b..ac681e27bc94 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bug report <xliff:g id="ID">#%d</xliff:g> is being generated"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Bug report <xliff:g id="ID">#%d</xliff:g> captured"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tap to share your bug report"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot taken successfully."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index a1bd9799df8b..ac681e27bc94 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bug report <xliff:g id="ID">#%d</xliff:g> is being generated"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Bug report <xliff:g id="ID">#%d</xliff:g> captured"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adding details to the bug report"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Please wait…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swipe left to share your bug report"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tap to share your bug report"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot taken successfully."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index f86fea0741d2..96ca14c6ebce 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"El informe de errores se está generando"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de errores capturado"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Se está generando el informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Se capturó el informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Agregando detalles al informe de errores"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de errores."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de errores."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca para compartir el informe de errores"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida la información personal y privada. Comparte los informes de errores únicamente con aplicaciones y personas en las que confíes."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de errores"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Se tomó la captura de pantalla correctamente."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Se tomó la captura de pantalla correctamente."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nombre del archivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index 8f6cdebbd1ed..00874c620583 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Se está generando el informe de errores"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de error registrado"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Se está generando el informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Informe de errores <xliff:g id="ID">#%d</xliff:g> capturado"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Añadiendo detalles al informe de errores"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Espera…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Desliza el dedo hacia la izquierda para compartir el informe de error"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de error"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca para compartir el informe de errores"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida información personal y privada. Comparte los informes de errores únicamente con aplicaciones y usuarios en los que confíes."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de error"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla se ha realizado correctamente."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Captura de pantalla realizada correctamente."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nombre de archivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index 3ebd56df6969..bc469bcd93ee 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kest"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Veaaruande loomine"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luuakse veaaruannet <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Jäädvustati veaaruanne <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Üksikasjade lisamine veaaruandesse"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Oodake …"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veaaruande jagamiseks pühkige vasakule"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Veaaruande jagamiseks puudutage"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Veaaruanded"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"nimeta"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Üksikasjad"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekraanipilt"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekraanipildi tegemine õnnestus."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekraanipildi jäädvustamine õnnestus."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Veaaruande üksikasjad"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Veaaruande <xliff:g id="ID">#%d</xliff:g> üksikasjad"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Faili nimi"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Pealkiri"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Üksikasjalik kirjeldus"</string>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 93fdb60965fb..614f17ecda94 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell-interfazea"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Sortzen ari gara akatsen txostena"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Akatsen txostena jaso da"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostena egiten ari gara"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostena egin da"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Akatsen txostenean xehetasunak gehitzen"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Itxaron, mesedez…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Programa-akatsen txostena partekatzeko, pasatu hatza ezkerrera"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Akatsen txostena partekatzeko, ukitu"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Sakatu akatsen txostena partekatzeko"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Erakutsi mezu hau hurrengoan"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Akatsen txostenak"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"izengabea"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Xehetasunak"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pantaila-argazkia"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Atera da pantaila-argazkia."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Atera da pantaila-argazkia."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Akatsen txostenaren xehetasunak"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostenaren xehetasunak"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fitxategi-izena"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Izena"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Azalpen xehatua"</string>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index c4ec8b42cb1b..ab00562eaa75 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"گزارش اشکال در حال ایجاد شدن است"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"گزارش اشکال دریافت شد"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"گزارش اشکال <xliff:g id="ID">#%d</xliff:g> در حال ایجاد شدن است"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"گزارش اشکال <xliff:g id="ID">#%d</xliff:g> ثبت شد"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"اضافه کردن جزئیات به گزارش اشکال"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"لطفاً منتظر بمانید..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"برای اشتراک‌گذاری گزارش اشکال، به تندی آن را به چپ بکشید"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"جهت اشتراک‌گذاری گزارش اشکال خود لمس کنید"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"برای به اشتراک گذاشتن گزارش اشکال، ضربه بزنید"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"گزارش‌های اشکال حاوی داده‌هایی از فایل‌های گزارش مختلف در سیستم هستند، شامل اطلاعات شخصی و خصوصی. گزارش‌های اشکال را فقط با افراد و برنامه‌های مورد اعتماد خود به اشتراک بگذارید."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"دفعه بعد این پیام نشان داده شود"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"گزارش اشکال"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"بی‌نام"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"جزئیات"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"عکس صفحه‌نمایش"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"عکس صفحه‌نمایش با موفقیت گرفته شد."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"عکس صفحه‌نمایش با موفقیت گرفته شد."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمی‌توان عکس صفحه‌نمایش گرفت."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"جزئیات گزارش اشکال"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"جزئیات گزارش اشکال <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"نام فایل"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"جزئیات دقیق"</string>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index 0fc4b77ab89a..be7aabd5b882 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Komentotulkki"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Luodaan virheraporttia"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Virheraportti tallennettu"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luodaan virheraporttia <xliff:g id="ID">#%d</xliff:g>."</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Virheraportti <xliff:g id="ID">#%d</xliff:g> tallennettu"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Lisätään tietoja virheraporttiin"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Odota…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Jaa virheraportti pyyhkäisemällä vasemmalle"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Jaa virheraportti koskettamalla tätä"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Jaa virheraportti napauttamalla."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Virheraportit sisältävät järjestelmän lokitietoja, ja niihin voi sisältyä henkilökohtaisia ja yksityisiä tietoja. Jaa virheraportteja vain luotettaville sovelluksille ja käyttäjille."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Näytä tämä viesti seuraavalla kerralla"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Virheraportit"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"nimetön"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Tietoja"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Kuvakaappaus"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Kuvakaappaus tallennettu."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Kuvakaappaus on tallennettu."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Virheraportin tiedot"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Virheraportin <xliff:g id="ID">#%d</xliff:g> tiedot"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Tiedostonimi"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Otsikko"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Yksityiskohtainen kuvaus"</string>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index d2ef54caf82b..7d9f97d5385c 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Le rapport de bogue est en cours de création"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bogue enregistré"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Rapport de bogue <xliff:g id="ID">#%d</xliff:g> généré"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Rapport de bogue <xliff:g id="ID">#%d</xliff:g> enregistré"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Ajout de détails au rapport de bogue"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Veuillez patienter…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport de bogue."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Touchez ici pour partager votre rapport de bogue"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bogue qu\'avec les applications et les personnes que vous estimez fiables."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bogues"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Saisie d\'écran"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La saisie d\'écran a réussi."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"La saisie d\'écran a réussi."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Une erreur s\'est produite lors de la saisie d\'écran."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bogue"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Détails du rapport de bogue <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index ca135edf02b9..74025d90c5c5 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Le rapport de bug est en cours de création."</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bug enregistré"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\" est en cours de création"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\" a bien été enregistré"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Ajout d\'informations au rapport de bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Veuillez patienter…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Faites glisser le doigt vers la gauche pour partager votre rapport d\'erreur."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyez ici pour partager le rapport de bug"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Appuyer pour partager votre rapport de bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bug contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bug qu\'avec les applications et les personnes que vous estimez fiables."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports d\'erreur"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captures d\'écran"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La capture d\'écran a bien été effectuée."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"La capture d\'écran a bien été effectuée."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Informations sur le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\""</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 612d346db766..d3be7c5bacea 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Estase xerando o informe de erro"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de erros rexistrado"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Estase xerando o informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Rexistrouse o informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Engadindo detalles ao informe de erro"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Agarda..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Pasa o dedo á esquerda para compartir o teu informe de erros"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí para compartir o teu informe de erros"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toca para compartir o teu informe de erros"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os informes de erros conteñen datos dos distintos ficheiros de rexistro do sistema, incluída información persoal e privada. Comparte os informes de erros unicamente con aplicacións e persoas de confianza."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensaxe a próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de erros"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sen nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"A captura de pantalla realizouse correctamente."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"A captura de pantalla realizouse correctamente."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles do informe de erros"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles do informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrición detallada"</string>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 7baefe7875f8..45df7b35ebc8 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"શેલ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"બગ રિપોર્ટ જનરેટ કરવામાં આવી રહી છે"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"બગ રિપોર્ટ કેપ્ચર કરી"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> જનરેટ કરવામાં આવી રહી છે"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> કૅપ્ચર કરી"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"બગ રિપોર્ટમાં વિગતો ઉમેરવી"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"કૃપા કરીને રાહ જુઓ…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"તમારી બગ રિપોર્ટ શેર કરવા માટે ડાબે સ્વાઇપ કરો"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"તમારી બગ રિપોર્ટ શેર કરવા માટે ટચ કરો"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"તમારી બગ રિપોર્ટ શેર કરવા ટૅપ કરો"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"બગ રિપોર્ટ્સ વ્યક્તિગત અને ખાનગી માહિતી સહિત, સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે. બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે એપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"આગલી વખતે આ સંદેશ બતાવો"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ્સ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"અનામાંકિત"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"વિગતો"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"સ્ક્રીનશોટ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"સ્ક્રીનશોટ સફળતાપૂર્વક લેવાયો."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"સ્ક્રીનશોટ સફળતાપૂર્વક લેવાયો."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"બગ રિપોર્ટની વિગતો"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> ની વિગતો"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ફાઇલનું નામ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"શીર્ષક"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"વિગતવાર વર્ણન"</string>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index c21213e45c0f..8858bc3202e4 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"बग रिपोर्ट जेनरेट हो रही है"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> जेनरेट की जा रही है"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्ट में विवरण जोड़े जा रहे हैं"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करें…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"अपनी बग रिपोर्ट साझा करने के लिए बाएं स्वाइप करें"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"अपनी बग रिपोर्ट साझा करने के लिए टैप करें"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय ऐप्स और व्यक्तियों से ही साझा करें."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यह संदेश अगली बार दिखाएं"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्ट"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामांकित"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्ट के विवरण"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> के विवरण"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत वर्णन"</string>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index 810ad3a437db..cb03f9cec314 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generira se izvješće o programskoj pogrešci"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Prijava programske pogreške snimljena je"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generira se izvješće o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Izvješće o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g> snimljeno"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje pojedinosti u izvješće o progr. pogrešci"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prijeđite prstom ulijevo da biste poslali izvješće o programskim pogreškama"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvješće o programskoj pogrešci"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Prijave programskih pogrešaka sadržavaju podatke iz različitih datoteka zapisnika sustava, uključujući osobne i privatne informacije. Prijave programskih pogrešaka dijelite samo s aplikacijama i osobama koje smatrate pouzdanima."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži tu poruku sljedeći put"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez naziva"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Pojedinosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimka zaslona"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zaslon je snimljen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Snimka zaslona uspješno izrađena."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Pojedinosti izvješća o programskoj pogrešci"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Pojedinosti izvješća o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index b78fc61e5a57..390cd2f3ca3a 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Héj"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Hibajelentés létrehozása folyamatban"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Programhiba-jelentés rögzítve"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) létrehozása folyamatban"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) rögzítve"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Információk hozzáadása a hibajelentéshez"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Kérjük, várjon..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Húzza ujját balra a hibajelentés megosztásához"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Érintse meg a programhiba-jelentés megosztásához"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Koppintson a hibajelentés megosztásához"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"A programhiba-jelentések a rendszer különféle naplófájljaiból származó adatokat tartalmaznak, köztük személyes és magánjellegű információkat is. Csak olyan alkalmazásokkal és személyekkel osszon meg programhiba-jelentéseket, amelyekben vagy akikben megbízik."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Üzenet mutatása legközelebb"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hibajelentések"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"névtelen"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Részletek"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Képernyőkép"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Sikerült elkészíteni a képernyőképet."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Képernyőkép sikeresen rögzítve."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nem sikerült elkészíteni a képernyőképet."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hibajelentés részletei"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) részletei"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fájlnév"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Név"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Részletes leírás"</string>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 4912d542b6a1..68478abffff4 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Վրիպակի զեկույցը ստեղծվում է"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Վրիպակի զեկույց է ստացվել"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը ստեղծվում է"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը գրանցվեց"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Տվյալների ավելացում վրիպակի զեկույցում"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Խնդրում ենք սպասել…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Սահեցրեք ձախ՝ սխալի հաշվետվությունը համօգտագործելու համար"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Հպեք՝ վրիպակի զեկույցը տրամադրելու համար"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական ​​և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Այս հաղորդագրությունը ցույց տալ հաջորդ անգամ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Վրիպակների հաշվետվություններ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"անանուն"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Մանրամասներ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Էկրանի պատկեր"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Էկրանի պատկերը հաջողությամբ ստացվեց:"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Էկրանի պատկերը հաջողությամբ ստացվեց:"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Վրիպակի զեկույցի մանրամասները"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցի մանրամասները"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Ֆայլի անունը"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Անվանումը"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Մանրամասն նկարագրություն"</string>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index e774de99ea3e..4416fc725b0b 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kerangka"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan bug sedang dibuat"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan bug tercatat"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Laporan bug <xliff:g id="ID">#%d</xliff:g> sedang dibuat"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Laporan bug <xliff:g id="ID">#%d</xliff:g> dijepret"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Menambahkan detail ke laporan bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Harap tunggu..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Gesek ke kiri untuk membagikan laporan bug Anda"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk membagikan laporan bug Anda"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ketuk untuk membagikan laporan bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Laporan bug berisi data dari berbagai file log sistem, termasuk informasi pribadi dan rahasia. Hanya bagikan laporan bug dengan aplikasi dan orang yang Anda percaya."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tampilkan pesan ini lain kali"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan bug"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"tanpa nama"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detail"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan layar"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan layar berhasil diambil."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Tangkapan layar berhasil diambil."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detail laporan bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detail laporan bug <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nama file"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Judul"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Deskripsi detail"</string>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index d175b4f95195..0d43719cd3c3 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Skipanalína"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Verið er að búa til villutilkynningu"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Villutilkynning útbúin"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Verið er að búa til villutilkynningu <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Villutilkynning <xliff:g id="ID">#%d</xliff:g> búin til"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Bætir upplýsingum við villutilkynningu"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Augnablik..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Strjúktu til vinstri til að deila villuskýrslunni"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Snertu til að deila villutilkynningunni"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ýttu til að deila villutilkynningunni"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Villutilkynningar innihalda gögn úr hinum ýmsu annálsskrám kerfisins, þ. á m. persónuleg gögn og trúnaðarupplýsingar. Deildu villutilkynningum eingöngu með forritum og fólki sem þú treystir."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Sýna þessi skilaboð næst"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Villutilkynningar"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"án heitis"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Nánar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjámynd"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tókst að taka skjámynd."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skjámynd tekin."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Upplýsingar um villutilkynningu"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Upplýsingar villutilkynningar <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Skráarheiti"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titill"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Ítarleg lýsing"</string>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index a954b0ca78f8..fc9383a2ca32 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generazione segnalazione di bug in corso"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Segnalazione di bug acquisita"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Scorri verso sinistra per condividere il rapporto sui bug"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tocca per condividere la segnalazione di bug"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Le segnalazioni di bug contengono dati da vari file di log del sistema, incluse informazioni personali e private. Condividi le segnalazioni di bug solo con app e persone attendibili."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra questo messaggio la prossima volta"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapporti sui bug"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"senza nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Dettagli"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot acquisito."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot acquisito."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Dettagli della segnalazione di bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Dettagli sulla segnalazione di bug <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome file"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titolo"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrizione dettagliata"</string>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 40bd73b4661d..335a2e80d882 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"מעטפת"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"מופק דוח על באג"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"דוח הבאגים צולם"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"יצירת הדוח על הבאג <xliff:g id="ID">#%d</xliff:g> מתבצעת"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"הדוח על הבאג <xliff:g id="ID">#%d</xliff:g> צולם"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"מוסיף פרטים לדוח על הבאג"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"המתן…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"החלק שמאלה כדי לשתף את דוח הבאגים"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"גע כדי לשתף את דוח הבאגים שלך"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"הקש כדי לשתף את הדוח על הבאג"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"דוחות על באגים כוללים נתונים מקובצי היומן השונים במערכת, כולל מידע אישי ופרטי. שתף דוחות באגים רק עם אפליקציות ואנשים שאתה סומך עליהם."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"הצג את ההודעה הזו בפעם הבאה"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"דוחות באגים"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ללא שם"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"פרטים"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"צילום מסך"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"צילום המסך בוצע בהצלחה."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"צילום המסך בוצע בהצלחה."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"פרטי דוח על באג"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"פרטי הדוח על הבאג <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"שם קובץ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"כותרת"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"תיאור מפורט"</string>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index f0183b5e9d82..b98b05fa1f19 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"シェル"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"バグレポートを生成しています"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"バグレポートが記録されました"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"バグレポート <xliff:g id="ID">#%d</xliff:g> の生成中"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"バグレポート <xliff:g id="ID">#%d</xliff:g> の記録完了"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"バグレポートに詳細情報を追加しています"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"お待ちください…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"バグレポートを共有するには左にスワイプ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"バグレポートを共有するにはタップします"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"バグレポートを共有するにはタップします"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"バグレポートには、個人の非公開情報など、システムのさまざまなログファイルのデータが含まれます。共有する場合は信頼するアプリとユーザーのみを選択してください。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"このメッセージを次回も表示する"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"バグレポート"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"名前なし"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"詳細"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"スクリーンショット"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"スクリーンショットを撮影しました。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"スクリーンショットを正常に撮影しました。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"バグレポートの詳細"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"バグレポート <xliff:g id="ID">#%d</xliff:g> の詳細"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ファイル名"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"タイトル"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"詳細説明"</string>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index a7ad694465ba..24d83a4b6230 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"გარეკანი"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გენერირება"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ანგარიში ხარვეზების შესახებ შექმნილია"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g> გენერირდება"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g> აღბეჭდილია"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ხარვეზის შესახებ ანგარიშს დეტალები ემატება"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"გთხოვთ, მოითმინოთ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"გაასრიალეთ მარცხნივ თქვენი ხარვეზის შეტყობინების გასაზიარებლად"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"შეეხეთ ხარვეზების შესახებ ანგარიშის გასაზიარებლად"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"შემდგომში აჩვენე ეს შეტყობინება"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"შეცდომების ანგარიშები"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"უსახელო"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"დეტალები"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ეკრანის ანაბეჭდი"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ეკრანის ანაბეჭდი გადაღებულია წარმატებით."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ეკრანის ანაბეჭდი გადაღებულია წარმატებით."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ხარვეზის შესახებ ანგარიშის დეტალები"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g>-ის დეტალები"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ფაილის სახელი"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"სათაური"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"დეტალური აღწერა"</string>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 25a387914daa..5878b17a7a5a 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Қабыршық"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Қате туралы есеп жасалып жатыр"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Вирус туралы баянат қабылданды"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жасалуда"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жазып алынды"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Қате туралы есепке мәліметтер қосылуда"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Күте тұрыңыз…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Қате туралы есепті бөлісу үшін солға жанаңыз"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Бөліс үшін, вирус туралы баянатты түртіңіз."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Қате туралы есепті бөлісу үшін түртіңіз"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Вирус туралы баянатта жүйеде тіркелген әртүрлі файлдар туралы деректер болады, оған жеке және құпия ақпарат та кіреді. Вирус баянаттарын сенімді қолданбалар және сенімді адамдармен ғана бөлісіңіз."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бұл хабарды келесі жолы көрсетіңіз"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Қате туралы баяндамалар"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"атаусыз"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Мәліметтер"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншот"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот сәтті түсірілді."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Скриншот сәтті түсірілді."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Қате туралы есептің мәліметтері"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі туралы мәліметтер"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файл атауы"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Атауы"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Егжей-тегжейлі сипаттама"</string>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 844c3177b9f6..9c95e9849efc 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"សែល"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"របាយការណ៍កំហុសកំពុងត្រូវបានបង្កើត"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"បាន​ចាប់​យក​របាយការណ៍​កំហុស"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសកំពុងត្រូវបានបង្កើត"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុសត្រូវបានថត"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"កំពុងបន្ថែមព័ត៌មានលម្អិតទៅរបាយការណ៍កំហុស"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"សូម​រង់ចាំ…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"អូស​ទៅ​ឆ្វេង​​ ដើម្បី​ចែក​រំលែក​របាយការណ៍​កំហុស​របស់​អ្នក"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ប៉ះ​ ដើម្បី​ចែក​រំលែក​របាយការណ៍​កំហុស​របស់​អ្នក"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ប៉ះដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍​កំហុស​រួមមាន​ឯកសារ​កំណត់​ហេតុ​ផ្សេងៗ​របស់​ប្រព័ន្ធ រួមមាន​ព័ត៌មាន​ផ្ទាល់ខ្លួន និង​ឯកជន។ ចែករំលែក​របាយការណ៍​កំហុស​ជា​មួយ​កម្មវិធី និង​មនុស្ស​ដែល​អ្នក​ទុក​ចិត្ត។"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"បង្ហាញ​សារ​នេះ​ពេល​ក្រោយ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"រាយការណ៍ពីកំហុស"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"គ្មានឈ្មោះ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ព័ត៌មានលម្អិត"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"រូបថតអេក្រង់"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"បានថតរូបថតអេក្រង់ដោយជោគជ័យ"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"រូបថតអេក្រង់ត្រូវបានថតដោយជោគជ័យ"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ព័ត៌មានលម្អិតពីរបាយការណ៍កំហុស"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ព័ត៌មានលម្អិតពី <xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុស"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ឈ្មោះ​ឯកសារ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ចំណងជើង"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ការពិពណ៌នាលម្អិត"</string>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index a3c9b95fecc0..ce6f3c05f4c4 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ಶೆಲ್"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ದೋಷ ವರದಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ದೋಷದ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ಅನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ಅನ್ನು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿಕೊಳ್ಳಲಾಗಿದೆ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ಬಗ್ ವರದಿಗೆ ವಿವರಗಳನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ದಯವಿಟ್ಟು ನಿರೀಕ್ಷಿಸಿ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ನಿಮ್ಮ ದೋಷ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಎಡಕ್ಕೆ ಸ್ವೈಪ್‌ ಮಾಡಿ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ನಿಮ್ಮ ದೋಷದ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ನಿಮ್ಮ ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ವೈಯಕ್ತಿಕ ಮತ್ತು ಖಾಸಗಿ ಮಾಹಿತಿಯು ಸೇರಿದಂತೆ, ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್‌ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ. ನೀವು ನಂಬುವಂತಹ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಜನರೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ಈ ಸಂದೇಶವನ್ನು ಮುಂದಿನ ಬಾರಿ ತೋರಿಸಿ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ದೋಷ ವರದಿಗಳು"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ಹೆಸರಿಸದಿರುವುದು"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ವಿವರಗಳು"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ಬಗ್ ವರದಿ ವಿವರಗಳು"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ವಿವರಗಳು"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ಫೈಲ್‌ಹೆಸರು"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ಶೀರ್ಷಿಕೆ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ವಿವರವಾದ ವಿವರಣೆ"</string>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 912d940a58ac..70df8e2efb36 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"셸"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"버그 신고 생성 중"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"버그 신고서 캡처됨"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 생성 중"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 캡처됨"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"세부정보를 버그 보고서에 추가"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"잠시 기다려 주세요..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"왼쪽으로 스와이프하여 버그 신고서를 공유하세요."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"버그 신고서를 공유하려면 터치하세요."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"버그 신고를 공유하려면 탭하세요."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"버그 신고서는 시스템의 다양한 로그 파일 데이터(예: 개인 및 비공개 정보)를 포함합니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"다음에 이 메시지 표시"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"버그 신고"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"이름 없음"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"세부정보"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"스크린샷"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"스크린샷을 찍었습니다."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"스크린샷을 찍었습니다."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"버그 신고 세부정보"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 세부정보"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"파일 이름"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"제목"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"자세한 설명"</string>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index 8ad785c98df5..49d8d8df0074 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Мүчүлүштүктөр тууралуу билдирүү түзүлүүдө"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Ката тууралуу билдирүү түзүлдү"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> түзүлүүдө"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> жаздырылды"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Мүчүлүштүк жөнүндө кабардын чоо-жайы кошулууда"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Күтө туруңуз…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ката жөнүндө кабар менен бөлүшүү үчүн солго серпип коюңуз"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Ката тууралуу билдирүүңүздү жөнөтүш үчүн, тийиңиз"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Мүчүлүштүк тууралуу билдирүүңүздү бөлүшүү үчүн таптап коюңуз"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Ката тууралуу билдирүүлөр системанын ар кандай лог файлдарынын берилиштерин камтыйт, аларга өздүк жана купуя маалыматтар дагы кирет. Ката тууралуу билдирүүлөрдү сиз ишенген колдонмолор жана адамдар менен гана бөлүшүңүз."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бул билдирүү кийин көрсөтүлсүн"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоолор"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"аталышы жок"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Чоо-жайы"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншот"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот ийгиликтүү тартылды."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Скриншот ийгиликтүү тартылды."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Мүчүлүштүк тууралуу билдирүүнүн <xliff:g id="ID">#%d</xliff:g> чоо-жайы"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файлдын аталышы"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Аталышы"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index d1592540b721..61b06c891a3a 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ກຳລັງສ້າງລາຍງານບັນຫາ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ລາຍງານຈຸດບົກພ່ອງຖືກເກັບກຳແລ້ວ"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ກຳລັງສ້າງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ບັນທຶກລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g> ແລ້ວ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ກຳລັງເພີ່ມລາຍລະອຽດໃສ່ລາຍງານຂໍ້ຜິດພາດ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ກະລຸນາລໍຖ້າ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"​ປັດ​ໄປ​ຊ້າຍ​ເພື່ອ​ສົ່ງ​ລາຍ​ງານ​ຂໍ້​ຜິດ​ພາດ​ຂອງ​ທ່ານ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ແຕະເພື່ອແບ່ງປັນລາຍງານຂໍ້ຜິດພາດຂອງທ່ານ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ສະແດງຂໍ້ຄວາມນີ້ອີກໃນເທື່ອຕໍ່ໄປ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ລາຍ​ງານ​ບັນ​ຫາ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ບໍ່ມີຊື່"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ລາຍລະອຽດ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ພາບໜ້າຈໍ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ຖ່າຍພາບໜ້າຈໍສຳເລັດແລ້ວ."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ຖ່າຍພາບໜ້າຈໍສຳເລັດແລ້ວ."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ລາຍ​ລະ​ອຽດ​ການລາຍງານບັນຫາ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ລາຍລະອຽດຂອງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ຊື່ໄຟລ໌"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ຊື່"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ຄຳອະທິບາຍແບບລະອຽດ"</string>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 0c069c681ec0..34182131f7a1 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Apvalkalas"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Pranešimas apie riktą generuojamas"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Riktų ataskaita užfiksuota"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) generuojamas"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Pranešimas apie riktą (<xliff:g id="ID">#%d</xliff:g>) užfiksuotas"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Pridedama informacijos prie pranešimo apie riktą"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Palaukite…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Perbraukite kairėn, kad bendrintumėte rikto ataskaitą"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Palieskite, kad bendrintumėte riktų ataskaitą"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Palieskite, kad bendrintumėte pranešimą apie riktą"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Riktų ataskaitose pateikiami duomenys iš įvairių sistemos žurnalo failų, įskaitant asmeninę ir privačią informaciją. Riktų ataskaitas bendrinkite tik su patikimomis programomis ir žmonėmis."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rodyti šį pranešimą kitą kartą"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Riktų ataskaitos"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"be pavadinimo"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Informacija"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrano kopija"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrano kopija sėkmingai padaryta."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekrano kopija sėkmingai sukurta."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Išsami pranešimo apie riktą informacija"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Išsami informacija apie pranešimą apie riktą (<xliff:g id="ID">#%d</xliff:g>)"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Failo pavadinimas"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Pavadinimas"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Išsamus aprašas"</string>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 1baa3435d776..61087164b577 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Aizsargs"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Notiek kļūdas pārskata izveide"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveidots kļūdu pārskats"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> tiek ģenerēts"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g> reģistrēts"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Informācijas pievienošana kļūdas pārskatam"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Lūdzu, uzgaidiet..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Velciet pa kreisi, lai kopīgotu savu kļūdu ziņojumu."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pieskarieties, lai kopīgotu kļūdu pārskatu."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Pieskarieties, lai kopīgotu kļūdas pārskatu."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Kļūdu pārskatā ir iekļauti dati no dažādiem sistēmas žurnālfailiem, tostarp personas dati un privāta informācija. Kļūdu pārskatus ieteicams kopīgot tikai ar uzticamām lietotnēm un lietotājiem."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rādīt šo ziņojumu nākamajā reizē"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Kļūdu ziņojumi"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez nosaukuma"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalizēta informācija"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrānuzņēmums"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrānuzņēmums ir veikts sekmīgi."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekrānuzņēmums ir veikts sekmīgi."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Kļūdas pārskata informācija"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g>: detalizēta informācija"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Faila nosaukums"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Nosaukums"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detalizēts apraksts"</string>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index efbec8ec7687..500196d10ff8 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Обвивка"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Се генерира извештајот за грешки"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештајот за грешка е снимен"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Се генерира извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештајот за грешки <xliff:g id="ID">#%d</xliff:g> е снимен"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Се додаваат детали на извештајот за грешка"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Почекајте..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Повлечете налево за да споделите пријава за грешка"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Допри да се сподели твојот извештај за грешка"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Допрете за да го споделите извештајот за грешки"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Извештаите за грешка содржат податоци од разни датотеки за евиденција на системот, вклучувајќи лични и приватни информации. Извештаите за грешка споделувајте ги само со апликации и луѓе на коишто им верувате."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ја поракава следниот пат"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаи за грешки"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"неименувани"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Слика од екранот"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Успешно е направена слика од екранот."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Успешно е направена слика од екранот."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали на извештајот за грешка"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детали за извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Име на датотека"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Детален опис"</string>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 82cfd6d9d911..696aab2ca79c 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ഷെൽ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ബഗ് റിപ്പോർട്ട് സൃഷ്ടിച്ചുകൊണ്ടിരിക്കുന്നു"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ബഗ് റിപ്പോർട്ട് ക്യാപ്‌ചർ ചെയ്‌തു"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> സൃഷ്ടിക്കുന്നു"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> ക്യാപ്ചർ ചെയ്തു"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ബഗ് റിപ്പോർട്ടിലേക്ക് വിശദാംശങ്ങൾ ചേർക്കുന്നു"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"കാത്തിരിക്കുക..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നതിന് ഇടത്തേയ്‌ക്ക് സ്വൈപ്പുചെയ്യുക"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ സ്‌പർശിക്കുക"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ ടാപ്പുചെയ്യുക"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"വ്യക്തിഗതവും സ്വകാര്യവുമായ വിവരങ്ങൾ ഉൾപ്പെടെ, സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള ഡാറ്റ, ബഗ് റിപ്പോർട്ടുകളിൽ അടങ്ങിയിരിക്കുന്നു. നിങ്ങൾ വിശ്വസിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ഈ സന്ദേശം അടുത്ത തവണ ദൃശ്യമാക്കുക"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ബഗ് റിപ്പോർട്ടുകൾ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"പേരില്ലാത്തവർ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"വിശദാംശങ്ങൾ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"സ്‌ക്രീൻഷോട്ട്"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ബഗ് റിപ്പോർട്ട് വിശദാംശങ്ങൾ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> വിശദാംശങ്ങൾ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ഫയല്‍നാമം"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"പേര്"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"വിശദമായ വിവരണം"</string>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 856803da4f7d..62d83cb67d3c 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Шел"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Алдааны тайланг үүсгэсэн"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Алдааны мэдээлэл хүлээн авав"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g> үүсгэгдэж байна"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g>-г бүртгэгдлээ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Алдааны тайланд дэлгэрэнгүй мэдээлэл нэмж байна"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Түр хүлээнэ үү..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Өөрийн согог репортыг хуваалцахын тулд зүүн шудрана уу"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Програмд гарсан алдааны мэдээллээ хуваалцах бол дарна уу"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Энэ мессежийг дараагийн удаа харуулах"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Гэмтлийн тухай тайлан"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"нэр байхгүй"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Дэлгэрэнгүй"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Дэлгэцийн зураг"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Дэлгэцийн зургийг амжилттай авлаа."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Дэлгэцийн зургийг амжилттай авлаа."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Алдааны дэлгэрэнгүй тайлан"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g>-ны дэлгэрэнгүй"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Файлын нэр"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Гарчиг"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Дэлгэрэнгүй тайлбар"</string>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index 763eec62a990..e6b2b045b950 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"दोष अहवाल तयार केला जात आहे"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"दोष अहवाल कॅप्‍चर केला"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> तयार केला जात आहे"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> कॅप्चर केला"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"दोष अहवालामध्‍ये तपशील जोडत आहे"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करा..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"आपला दोष अहवाल सामायिक करण्यासाठी डावीकडे स्वाइप करा"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"आपला दोष अहवाल सामायिक करण्‍यासाठी स्‍पर्श करा"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"आपला दोष अहवाल सामायिक करण्यासाठी टॅप करा"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"दोष अहवालांमध्‍ये वैयक्तिक आणि खाजगी माहितीसह, सिस्‍टमच्‍या अनेक लॉग फायलींमधील डेटा असतो. केवळ आपला विश्वास असलेल्‍या अ‍ॅप्‍स आणि लोकांसह दोष अहवाल सामायिक करा."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"पुढील वेळी हा संदेश दर्शवा"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"दोष अहवाल"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामित"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"तपशील"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रीनशॉट यशस्वीपणे घेतला."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"स्क्रीनशॉट यशस्वीरित्या घेतला."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"दोष अहवाल तपशील"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> तपशील"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फाईलनाव"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"तपशीलवार वर्णन"</string>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index 1afe430a96c0..1d04253e9522 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan pepijat sedang dijana"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Laporan pepijat <xliff:g id="ID">#%d</xliff:g> sedang dijana"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Laporan pepijat <xliff:g id="ID">#%d</xliff:g> telah ditangkap"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Menambahkan butiran pada laporan pepijat"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sila tunggu…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Leret ke kiri untuk berkongsi laporan pepijat anda"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ketik untuk berkongsi laporan pepijat anda"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan pepijat"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"tidak bernama"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Butiran"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan skrin"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan skrin berjaya diambil."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Tangkapan skrin berjaya diambil."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Butiran laporan pepijat"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Butiran laporan pepijat <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nama fail"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tajuk"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Perihalan terperinci"</string>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index e94111112a8c..f63c8c592dbe 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"အခွံ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ချွတ်ယွင်းမှု အစီရင်ခံစာကို ထုတ်ပေးနေသည်"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"အမှားအယွင်းမှတ်တမ်းကို အောင်မြင်စွာ သိမ်းဆည်းပြီး"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> ကိုထုတ်နေပါသည်"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> ကိုရယူထားပြီးပါပြီ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ချွတ်ယွင်းချက်အစီရင်ခံချက်သို့ အသေးစိတ်များပေါင်းထည့်ရန်"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ခေတ္တစောင့်ပါ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"သင်၏ ဘာဂ် အစီရင်ခံစာကို မျှပေးရန် ဘယ်ဘက်သို့ ပွတ်ဆွဲရန်"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"အမှားအယွင်း မှတ်တမ်းကို မျှဝေရန် ထိလိုက်ပါ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"သင့်ချွတ်ယွင်းမှုအစီရင်ခံချက်ကို မျှဝေရန် တို့ပါ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"အမှားအယွင်း မှတ်တမ်းမှာ ပါရှိသော အချက်အလက်များမှာ ကိုယ်ရေးကိုယ်တာ နဲ့ လုံခြုံရေး အချက်အလက်များပါဝင်သော စနစ်မှ ပြုလုပ်မှု မှတ်တမ်းများ ဖြစ်ပါသည်၊ အမှားအယွင်း မှတ်တမ်းများကို ယုံကြည်ရသော အပလီကေးရှင်းများနဲ့ လူများကိုသာ ပေးဝေပြသမှု လုပ်ပါရန်။"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ဤစာတန်းကို နောက်တစ်ခါတွင် ပြရန်"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ချို့ယွင်းမှု အစီရင်ခံစာများ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"အမည်မဲ့"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"အသေးစိတ်များ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံကို အောင်မြင်စွာ ရိုက်ပြီးပြီ။"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ဖန်သားပြင်ဓာတ်ပုံ အောင်မြင်စွာရိုက်ပြီးပါပြီ။"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ချွတ်ယွင်းချက်အစီရင်ခံစာ အသေးစိတ်များ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> အသေးစိတ်များ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ဖိုင်အမည်"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ခေါင်းစဉ်"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"အသေးစိတ် ဖော်ပြချက်"</string>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 87b3530c4210..328e8aef4928 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Feilrapporten blir generert"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Feilrapporten er lagret"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> blir generert"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> er fullført"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Legger til detaljer i feilrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent litt"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Sveip til venstre for å dele feilrapporten din"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Trykk for å dele feilrapporten din"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Trykk for å dele feilrapporten"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Feilrapporter inkluderer data fra systemets forskjellige loggfiler. Dette omfatter personlig og privat informasjon. Du bør bare dele feilrapporter med apper og folk du stoler på."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne meldingen neste gang"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Feilrapporter"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"uten navn"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detaljer"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skjermdumpen er tatt."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skjermdumpen er tatt."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detaljer om feilrapporten"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tittel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljert beskrivelse"</string>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 5b68ece1ec22..62bfeadef9ff 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"सेल"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"बग रिपोर्ट उत्पन्न भइरहेको छ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"बग प्रतिवेदन समातियो"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>लाई निकालिदैछ"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>लाई कैद गरियो"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्टमा विवरणहरू थप्दै"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा गर्नुहोला..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"तपाईँको बग रिपोर्ट साझेदारी गर्न बायाँ स्वाइप गर्नुहोस्"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"तपाईंको बग रिपोर्ट साझेदारी गर्न छुनुहोस्"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"तपाईंको बग रिपोर्टलाई साझेदारी गर्न ट्याप गर्नुहोस्"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्टहरूमा प्रणालीका विभिन्न लग फाइलहरूबाट व्यक्तिगत तथा नीजि सूचनासहितको डेटा रहन्छ। बग रिपोर्टहरू अनुप्रयोगहरू र तपाईँले विश्वास गरेका व्यक्तिहरूसँग मात्र साझेदारी गर्नुहोस्।"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यो सन्देश अर्को पटक देखाउनुहोस्"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"(नामविहीन)"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रिनशट"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रिनशट सफलतापूर्वक लिइयो।"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"स्क्रिनशट सफलतापूर्वक लिइयो।"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्टको विवरण"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>का विवरणहरू"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फाइलको नाम"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत विवरण"</string>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index dd67ccd05529..2f4b215f7a76 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bugrapport wordt gegenereerd"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutenrapport vastgelegd"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Bugrapport <xliff:g id="ID">#%d</xliff:g> wordt gegenereerd"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Bugrapport <xliff:g id="ID">#%d</xliff:g> is vastgelegd"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Details toevoegen aan het bugrapport"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Even geduld…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veeg naar links om je bugmelding te delen"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak aan om je foutenrapport te delen"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tik om je bugrapport te delen"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Foutenrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, waaronder persoonlijke en privégegevens. Deel foutenrapporten alleen met apps en mensen die u vertrouwt."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Dit bericht de volgende keer weergeven"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot is gemaakt."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot is gemaakt."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details van bugrapport"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details van bugrapport <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Bestandsnaam"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beschrijving"</string>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index 96addbf037f6..dc2277f58c79 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ਸ਼ੈਲ"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ਬੱਗ ਰਿਪੋਰਟ ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"ਬਗ ਰਿਪੋਰਟ ਕੈਪਚਰ ਕੀਤੀ"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਕੈਪਚਰ ਕੀਤੀ ਗਈ"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"ਬੱਗ ਰਿਪੋਰਟ ਵਿੱਚ ਵੇਰਵਿਆਂ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ਤੁਹਾਡੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਖੱਬੇ ਪਾਸੇ ਸਵਾਈਪ ਕਰੋ"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ਆਪਣੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਛੋਹਵੋ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ਆਪਣੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ਬਗ ਰਿਪੋਰਟਾਂ ਵਿੱਚ ਸਿਸਟਮ ਦੀਆਂ ਭਿੰਨ ਲੌਗ ਫਾਈਲਾਂ ਦਾ ਡਾਟਾ ਹੁੰਦਾ ਹੈ, ਨਿੱਜੀ ਅਤੇ ਪ੍ਰਾਈਵੇਟ ਜਾਣਕਾਰੀ ਸਮੇਤ। ਕੇਵਲ ਉਹਨਾਂ ਐਪਸ ਅਤੇ ਲੋਕਾਂ ਨਾਲ ਬਗ ਰਿਪੋਰਟਾਂ ਸ਼ੇਅਰ ਕਰੋ, ਜਿਹਨਾਂ ਤੇ ਤੁਸੀਂ ਭਰੋਸਾ ਕਰਦੇ ਹੋ।"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ਅਗਲੀ ਵਾਰ ਇਹ ਸੁਨੇਹਾ ਦਿਖਾਓ"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"ਬਗ ਰਿਪੋਰਟਾਂ"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ਬਿਨਾਂ-ਨਾਮ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"ਵੇਰਵੇ"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਫਲਤਾਪੂਰਵਕ ਲਿਆ ਗਿਆ।"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਫਲਤਾਪੂਰਵਕ ਲਿਆ ਗਿਆ।"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ਬੱਗ ਰਿਪੋਰਟ ਵੇਰਵੇ"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਵੇਰਵੇ"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ਫ਼ਾਈਲ ਨਾਮ"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ਸਿਰਲੇਖ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"ਵਿਸਥਾਰ ਸਹਿਤ ਵਰਣਨ"</string>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 7a67ac686286..c58556803847 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Powłoka"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Trwa generowanie raportu o błędzie"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Raport o błędach został zapisany"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generuję raport o błędzie <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Raport o błędzie <xliff:g id="ID">#%d</xliff:g> został zapisany"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaję szczegóły do raportu o błędzie"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Czekaj..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Przesuń palcem w lewo, by udostępnić swoje zgłoszenie błędu"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Kliknij, by udostępnić raport o błędzie"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Raporty o błędach zawierają dane z różnych plików dzienników systemu, w tym dane osobowe i prywatne. Udostępniaj je tylko aplikacjom i osobom, którym ufasz."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaż ten komunikat następnym razem"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Raporty o błędach"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez nazwy"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Szczegóły"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Zrzut ekranu"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zrobiono zrzut ekranu."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Zrzut ekranu został zrobiony."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Szczegóły zgłoszenia błędu"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Szczegóły raportu o błędzie <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nazwa pliku"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tytuł"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Szczegółowy opis"</string>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index 471e959c9488..fc6e21c28cb0 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Um relatório do bug está sendo gerado"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"O relatório do bug <xliff:g id="ID">#%d</xliff:g> está sendo gerado"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Relatório do bug <xliff:g id="ID">#%d</xliff:g> capturado"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adicionando detalhes ao relatório do bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toque para compartilhar seu relatório do bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Captura de tela concluída."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório do bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index ed78f55a1211..252edb180cd5 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"O relatório de erro está a ser criado"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de erros capturado"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"O relatório de erro <xliff:g id="ID">#%d</xliff:g> está a ser criado"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Relatório de erro <xliff:g id="ID">#%d</xliff:g> criado"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"A adicionar detalhes ao relatório de erro"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslizar rapidamente para a esquerda para partilhar o seu relatório de erros"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para partilhar o relatório de erros"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toque para partilhar o relatório de erro"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de erros incluem dados de vários ficheiros de registo do sistema, nomeadamente informações pessoais e privadas. Partilhe relatórios de erros apenas com aplicações e pessoas fidedignas."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de erros"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de ecrã"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecrã tirada com êxito."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Captura de ecrã tirada com êxito."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível tirar a captura de ecrã."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório de erro"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de erro <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index 471e959c9488..fc6e21c28cb0 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Um relatório do bug está sendo gerado"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"O relatório do bug <xliff:g id="ID">#%d</xliff:g> está sendo gerado"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Relatório do bug <xliff:g id="ID">#%d</xliff:g> capturado"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Adicionando detalhes ao relatório do bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Aguarde…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslize para a esquerda para compartilhar seu relatório de bugs"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Toque para compartilhar seu relatório do bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Captura de tela concluída."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório do bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index af67bc6d5209..d720417788a9 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Se generează raportul de eroare"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Raportul despre erori a fost creat"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Raportul de eroare <xliff:g id="ID">#%d</xliff:g> se generează"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Raportul de eroare <xliff:g id="ID">#%d</xliff:g> a fost creat"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Se adaugă detaliile la raportul de eroare"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Așteptați…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Glisați la stânga pentru a trimite raportul de erori"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Atingeți pentru a permite accesul la raportul despre erori"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Atingeți pentru a trimite raportul de eroare"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Rapoartele despre erori conțin date din diferite fișiere de jurnal ale sistemului, inclusiv informații private și personale. Permiteți accesul la rapoartele despre erori numai aplicațiilor și persoanelor în care aveți încredere."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afișați acest mesaj data viitoare"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapoarte de erori"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"fără nume"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detalii"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captură de ecran"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecran a fost făcută."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Captura de ecran a fost făcută."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalii privind raportul de eroare"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaliile raportului de eroare <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Numele fișierului"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titlu"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Descriere detaliată"</string>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index a5e2bd2807ab..ed5ecafd09ee 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Оболочка"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Создание отчета об ошибке…"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчет об ошибке сохранен"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Создание отчета об ошибке <xliff:g id="ID">#%d</xliff:g>…"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Отчет об ошибке <xliff:g id="ID">#%d</xliff:g> сохранен"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Добавление данных в отчет об ошибке"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Подождите…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведите влево, чтобы отправить отчет"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Нажмите, чтобы отправить отчет об ошибках"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Нажмите, чтобы отправить отчет об ошибке."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчеты об ошибках содержат данные различных системных журналов и могут включать личную информацию. Рекомендуем открывать к ним доступ только лицам и приложениям, заслуживающим доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показать это сообщение в следующий раз"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Отчеты об ошибках"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"без названия"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншоты"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот готов"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Скриншот сделан"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали отчета об ошибке"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Данные отчета об ошибке <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Название файла"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Название"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Подробное описание"</string>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index 866c0f7c788f..cd8fba36e692 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ෂෙල්"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"දෝෂ වාර්තාවක් ජනනය කරමින් පවතී"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"දෝෂ වාර්තාව ලබාගන්නා ලදි"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> ජනනය කරමින් පවතී"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> ග්‍රහණය කර ගන්නා ලදී"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"දෝෂ වාර්තාව වෙත විස්තර එක් කිරීම"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"කරුණාකර රැඳී සිටින්න..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"ඔබගේ දෝෂ වාර්තාව බෙදාගැනීමට වමට ස්වයිප් කරන්න"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට ස්පර්ශ කරන්න"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට තට්ටු කරන්න"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"පුද්ගලික සහ පෞද්ගලික තොරතුරු ඇතුළත්ව පද්ධතියේ විවිධ ලොග් ගොනු වල දත්ත දෝෂ වාර්තාවේ අඩංගු වේ. ඔබට විශ්වාසවන්ත යෙදුම් සහ පුද්ගලයින් සමඟ පමණක් දෝෂ වාර්තා බෙදා ගන්න."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ඊළඟ වෙලාවේ මෙම පණිවිඩය පෙන්වන්න"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"දෝෂ වාර්තා"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"නම් නොකළ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"විස්තර"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"තිර රුව"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"සාර්ථකව තිර රුවක් ගන්නා ලදී."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"සාර්ථකව තිර රුවක් ගන්නා ලදී."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"දෝෂ වාර්තා විස්තර"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> විස්තර"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ගොනුවේ නම"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"මාතෘකාව"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"සවිස්තර විස්තරය"</string>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index f207480ec552..23e67f5a1fab 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generuje sa hlásenie chyby"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generuje sa hlásenie chyby <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Hlásenie chyby <xliff:g id="ID">#%d</xliff:g> bolo zaznamenané"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Pridanie podrobností o hlásení chyby"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Čakajte prosím…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ak chcete hlásenie o chybe zdieľať, prejdite prstom doľava."</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hlásenie chyby môžete zdieľať klepnutím"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímka obrazovky"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímka obrazovky bola zaznamenaná."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Snímka obrazovky bola úspešne zaznamenaná."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti hlásenia chyby"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti hlásenia chyby <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Názov súboru"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Názov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index c249961eba4e..519f3f22a721 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Lupina"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Poročilo o napakah se pripravlja"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Poročilo o napaki je posneto"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> je v izdelavi"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> zajeto"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodajanje podrobnosti v poročilo o napakah"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Počakajte ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Povlecite v levo, če želite poslati sporočilo o napaki"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dotaknite se, če želite deliti sporočilo o napaki z drugimi"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dotaknite se, če želite poročilo o napaki dati v skupno rabo"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Poročila o napakah vsebujejo podatke iz različnih dnevniških datotek sistema, vključno z osebnimi in zasebnimi podatki. Poročila o napakah delite samo z aplikacijami in ljudmi, ki jim zaupate."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži to sporočilo naslednjič"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Poročila o napakah"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Posnetek zaslona"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Posnetek zaslon je bil uspešno ustvarjen."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Posnetek zaslona je bil uspešno ustvarjen."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti o poročilu o napakah"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti poročila o napaki <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Ime datoteke"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Podroben opis"</string>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index 8a306b333ca9..5e3c70695900 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Guaska"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Po krijohet raporti i defekteve në kod"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Raporti i defektit në kod u regjistrua"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> po krijohet"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Raporti i defekteve në kod <xliff:g id="ID">#%d</xliff:g> u regjistrua"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Po shtohen detajet te raporti i defekteve në kod"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Qëndro në pritje..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Rrëshqit majtas për të ndarë raportin e defektit në kod"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Prek për të ndarë raportin e defektit në kod"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Trokit për të ndarë raportin e defekteve në kod"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Raportet e gabimeve përmbajnë të dhëna nga skedarë të ndryshëm ditarësh sistemi, përfshi informacione personale dhe private. Shpërndaji publikisht raportet e gabimeve vetëm me aplikacionet dhe personat që iu beson."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tregoje këtë mesazh herën tjetër"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Raportet e gabimeve"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"e paemërtuar"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Detajet"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pamja e ekranit"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Pamja e ekranit u realizua me sukses."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Pamja e ekranit u regjistrua me sukses."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detajet e raportimit të gabimeve në kod"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detajet e raportit të defekteve në kod <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Emri i skedarit"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Titulli"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Përshkrimi i detajuar"</string>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 9bff65cd727c..55119b633080 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Извештај о грешци се генерише"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештај о грешци је снимљен"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> се генерише"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештај о грешци <xliff:g id="ID">#%d</xliff:g> је снимљен"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Додају се детаљи у извештај о грешци"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Сачекајте..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Превуците улево да бисте делили извештај о грешкама"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Додирните да бисте делили извештај о грешци"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Додирните да бисте делили извештај о грешци"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Извештаји о грешкама садрже податке из различитих системских датотека евиденције, укључујући личне и приватне податке. Делите извештаје о грешкама само са апликацијама и људима у које имате поверења."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ову поруку следећи пут"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаји о грешкама"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"неименовано"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Детаљи"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Снимци екрана"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Снимање екрана је успело."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Снимак екрана је направљен."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детаљи извештаја о грешци"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детаљи извештаја о грешци <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Назив датотеке"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Детаљни опис"</string>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index fb962bfbf863..085f57e72817 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Skal"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Felrapporten genereras"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Felrapporten har skapats"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Felrapporten <xliff:g id="ID">#%d</xliff:g> genereras"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Felrapporten <xliff:g id="ID">#%d</xliff:g> har skapats"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Lägger till information i felrapporten"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vänta …"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Svep åt vänster om du vill dela felrapporten"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryck om du vill dela felrapporten"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tryck om du vill dela felrapporten"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Felrapporter innehåller data från systemets olika loggfiler, inklusive personliga och privata uppgifter. Dela bara felrapporter med personer du litar på."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Visa det här meddelandet nästa gång"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Felrapporter"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"namnlös"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Information"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skärmdump"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"En skärmdump har tagits."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skärmdump har tagits."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Information för felrapporten"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Information för felrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filnamn"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Namn"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detaljerad beskrivning"</string>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index de464148fe32..c5a8ef1f6b5e 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Ganda"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Inatayarisha ripoti ya hitilafu"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Ripoti ya hitilafu imenaswa"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g> inatayarishwa"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g> imerekodiwa"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Inaongeza maelezo kwenye ripoti ya hitilafu"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Tafadhali subiri…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Telezesha kidole kushoto ili ushiriki ripoti yako ya hitilafu"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Gusa ili ushiriki ripoti yako ya hitilafu"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Gonga ili ushiriki ripoti yako ya hitilafu"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Ripoti ya hitilafu ina data kutoka kwenye faili za kumbukumbu mbalimbali za mfumo, pamoja na maelezo ya kibinafsi na faragha. Shiriki ripoti ya hitilafu na programu na watu unaowaamini pekee."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Onyesha ujumbe huu wakati mwingine"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Ripoti za hitilafu"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"Isiyo na jina"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Maelezo"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Picha ya skrini"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Imepiga picha ya skrini."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Imepiga picha ya skrini."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Maelezo kuhusu ripoti ya hitilafu"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Maelezo ya ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Jina la faili"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Kichwa"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Maelezo ya kina"</string>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 15c7014ab5dc..7ef89e27cf03 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"ஷெல்"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"பிழை அறிக்கை உருவாக்கப்படுகிறது"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"பிழை அறிக்கைகள் படமெடுக்கப்பட்டன"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> உருவாக்கப்படுகிறது"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> எடுக்கப்பட்டது"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"பிழை அறிக்கையில் விவரங்களைச் சேர்க்கிறது"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"காத்திருக்கவும்…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"பிழை அறிக்கையைப் பகிர இடது புறமாகத் தேய்க்கவும்"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"உங்கள் பிழை அறிக்கையைப் பகிர, தொடவும்"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"பிழை அறிக்கையைப் பகிர, தட்டவும்"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"பிழை அறிக்கைகளில், சொந்த வாழ்க்கை மற்றும் தனிப்பட்ட தகவல் உள்பட கணினியின் பல்வேறு பதிவுகளில் உள்ள தரவு இருக்கும். நீங்கள் நம்பும் பயன்பாடுகள் மற்றும் நபர்களுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"இந்தச் செய்தியை அடுத்த முறைக் காட்டு"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"பிழை அறிக்கைகள்"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"பெயரிடப்படாதது"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"விவரங்கள்"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ஸ்கிரீன் ஷாட்"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"பிழை அறிக்கை விவரங்கள்"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> இன் விவரங்கள்"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"கோப்புப்பெயர்"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"தலைப்பு"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"விரிவான விளக்கம்"</string>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index c84ec9a64342..6ba816b19646 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"షెల్"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"బగ్ నివేదిక ఉత్పాదించబడుతోంది"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"బగ్ నివేదిక క్యాప్చర్ చేయబడింది"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ నివేదికకు వివరాలను జోడిస్తోంది"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"దయచేసి వేచి ఉండండి..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎడమవైపుకు స్వైప్ చేయండి"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి తాకండి"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి నొక్కండి"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"బగ్ నివేదికలు వ్యక్తిగతమైన మరియు రహస్యమైన సమాచారంతో సహా సిస్టమ్ యొక్క విభిన్న లాగ్ ఫైల్‌ల్లోని డేటాను కలిగి ఉంటాయి. కనుక బగ్ నివేదికలను మీరు విశ్వసించే అనువర్తనాలు మరియు వ్యక్తులతో మాత్రమే భాగస్వామ్యం చేయండి."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"తదుపరిసారి ఈ సందేశాన్ని చూపు"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ నివేదికలు"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"పేరు లేనివి"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"వివరాలు"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"స్క్రీన్‌షాట్"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"స్క్రీన్‌షాట్ విజయవంతంగా తీయబడింది."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"స్క్రీన్‌షాట్ విజయవంతంగా తీయబడింది."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"బగ్ నివేదిక వివరాలు"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"శీర్షిక"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"సమగ్ర వివరణ"</string>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index f29978e81bae..d68ca2665718 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"กำลังสร้างรายงานข้อบกพร่อง"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"จับภาพรายงานข้อบกพร่องแล้ว"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"กำลังสร้างรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"บันทึกรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g> แล้ว"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"กำลังเพิ่มรายละเอียดในรายงานข้อบกพร่อง"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"โปรดรอสักครู่…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"กวาดไปทางซ้ายเพื่อแชร์รายงานข้อบกพร่อง"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"รายงานข้อบกพร่องมีข้อมูลจากไฟล์บันทึกต่างๆ ของระบบ รวมถึงข้อมูลส่วนตัว แชร์รายงานข้อบกพร่องกับแอปและบุคคลที่คุณไว้ใจเท่านั้น"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"แสดงข้อความนี้ในครั้งต่อไป"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"รายงานข้อบกพร่อง"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"ไม่มีชื่อ"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"รายละเอียด"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"ภาพหน้าจอ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"จับภาพหน้าจอสำเร็จแล้ว"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"จับภาพหน้าจอสำเร็จแล้ว"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"รายละเอียดรายงานข้อบกพร่อง"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"รายละเอียดรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"ชื่อไฟล์"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"ชื่อ"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"คำอธิบายโดยละเอียด"</string>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index c12191a1e849..432eb9053806 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Binubuo na ang ulat ng bug"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Na-capture ang ulat ng bug"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Binubuo na ang ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Na-capture ang ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Pagdaragdag ng mga detalye sa ulat ng bug"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Mangyaring maghintay..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Mag-swipe pakaliwa upang ibahagi ang iyong ulat ng bug"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pindutin upang ibahagi ang iyong ulat ng bug"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Mag-tap upang ibahagi ang iyong ulat ng bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Naglalaman ang mga ulat ng bug ng data mula sa iba\'t ibang file ng log ng system, kabilang ang personal at pribadong impormasyon. Magbahagi lang ng mga ulat ng bug sa apps at mga tao na pinagkakatiwalaan mo."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ipakita ang mensaheng ito sa susunod"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Mga ulat sa bug"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"walang pangalan"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Mga Detalye"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Nakunan ng screenshot."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Matagumpay na nakakuha ng screenshot."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Mga detalye ng ulat ng bug"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Mga detalye ng ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Pamagat"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Detalyadong paglalarawan"</string>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index 3f562d7d9416..dae377f0b297 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Kabuk"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Hata raporu oluşturuluyor"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Hata raporu kaydedildi"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) oluşturuluyor"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) yakalandı"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Hata raporuna ayrıntılar ekleniyor"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Lütfen bekleyin…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Hata raporunuzu paylaşmak için hızlıca sola kaydırın"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Hata raporunuzu paylaşmak için hafifçe dokunun"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu iletiyi göster"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hata raporları"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Ayrıntılar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekran görüntüsü"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekran görüntüsü başarıyla alındı."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Ekran görüntüsü başarıyla alındı."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hata raporu ayrıntıları"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) ayrıntıları"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Dosya adı"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Başlık"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Ayrıntılı açıklama"</string>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index 93e65110868d..02eeb2f8a286 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Оболонка"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Генерується повідомлення про помилку"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Звіт про помилки створено"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Генерується повідомлення про помилку <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Повідомлення про помилку <xliff:g id="ID">#%d</xliff:g> створено"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Додаються деталі до повідомлення про помилку"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Зачекайте…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведіть пальцем ліворуч, щоб надіслати звіт про помилки"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Торкніться, щоб надіслати звіт про помилки"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Торкніться, щоб надіслати повідомлення про помилку"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Звіти про помилки містять дані з різних файлів журналу системи, зокрема особисті та конфіденційні. Надсилайте звіт про помилки лише тим, кому довіряєте."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показати це повідомлення наступного разу"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Звіти про помилки"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"без назви"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Деталі"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Знімок екрана"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Знімок екрана зроблено."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Знімок екрана зроблено."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Деталі повідомлення про помилку"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Деталі повідомлення про помилку <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Назва файлу"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Назва"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Детальний опис"</string>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 52a45a033b28..23cada628b8c 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"شیل"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"بگ رپورٹ تخلیق ہو رہی ہے"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"بَگ رپورٹ کیپچر کر لی گئی"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> تخلیق ہو رہی ہے"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کیپچر ہو گئی"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"بگ رپورٹ میں تفصیلات شامل کی جا رہی ہیں"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"براہ کرم انتظار کریں…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"اپنی بگ رپورٹ کا اشتراک کرنے کیلئے بائیں سوائپ کریں"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"اپنی بَگ رپورٹ کا اشتراک کرنے کیلئے ٹچ کریں"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"اپنی بگ رپورٹ کا اشتراک کرنے کیلئے تھپتھپائیں"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"بَگ رپورٹس میں سسٹم کی مختلف لاگ فائلوں سے ڈیٹا شامل ہوتا ہے، بشمول ذاتی اور نجی معلومات۔ بَگ رپورٹس کا اشتراک صرف اپنے بھروسے مند ایپس اور لوگوں کے ساتھ کریں۔"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"یہ پیغام اگلی بار دکھائیں"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"بگ رپورٹس"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"بغیر نام"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"تفصیلات"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"اسکرین شاٹ"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"اسکرین شاٹ کامیابی سے لے لیا گیا۔"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"اسکرین شاٹ کامیابی سے لے لیا گیا۔"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"بگ رپورٹ کی تفصیلات"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کی تفصیلات"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"فائل کا نام"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"تفصیلی وضاحت"</string>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index 56e096577721..39703a20bcf7 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Terminal"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Xatoliklar hisoboti tayyorlanmoqda"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Xatolik hisobotini yozib olindi"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tayyorlanmoqda"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) yozib olindi"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Xatoliklar hisobotiga tafsilotlar qo‘shilmoqda"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Iltimos, kuting…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Xatolik hisobotini yuborish uchun barmog‘ingiz bilan chapga suring"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xatolik hisobotini bo‘lishish uchun barmog‘ingizni tegizing."</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Xatoliklar hisobotini ulashish uchun bosing"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Xatolik hisobotlari tizimdagi har xil jurnal fayllardagi ma’lumotlarni, shuningdek, shaxsiy hamda maxfiy ma’lumotlarni o‘z ichiga oladi. Xatolik hisobotlarini faqat ishonchli dasturlar va odamlar bilan bo‘lishing."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ushbu xabar keyingi safar ko‘rsatilsin"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Xatoliklar hisoboti"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"nomsiz"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Tafsilotlar"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skrinshot"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skrinshot tayyor."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skrinshot tayyor."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Xatoliklar hisoboti tafsilotlari"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tafsilotlari"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Fayl nomi"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Nomi"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Batafsil ta’rif"</string>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 2642b89ff034..16ffaffdf1cb 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Báo cáo lỗi đang được tạo"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Báo cáo lỗi đã được chụp"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Báo cáo lỗi <xliff:g id="ID">#%d</xliff:g> đang được tạo"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Đã chụp báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Đang thêm thông tin chi tiết vào báo cáo lỗi"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Vui lòng đợi…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Vuốt sang trái để chia sẻ báo cáo lỗi của bạn"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chạm để chia sẻ báo cáo lỗi của bạn"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Nhấn để chia sẻ báo cáo lỗi của bạn"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Các báo cáo lỗi chứa dữ liệu từ nhiều tệp nhật ký khác nhau của hệ thống, bao gồm cả thông tin cá nhân và riêng tư. Chỉ chia sẻ báo cáo lỗi với các ứng dụng và những người mà bạn tin tưởng."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Hiển thị thông báo này vào lần tới"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Báo cáo lỗi"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"chưa được đặt tên"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Chi tiết"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ảnh chụp màn hình"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Đã chụp ảnh màn hình thành công."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Đã chụp ảnh màn hình thành công."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Không thể chụp ảnh màn hình."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Chi tiết báo cáo lỗi"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Chi tiết báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Tên tệp"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Tiêu đề"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Mô tả chi tiết"</string>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index c933961d7871..382478eaf3e4 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在生成错误报告"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"已抓取错误报告"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在生成错误报告 <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"已捕获错误报告 <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"正在向错误报告添加详细信息"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"请稍候…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑动即可分享错误报告"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"触摸即可分享您的错误报告"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"点按即可分享您的错误报告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"错误报告包含的数据来自于系统的各个日志文件,其中包含个人信息和隐私信息。请务必只与您信任的应用和用户分享错误报告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再显示这条讯息"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"错误报告"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"详细信息"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"屏幕截图"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"已成功截图。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"已成功截图。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"错误报告详细信息"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"错误报告 <xliff:g id="ID">#%d</xliff:g> 详情"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"文件名"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"标题"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"详细说明"</string>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 7a35eef8980d..04b5e4854de3 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"命令介面"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在產生錯誤報告"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在產生錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"正在新增錯誤報告詳細資訊"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"請稍候…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"輕按即可分享錯誤報告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和使用者分享錯誤報告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再顯示這則訊息"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"詳細資訊"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"螢幕擷取畫面"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"成功拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"成功拍攝螢幕擷取畫面。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳情"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳情"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index ec66878a7237..7a1ab77622a7 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"殼層"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在產生錯誤報告"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"正在產生錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"已擷取錯誤報告 <xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"正在新增錯誤報告詳細資訊"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"請稍候…"</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"向左滑動即可分享錯誤報告"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"輕按即可分享錯誤報告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告的資料來自系統各個紀錄檔,包括個人和私密資訊。請務必只與您信任的應用程式和使用者分享錯誤報告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次仍顯示這則訊息"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"詳細資料"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"螢幕擷取畫面"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"已成功拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"已成功拍攝螢幕擷取畫面。"</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳細資料"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳細資料"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index c2642244f481..29b7dd8329bc 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"I-Shell"</string>
- <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Kukhiqizwa umbiko wesiphazamisi"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Umbiko wesiphazamisi uthwetshuliwe"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Umbiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g> uyacutshungulwa"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Umbiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g> uthwetshuliwe"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Ingeza imininingwane kumbiko wesiphazamisi"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sicela ulinde..."</string>
<string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Swayiphela kwesokunxele ukuze wabelane umbiko wesiphazamiso sakho"</string>
- <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Thinta ukuze wabelane ngombiko wakho wesiphazamisi"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Thepha ukuze wabelane ngombiko wakho wesiphazamisi"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Imibiko yeziphazamisi iqukethe idatha yamafayela wokungena ahlukile wesistimu, afaka ulwazi lomuntu siqu noma lobumfihlo. Yabelana kuphela ngemibiko yeziphazamisi nezinhlelo zokusebenza nabantu obathembayo."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bonisa lo mlayezo ngesikhathi esilandelayo"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Imibiko yeziphazamiso"</string>
@@ -30,9 +30,9 @@
<string name="bugreport_unnamed" msgid="2800582406842092709">"awunikiwe igama"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"Imininingwane"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"Isithombe-skrini"</string>
- <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Isithombe-skrini sithathwe ngempumelelo."</string>
+ <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Isithombe-skrini sithathwe ngempumelelo."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
- <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Imininingwane yombiko wesiphazamisi"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Imininingwane yombiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g>"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"Igama lefayela"</string>
<string name="bugreport_info_title" msgid="5599558206004371052">"Isihloko"</string>
<string name="bugreport_info_description" msgid="4117088998733546784">"Incazelo enemininingwane"</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 8c555a655bef..36097a124ff9 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -41,6 +41,8 @@ import java.util.zip.ZipOutputStream;
import libcore.io.Streams;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.google.android.collect.Lists;
import android.accounts.Account;
@@ -88,8 +90,8 @@ import android.widget.Toast;
* <p>
* The workflow is:
* <ol>
- * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with its pid and the
- * estimated total effort.
+ * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with a sequential id,
+ * its pid, and the estimated total effort.
* <li>{@link BugreportReceiver} receives the intent and delegates it to this service.
* <li>Upon start, this service:
* <ol>
@@ -132,6 +134,7 @@ public class BugreportProgressService extends Service {
static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+ static final String EXTRA_ID = "android.intent.extra.ID";
static final String EXTRA_PID = "android.intent.extra.PID";
static final String EXTRA_MAX = "android.intent.extra.MAX";
static final String EXTRA_NAME = "android.intent.extra.NAME";
@@ -146,6 +149,9 @@ public class BugreportProgressService extends Service {
private static final int MSG_SCREENSHOT_REQUEST = 4;
private static final int MSG_SCREENSHOT_RESPONSE = 5;
+ // Passed to Message.obtain() when msg.arg2 is not used.
+ private static final int UNUSED_ARG2 = -2;
+
/**
* Delay before a screenshot is taken.
* <p>
@@ -157,7 +163,7 @@ public class BugreportProgressService extends Service {
static final long POLLING_FREQUENCY = 2 * DateUtils.SECOND_IN_MILLIS;
/** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */
- private static final long INACTIVITY_TIMEOUT = 3 * DateUtils.MINUTE_IN_MILLIS;
+ private static final long INACTIVITY_TIMEOUT = 10 * DateUtils.MINUTE_IN_MILLIS;
/** System properties used for monitoring progress. */
private static final String DUMPSTATE_PREFIX = "dumpstate.";
@@ -177,7 +183,7 @@ public class BugreportProgressService extends Service {
*/
private static final String SCREENSHOT_DIR = "bugreports";
- /** Managed dumpstate processes (keyed by pid) */
+ /** Managed dumpstate processes (keyed by id) */
private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
private Context mContext;
@@ -222,7 +228,7 @@ public class BugreportProgressService extends Service {
}
// If service is killed it cannot be recreated because it would not know which
- // dumpstate PIDs it would have to watch.
+ // dumpstate IDs it would have to watch.
return START_NOT_STICKY;
}
@@ -299,38 +305,40 @@ public class BugreportProgressService extends Service {
}
final String action = intent.getAction();
final int pid = intent.getIntExtra(EXTRA_PID, 0);
+ final int id = intent.getIntExtra(EXTRA_ID, 0);
final int max = intent.getIntExtra(EXTRA_MAX, -1);
final String name = intent.getStringExtra(EXTRA_NAME);
- if (DEBUG) Log.v(TAG, "action: " + action + ", name: " + name + ", pid: " + pid
- + ", max: "+ max);
+ if (DEBUG)
+ Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id + ", pid: "
+ + pid + ", max: " + max);
switch (action) {
case INTENT_BUGREPORT_STARTED:
- if (!startProgress(name, pid, max)) {
+ if (!startProgress(name, id, pid, max)) {
stopSelfWhenDone();
return;
}
poll();
break;
case INTENT_BUGREPORT_FINISHED:
- if (pid == 0) {
+ if (id == 0) {
// Shouldn't happen, unless BUGREPORT_FINISHED is received from a legacy,
// out-of-sync dumpstate process.
- Log.w(TAG, "Missing " + EXTRA_PID + " on intent " + intent);
+ Log.w(TAG, "Missing " + EXTRA_ID + " on intent " + intent);
}
- onBugreportFinished(pid, intent);
+ onBugreportFinished(id, intent);
break;
case INTENT_BUGREPORT_INFO_LAUNCH:
- launchBugreportInfoDialog(pid);
+ launchBugreportInfoDialog(id);
break;
case INTENT_BUGREPORT_SCREENSHOT:
- takeScreenshot(pid, true);
+ takeScreenshot(id, true);
break;
case INTENT_BUGREPORT_SHARE:
- shareBugreport(pid, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
+ shareBugreport(id, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
break;
case INTENT_BUGREPORT_CANCEL:
- cancel(pid);
+ cancel(id);
break;
default:
Log.w(TAG, "Unsupported intent: " + action);
@@ -367,10 +375,10 @@ public class BugreportProgressService extends Service {
}
}
- private BugreportInfo getInfo(int pid) {
- final BugreportInfo info = mProcesses.get(pid);
+ private BugreportInfo getInfo(int id) {
+ final BugreportInfo info = mProcesses.get(id);
if (info == null) {
- Log.w(TAG, "Not monitoring process with PID " + pid);
+ Log.w(TAG, "Not monitoring process with ID " + id);
}
return info;
}
@@ -381,10 +389,14 @@ public class BugreportProgressService extends Service {
*
* @return whether it succeeded or not.
*/
- private boolean startProgress(String name, int pid, int max) {
+ private boolean startProgress(String name, int id, int pid, int max) {
if (name == null) {
Log.w(TAG, "Missing " + EXTRA_NAME + " on start intent");
}
+ if (id == -1) {
+ Log.e(TAG, "Missing " + EXTRA_ID + " on start intent");
+ return false;
+ }
if (pid == -1) {
Log.e(TAG, "Missing " + EXTRA_PID + " on start intent");
return false;
@@ -394,14 +406,14 @@ public class BugreportProgressService extends Service {
return false;
}
- final BugreportInfo info = new BugreportInfo(mContext, pid, name, max);
- if (mProcesses.indexOfKey(pid) >= 0) {
- Log.w(TAG, "PID " + pid + " already watched");
+ final BugreportInfo info = new BugreportInfo(mContext, id, pid, name, max);
+ if (mProcesses.indexOfKey(id) >= 0) {
+ Log.w(TAG, "ID " + id + " already watched");
} else {
- mProcesses.put(info.pid, info);
+ mProcesses.put(info.id, info);
}
// Take initial screenshot.
- takeScreenshot(pid, false);
+ takeScreenshot(id, false);
updateProgress(info);
return true;
}
@@ -423,22 +435,24 @@ public class BugreportProgressService extends Service {
com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
- infoIntent.putExtra(EXTRA_PID, info.pid);
+ infoIntent.putExtra(EXTRA_ID, info.id);
+ final PendingIntent infoPendingIntent =
+ PendingIntent.getService(mContext, info.id, infoIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
final Action infoAction = new Action.Builder(null,
mContext.getString(R.string.bugreport_info_action),
- PendingIntent.getService(mContext, info.pid, infoIntent,
- PendingIntent.FLAG_UPDATE_CURRENT)).build();
+ infoPendingIntent).build();
final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
- screenshotIntent.putExtra(EXTRA_PID, info.pid);
+ screenshotIntent.putExtra(EXTRA_ID, info.id);
PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
- .getService(mContext, info.pid, screenshotIntent,
+ .getService(mContext, info.id, screenshotIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
final Action screenshotAction = new Action.Builder(null,
mContext.getString(R.string.bugreport_screenshot_action),
screenshotPendingIntent).build();
- final String title = mContext.getString(R.string.bugreport_in_progress_title, info.pid);
+ final String title = mContext.getString(R.string.bugreport_in_progress_title, info.id);
final String name =
info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
@@ -454,6 +468,7 @@ public class BugreportProgressService extends Service {
.setLocalOnly(true)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
+ .setContentIntent(infoPendingIntent)
.addAction(infoAction)
.addAction(screenshotAction)
.addAction(cancelAction)
@@ -464,8 +479,11 @@ public class BugreportProgressService extends Service {
+ info + ")");
return;
}
- Log.v(TAG, "Sending 'Progress' notification for pid " + info.pid + ": " + percentText);
- NotificationManager.from(mContext).notify(TAG, info.pid, notification);
+ if (DEBUG) {
+ Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
+ + "): " + percentText);
+ }
+ NotificationManager.from(mContext).notify(TAG, info.id, notification);
}
/**
@@ -474,38 +492,39 @@ public class BugreportProgressService extends Service {
private static PendingIntent newCancelIntent(Context context, BugreportInfo info) {
final Intent intent = new Intent(INTENT_BUGREPORT_CANCEL);
intent.setClass(context, BugreportProgressService.class);
- intent.putExtra(EXTRA_PID, info.pid);
- return PendingIntent.getService(context, info.pid, intent,
+ intent.putExtra(EXTRA_ID, info.id);
+ return PendingIntent.getService(context, info.id, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* Finalizes the progress on a given bugreport and cancel its notification.
*/
- private void stopProgress(int pid) {
- if (mProcesses.indexOfKey(pid) < 0) {
- Log.w(TAG, "PID not watched: " + pid);
+ private void stopProgress(int id) {
+ if (mProcesses.indexOfKey(id) < 0) {
+ Log.w(TAG, "ID not watched: " + id);
} else {
- Log.d(TAG, "Removing PID " + pid);
- mProcesses.remove(pid);
+ Log.d(TAG, "Removing ID " + id);
+ mProcesses.remove(id);
}
stopSelfWhenDone();
- Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
- NotificationManager.from(mContext).cancel(TAG, pid);
+ Log.v(TAG, "stopProgress(" + id + "): cancel notification");
+ NotificationManager.from(mContext).cancel(TAG, id);
}
/**
* Cancels a bugreport upon user's request.
*/
- private void cancel(int pid) {
- Log.v(TAG, "cancel: pid=" + pid);
- final BugreportInfo info = getInfo(pid);
+ private void cancel(int id) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL);
+ Log.v(TAG, "cancel: ID=" + id);
+ final BugreportInfo info = getInfo(id);
if (info != null && !info.finished) {
- Log.i(TAG, "Cancelling bugreport service (pid=" + pid + ") on user's request");
+ Log.i(TAG, "Cancelling bugreport service (ID=" + id + ") on user's request");
setSystemProperty(CTL_STOP, BUGREPORT_SERVICE);
deleteScreenshots(info);
}
- stopProgress(pid);
+ stopProgress(id);
}
/**
@@ -522,14 +541,15 @@ public class BugreportProgressService extends Service {
for (int i = 0; i < total; i++) {
final BugreportInfo info = mProcesses.valueAt(i);
if (info == null) {
- Log.wtf(TAG, "pollProgress(): null info at index " + i + "(pid = "
+ Log.wtf(TAG, "pollProgress(): null info at index " + i + "(ID = "
+ mProcesses.keyAt(i) + ")");
continue;
}
final int pid = info.pid;
+ final int id = info.id;
if (info.finished) {
- if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+ if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + " (id: " + id + ")");
continue;
}
activeProcesses++;
@@ -544,13 +564,13 @@ public class BugreportProgressService extends Service {
if (progressChanged || maxChanged) {
if (progressChanged) {
- if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
- + info.progress + " to " + progress);
+ if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id
+ + ") from " + info.progress + " to " + progress);
info.progress = progress;
}
if (maxChanged) {
- Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
- + " to " + max);
+ Log.i(TAG, "Updating max progress for PID " + pid + "(id: " + id
+ + ") from " + info.max + " to " + max);
info.max = max;
}
info.lastUpdate = System.currentTimeMillis();
@@ -558,9 +578,9 @@ public class BugreportProgressService extends Service {
} else {
long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
if (inactiveTime >= INACTIVITY_TIMEOUT) {
- Log.w(TAG, "No progress update for process " + pid + " since "
+ Log.w(TAG, "No progress update for PID " + pid + " since "
+ info.getFormattedLastUpdate());
- stopProgress(info.pid);
+ stopProgress(info.id);
}
}
}
@@ -572,19 +592,23 @@ public class BugreportProgressService extends Service {
* Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
* change its values.
*/
- private void launchBugreportInfoDialog(int pid) {
+ private void launchBugreportInfoDialog(int id) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS);
// Copy values so it doesn't lock mProcesses while UI is being updated
final String name, title, description;
- final BugreportInfo info = getInfo(pid);
+ final BugreportInfo info = getInfo(id);
if (info == null) {
+ // Most likely am killed Shell before user tapped the notification. Since system might
+ // be too busy anwyays, it's better to ignore the notification and switch back to the
+ // non-interactive mode (where the bugerport will be shared upon completion).
+ Log.d(TAG, "launchBugreportInfoDialog(" + id + "): cancel notification");
+ // TODO: add test case to make sure notification is canceled.
+ NotificationManager.from(mContext).cancel(TAG, id);
return;
}
- name = info.name;
- title = info.title;
- description = info.description;
collapseNotificationBar();
- mInfoDialog.initialize(mContext, pid, name, title, description);
+ mInfoDialog.initialize(mContext, info);
}
/**
@@ -597,7 +621,17 @@ public class BugreportProgressService extends Service {
* Typical usage is delaying when taken from the notification action, and taking it right away
* upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
*/
- private void takeScreenshot(int pid, boolean delayed) {
+ private void takeScreenshot(int id, boolean delayed) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT);
+ if (getInfo(id) == null) {
+ // Most likely am killed Shell before user tapped the notification. Since system might
+ // be too busy anwyays, it's better to ignore the notification and switch back to the
+ // non-interactive mode (where the bugerport will be shared upon completion).
+ Log.d(TAG, "takeScreenshot(" + id + ", " + delayed + "): cancel notification");
+ // TODO: add test case to make sure notification is canceled.
+ NotificationManager.from(mContext).cancel(TAG, id);
+ return;
+ }
setTakingScreenshot(true);
if (delayed) {
collapseNotificationBar();
@@ -608,39 +642,36 @@ public class BugreportProgressService extends Service {
// Show a toast just once, otherwise it might be captured in the screenshot.
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
- takeScreenshot(pid, SCREENSHOT_DELAY_SECONDS);
+ takeScreenshot(id, SCREENSHOT_DELAY_SECONDS);
} else {
- takeScreenshot(pid, 0);
+ takeScreenshot(id, 0);
}
}
/**
* Takes a screenshot after {@code delay} seconds.
*/
- private void takeScreenshot(int pid, int delay) {
+ private void takeScreenshot(int id, int delay) {
if (delay > 0) {
- Log.d(TAG, "Taking screenshot for " + pid + " in " + delay + " seconds");
+ Log.d(TAG, "Taking screenshot for " + id + " in " + delay + " seconds");
final Message msg = mMainHandler.obtainMessage();
msg.what = MSG_DELAYED_SCREENSHOT;
- msg.arg1 = pid;
+ msg.arg1 = id;
msg.arg2 = delay - 1;
mMainHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
return;
}
// It's time to take the screenshot: let the proper thread handle it
- final BugreportInfo info = getInfo(pid);
+ final BugreportInfo info = getInfo(id);
if (info == null) {
return;
}
final String screenshotPath =
new File(mScreenshotsDir, info.getPathNextScreenshot()).getAbsolutePath();
- final Message requestMsg = new Message();
- requestMsg.what = MSG_SCREENSHOT_REQUEST;
- requestMsg.arg1 = pid;
- requestMsg.obj = screenshotPath;
- mScreenshotHandler.sendMessage(requestMsg);
+ Message.obtain(mScreenshotHandler, MSG_SCREENSHOT_REQUEST, id, UNUSED_ARG2, screenshotPath)
+ .sendToTarget();
}
/**
@@ -666,12 +697,8 @@ public class BugreportProgressService extends Service {
boolean taken = takeScreenshot(mContext, screenshotFile);
setTakingScreenshot(false);
- final Message resultMsg = new Message();
- resultMsg.what = MSG_SCREENSHOT_RESPONSE;
- resultMsg.arg1 = requestMsg.arg1;
- resultMsg.arg2 = taken ? 1 : 0;
- resultMsg.obj = screenshotFile;
- mMainHandler.sendMessage(resultMsg);
+ Message.obtain(mMainHandler, MSG_SCREENSHOT_RESPONSE, requestMsg.arg1, taken ? 1 : 0,
+ screenshotFile).sendToTarget();
}
private void handleScreenshotResponse(Message resultMsg) {
@@ -682,7 +709,7 @@ public class BugreportProgressService extends Service {
}
final File screenshotFile = new File((String) resultMsg.obj);
- final int msgId;
+ final String msg;
if (taken) {
info.addScreenshot(screenshotFile);
if (info.finished) {
@@ -690,14 +717,13 @@ public class BugreportProgressService extends Service {
info.renameScreenshots(mScreenshotsDir);
sendBugreportNotification(mContext, info);
}
- msgId = R.string.bugreport_screenshot_taken;
+ msg = mContext.getString(R.string.bugreport_screenshot_taken);
} else {
// TODO: try again using Framework APIs instead of relying on screencap.
- msgId = R.string.bugreport_screenshot_failed;
+ msg = mContext.getString(R.string.bugreport_screenshot_failed);
+ Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
- final String msg = mContext.getString(msgId);
Log.d(TAG, msg);
- Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
/**
@@ -715,34 +741,40 @@ public class BugreportProgressService extends Service {
*/
private void stopSelfWhenDone() {
if (mProcesses.size() > 0) {
- if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
+ if (DEBUG) Log.d(TAG, "Staying alive, waiting for IDs " + mProcesses);
return;
}
- Log.v(TAG, "No more pids to handle, shutting down");
+ Log.v(TAG, "No more processes to handle, shutting down");
stopSelf();
}
/**
* Handles the BUGREPORT_FINISHED intent sent by {@code dumpstate}.
*/
- private void onBugreportFinished(int pid, Intent intent) {
+ private void onBugreportFinished(int id, Intent intent) {
final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
if (bugreportFile == null) {
// Should never happen, dumpstate always set the file.
Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
return;
}
- mInfoDialog.onBugreportFinished(pid);
- BugreportInfo info = getInfo(pid);
+ mInfoDialog.onBugreportFinished(id);
+ BugreportInfo info = getInfo(id);
if (info == null) {
// Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
- Log.v(TAG, "Creating info for untracked pid " + pid);
- info = new BugreportInfo(mContext, pid);
- mProcesses.put(pid, info);
+ Log.v(TAG, "Creating info for untracked ID " + id);
+ info = new BugreportInfo(mContext, id);
+ mProcesses.put(id, info);
}
info.renameScreenshots(mScreenshotsDir);
info.bugreportFile = bugreportFile;
+ final int max = intent.getIntExtra(EXTRA_MAX, -1);
+ if (max != -1) {
+ MetricsLogger.histogram(this, "dumpstate_duration", max);
+ info.max = max;
+ }
+
final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
if (screenshot != null) {
info.addScreenshot(screenshot);
@@ -765,7 +797,7 @@ public class BugreportProgressService extends Service {
if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
- stopProgress(info.pid);
+ stopProgress(info.id);
return;
}
@@ -837,12 +869,13 @@ public class BugreportProgressService extends Service {
* Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
* intent, but issuing a warning dialog the first time.
*/
- private void shareBugreport(int pid, BugreportInfo sharedInfo) {
- BugreportInfo info = getInfo(pid);
+ private void shareBugreport(int id, BugreportInfo sharedInfo) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE);
+ BugreportInfo info = getInfo(id);
if (info == null) {
// Service was terminated but notification persisted
info = sharedInfo;
- Log.d(TAG, "shareBugreport(): no info for PID " + pid + " on managed processes ("
+ Log.d(TAG, "shareBugreport(): no info for ID " + id + " on managed processes ("
+ mProcesses + "), using info from intent instead (" + info + ")");
}
@@ -863,7 +896,7 @@ public class BugreportProgressService extends Service {
mContext.startActivity(notifIntent);
// ... and stop watching this process.
- stopProgress(pid);
+ stopProgress(id);
}
/**
@@ -877,16 +910,16 @@ public class BugreportProgressService extends Service {
final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
shareIntent.setClass(context, BugreportProgressService.class);
shareIntent.setAction(INTENT_BUGREPORT_SHARE);
- shareIntent.putExtra(EXTRA_PID, info.pid);
+ shareIntent.putExtra(EXTRA_ID, info.id);
shareIntent.putExtra(EXTRA_INFO, info);
- final String title = context.getString(R.string.bugreport_finished_title, info.pid);
+ final String title = context.getString(R.string.bugreport_finished_title, info.id);
final Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setContentTitle(title)
.setTicker(title)
.setContentText(context.getString(R.string.bugreport_finished_text))
- .setContentIntent(PendingIntent.getService(context, info.pid, shareIntent,
+ .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
.setDeleteIntent(newCancelIntent(context, info))
.setLocalOnly(true)
@@ -897,8 +930,8 @@ public class BugreportProgressService extends Service {
builder.setContentInfo(info.name);
}
- Log.v(TAG, "Sending 'Share' notification for pid " + info.pid + ": " + title);
- NotificationManager.from(context).notify(TAG, info.pid, builder.build());
+ Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
+ NotificationManager.from(context).notify(TAG, info.id, builder.build());
}
/**
@@ -906,7 +939,7 @@ public class BugreportProgressService extends Service {
* finishes - at this point there is nothing to be done other than waiting, hence it has no
* pending action.
*/
- private static void sendBugreportBeingUpdatedNotification(Context context, int pid) {
+ private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
final String title = context.getString(R.string.bugreport_updating_title);
final Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
@@ -916,8 +949,8 @@ public class BugreportProgressService extends Service {
.setLocalOnly(true)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color));
- Log.v(TAG, "Sending 'Updating zip' notification for pid " + pid + ": " + title);
- NotificationManager.from(context).notify(TAG, pid, builder.build());
+ Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
+ NotificationManager.from(context).notify(TAG, id, builder.build());
}
/**
@@ -985,7 +1018,7 @@ public class BugreportProgressService extends Service {
// It's not possible to add a new entry into an existing file, so we need to create a new
// zip, copy all entries, then rename it.
- sendBugreportBeingUpdatedNotification(context, info.pid); // ...and that takes time
+ sendBugreportBeingUpdatedNotification(context, info.id); // ...and that takes time
final File dir = info.bugreportFile.getParentFile();
final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -1092,7 +1125,7 @@ public class BugreportProgressService extends Service {
private static boolean setSystemProperty(String key, String value) {
try {
- if (DEBUG) Log.v(TAG, "Setting system property" + key + " to " + value);
+ if (DEBUG) Log.v(TAG, "Setting system property " + key + " to " + value);
SystemProperties.set(key, value);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Could not set property " + key + " to " + value, e);
@@ -1113,14 +1146,21 @@ public class BugreportProgressService extends Service {
/**
* Updates the user-provided details of a bugreport.
*/
- private void updateBugreportInfo(int pid, String name, String title, String description) {
- final BugreportInfo info = getInfo(pid);
+ private void updateBugreportInfo(int id, String name, String title, String description) {
+ final BugreportInfo info = getInfo(id);
if (info == null) {
return;
}
+ if (title != null && !title.equals(info.title)) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_TITLE_CHANGED);
+ }
info.title = title;
+ if (description != null && !description.equals(info.description)) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED);
+ }
info.description = description;
- if (name != null && !info.name.equals(name)) {
+ if (name != null && !name.equals(info.name)) {
+ MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_DETAILS_NAME_CHANGED);
info.name = name;
updateProgress(info);
}
@@ -1179,6 +1219,7 @@ public class BugreportProgressService extends Service {
private EditText mInfoDescription;
private AlertDialog mDialog;
private Button mOkButton;
+ private int mId;
private int mPid;
/**
@@ -1207,8 +1248,9 @@ public class BugreportProgressService extends Service {
/**
* Sets its internal state and displays the dialog.
*/
- private void initialize(Context context, int pid, String name, String title,
- String description) {
+ private void initialize(final Context context, BugreportInfo info) {
+ final String dialogTitle =
+ context.getString(R.string.bugreport_info_dialog_title, info.id);
// First initializes singleton.
if (mDialog == null) {
@SuppressLint("InflateParams")
@@ -1232,7 +1274,7 @@ public class BugreportProgressService extends Service {
mDialog = new AlertDialog.Builder(context)
.setView(view)
- .setTitle(context.getString(R.string.bugreport_info_dialog_title, pid))
+ .setTitle(dialogTitle)
.setCancelable(false)
.setPositiveButton(context.getString(com.android.internal.R.string.ok),
null)
@@ -1242,6 +1284,8 @@ public class BugreportProgressService extends Service {
@Override
public void onClick(DialogInterface dialog, int id)
{
+ MetricsLogger.action(context,
+ MetricsEvent.ACTION_BUGREPORT_DETAILS_CANCELED);
if (!mTempName.equals(mSavedName)) {
// Must restore dumpstate's name since it was changed
// before user clicked OK.
@@ -1255,19 +1299,26 @@ public class BugreportProgressService extends Service {
new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG));
+ } else {
+ // Re-use view, but reset fields first.
+ mDialog.setTitle(dialogTitle);
+ mInfoName.setText(null);
+ mInfoTitle.setText(null);
+ mInfoDescription.setText(null);
}
// Then set fields.
- mSavedName = mTempName = name;
- mPid = pid;
- if (!TextUtils.isEmpty(name)) {
- mInfoName.setText(name);
+ mSavedName = mTempName = info.name;
+ mId = info.id;
+ mPid = info.pid;
+ if (!TextUtils.isEmpty(info.name)) {
+ mInfoName.setText(info.name);
}
- if (!TextUtils.isEmpty(title)) {
- mInfoTitle.setText(title);
+ if (!TextUtils.isEmpty(info.title)) {
+ mInfoTitle.setText(info.title);
}
- if (!TextUtils.isEmpty(description)) {
- mInfoDescription.setText(description);
+ if (!TextUtils.isEmpty(info.description)) {
+ mInfoDescription.setText(info.description);
}
// And finally display it.
@@ -1285,12 +1336,13 @@ public class BugreportProgressService extends Service {
@Override
public void onClick(View view) {
+ MetricsLogger.action(context, MetricsEvent.ACTION_BUGREPORT_DETAILS_SAVED);
sanitizeName();
final String name = mInfoName.getText().toString();
final String title = mInfoTitle.getText().toString();
final String description = mInfoDescription.getText().toString();
- updateBugreportInfo(mPid, name, title, description);
+ updateBugreportInfo(mId, name, title, description);
mDialog.dismiss();
}
});
@@ -1337,7 +1389,7 @@ public class BugreportProgressService extends Service {
* <p>Once the bugreport is finished dumpstate has already generated the final files, so
* changing the name would have no effect.
*/
- private void onBugreportFinished(int pid) {
+ private void onBugreportFinished(int id) {
if (mInfoName != null) {
mInfoName.setEnabled(false);
mInfoName.setText(mSavedName);
@@ -1353,6 +1405,11 @@ public class BugreportProgressService extends Service {
private final Context context;
/**
+ * Sequential, user-friendly id used to identify the bugreport.
+ */
+ final int id;
+
+ /**
* {@code pid} of the {@code dumpstate} process generating the bugreport.
*/
final int pid;
@@ -1426,8 +1483,9 @@ public class BugreportProgressService extends Service {
/**
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
*/
- BugreportInfo(Context context, int pid, String name, int max) {
+ BugreportInfo(Context context, int id, int pid, String name, int max) {
this.context = context;
+ this.id = id;
this.pid = pid;
this.name = name;
this.max = max;
@@ -1437,8 +1495,8 @@ public class BugreportProgressService extends Service {
* Constructor for untracked bugreports - typically called upon receiving BUGREPORT_FINISHED
* without a previous call to BUGREPORT_STARTED.
*/
- BugreportInfo(Context context, int pid) {
- this(context, pid, null, 0);
+ BugreportInfo(Context context, int id) {
+ this(context, id, id, null, 0);
this.finished = true;
}
@@ -1467,7 +1525,7 @@ public class BugreportProgressService extends Service {
final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size());
for (File oldFile : screenshotFiles) {
final String oldName = oldFile.getName();
- final String newName = oldName.replace(Integer.toString(pid), name);
+ final String newName = oldName.replaceFirst(Integer.toString(pid), name);
final File newFile;
if (!newName.equals(oldName)) {
final File renamedFile = new File(screenshotDir, newName);
@@ -1494,10 +1552,10 @@ public class BugreportProgressService extends Service {
@Override
public String toString() {
final float percent = ((float) progress * 100 / max);
- return "pid: " + pid + ", name: " + name + ", finished: " + finished
+ return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
+ "\n\ttitle: " + title + "\n\tdescription: " + description
+ "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
- + "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
+ + "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
+ "\n\tlast_update: " + getFormattedLastUpdate()
+ "\naddingDetailsToZip: " + addingDetailsToZip
+ " addedDetailsToZip: " + addedDetailsToZip;
@@ -1506,6 +1564,7 @@ public class BugreportProgressService extends Service {
// Parcelable contract
protected BugreportInfo(Parcel in) {
context = null;
+ id = in.readInt();
pid = in.readInt();
name = in.readString();
title = in.readString();
@@ -1527,6 +1586,7 @@ public class BugreportProgressService extends Service {
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(id);
dest.writeInt(pid);
dest.writeString(name);
dest.writeString(title);
diff --git a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
index 6f783a1fbabf..be54b43e0524 100644
--- a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.UserHandle;
+import android.text.format.DateUtils;
/**
* Receiver that handles finished remote bugreports, by re-sending
@@ -43,12 +44,16 @@ public class RemoteBugreportReceiver extends BroadcastReceiver {
private static final String EXTRA_REMOTE_BUGREPORT_HASH =
"android.intent.extra.REMOTE_BUGREPORT_HASH";
- /** Always keep just the last remote bugreport zip file */
- private static final int MIN_KEEP_COUNT = 1;
+ /** Always keep just the last remote bugreport's files around. */
+ private static final int REMOTE_BUGREPORT_FILES_AMOUNT = 3;
+
+ /** Always keep remote bugreport files created in the last day. */
+ private static final long MIN_KEEP_AGE = DateUtils.DAY_IN_MILLIS;
@Override
public void onReceive(Context context, Intent intent) {
- cleanupOldFiles(this, intent, INTENT_REMOTE_BUGREPORT_FINISHED, MIN_KEEP_COUNT, 0);
+ cleanupOldFiles(this, intent, INTENT_REMOTE_BUGREPORT_FINISHED,
+ REMOTE_BUGREPORT_FILES_AMOUNT, MIN_KEEP_AGE);
final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
final Uri bugreportUri = getUri(context, bugreportFile);
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 8c62670dfa7c..d0499a5e3946 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -19,6 +19,7 @@ package com.android.shell;
import static android.test.MoreAsserts.assertContainsRegex;
import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
+import static com.android.shell.BugreportProgressService.EXTRA_ID;
import static com.android.shell.BugreportProgressService.EXTRA_MAX;
import static com.android.shell.BugreportProgressService.EXTRA_NAME;
import static com.android.shell.BugreportProgressService.EXTRA_PID;
@@ -60,6 +61,7 @@ import android.service.notification.StatusBarNotification;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
@@ -98,24 +100,33 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
private static final String BUGREPORTS_DIR = "bugreports";
private static final String BUGREPORT_FILE = "test_bugreport.txt";
private static final String ZIP_FILE = "test_bugreport.zip";
+ private static final String ZIP_FILE2 = "test_bugreport2.zip";
private static final String SCREENSHOT_FILE = "test_screenshot.png";
private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n";
private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n";
private static final int PID = 42;
- private static final String PROGRESS_PROPERTY = "dumpstate.42.progress";
- private static final String MAX_PROPERTY = "dumpstate.42.max";
- private static final String NAME_PROPERTY = "dumpstate.42.name";
+ private static final int PID2 = 24;
+ private static final int ID = 108;
+ private static final int ID2 = 801;
+ private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress";
+ private static final String MAX_PROPERTY = "dumpstate." + PID + ".max";
+ private static final String NAME_PROPERTY = "dumpstate." + PID + ".name";
private static final String NAME = "BUG, Y U NO REPORT?";
+ private static final String NAME2 = "A bugreport's life";
private static final String NEW_NAME = "Bug_Forrest_Bug";
+ private static final String NEW_NAME2 = "BugsyReportsy";
private static final String TITLE = "Wimbugdom Champion 2015";
+ private static final String TITLE2 = "Master of the Universe";
+ private static final String DESCRIPTION = "One's description...";
+ private static final String DESCRIPTION2 = "...is another's treasure.";
private static final String NO_DESCRIPTION = null;
private static final String NO_NAME = null;
private static final String NO_SCREENSHOT = null;
private static final String NO_TITLE = null;
- private static final int NO_PID = 0;
+ private static final int NO_ID = 0;
private static final boolean RENAMED_SCREENSHOTS = true;
private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
@@ -123,6 +134,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
private String mPlainTextPath;
private String mZipPath;
+ private String mZipPath2;
private String mScreenshotPath;
private Context mContext;
@@ -141,10 +153,12 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
mPlainTextPath = getPath(BUGREPORT_FILE);
mZipPath = getPath(ZIP_FILE);
+ mZipPath2 = getPath(ZIP_FILE2);
mScreenshotPath = getPath(SCREENSHOT_FILE);
createTextFile(mPlainTextPath, BUGREPORT_CONTENT);
createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
+ createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT);
// Creates a multi-line description.
StringBuilder sb = new StringBuilder();
@@ -177,13 +191,32 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
assertProgressNotification(NAME, nf.format(0.25));
Bundle extras =
- sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+ sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
+ public void testProgress_cancel() throws Exception {
+ resetProperties();
+ sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
+
+ final NumberFormat nf = NumberFormat.getPercentInstance();
+ nf.setMinimumFractionDigits(2);
+ nf.setMaximumFractionDigits(2);
+
+ assertProgressNotification(NAME, nf.format(0));
+
+ openProgressNotification(ID);
+ UiObject cancelButton = mUiBot.getVisibleObject(mContext.getString(
+ com.android.internal.R.string.cancel).toUpperCase());
+ mUiBot.click(cancelButton, "cancel_button");
+
+ waitForService(false);
+ }
+
public void testProgress_takeExtraScreenshot() throws Exception {
takeExtraScreenshotTest(false);
}
@@ -201,15 +234,15 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
assertScreenshotButtonEnabled(false);
waitForScreenshotButtonEnabled(true);
- sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+ sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
if (serviceDies) {
- waitShareNotification(PID);
+ waitShareNotification(ID);
killService();
}
- Bundle extras = acceptBugreportAndGetSharedIntent(PID);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+ Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 2, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
@@ -227,8 +260,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
resetProperties();
sendBugreportStarted(1000);
- sendBugreportFinished(PID, mPlainTextPath, NO_SCREENSHOT);
- waitShareNotification(PID);
+ sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT);
+ waitShareNotification(ID);
// There's no indication in the UI about the screenshot finish, so just sleep like a baby...
Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
@@ -237,8 +270,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
killService();
}
- Bundle extras = acceptBugreportAndGetSharedIntent(PID);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, PID, ZIP_FILE,
+ Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
@@ -249,11 +282,10 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
sendBugreportStarted(1000);
waitForScreenshotButtonEnabled(true);
- DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+ DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
// Check initial name.
- String actualName = detailsUi.nameField.getText().toString();
- assertEquals("Wrong value on field 'name'", NAME, actualName);
+ detailsUi.assertName(NAME);
// Change name - it should have changed system property once focus is changed.
detailsUi.nameField.setText(NEW_NAME);
@@ -281,9 +313,9 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
assertPropertyValue(NAME_PROPERTY, NEW_NAME);
assertProgressNotification(NEW_NAME, "0.00%");
- Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath,
mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
@@ -302,11 +334,10 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
sendBugreportStarted(1000);
waitForScreenshotButtonEnabled(true);
- DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+ DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
// Check initial name.
- String actualName = detailsUi.nameField.getText().toString();
- assertEquals("Wrong value on field 'name'", NAME, actualName);
+ detailsUi.assertName(NAME);
// Change fields.
detailsUi.reOpen();
@@ -319,33 +350,87 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
assertPropertyValue(NAME_PROPERTY, NEW_NAME);
assertProgressNotification(NEW_NAME, "0.00%");
- Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID,
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID,
plainText? mPlainTextPath : mZipPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
}
- public void testProgress_changeJustDetails() throws Exception {
+ public void testProgress_changeJustDetailsTouchingDetails() throws Exception {
+ changeJustDetailsTest(true);
+ }
+
+ public void testProgress_changeJustDetailsTouchingNotification() throws Exception {
+ changeJustDetailsTest(false);
+ }
+
+ private void changeJustDetailsTest(boolean touchDetails) throws Exception {
resetProperties();
sendBugreportStarted(1000);
waitForScreenshotButtonEnabled(true);
- DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+ DetailsUi detailsUi = new DetailsUi(mUiBot, ID, touchDetails);
detailsUi.nameField.setText("");
detailsUi.titleField.setText("");
detailsUi.descField.setText(mDescription);
detailsUi.clickOk();
- Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mZipPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
NO_NAME, NO_TITLE, mDescription, 1, DIDNT_RENAME_SCREENSHOTS);
assertServiceNotRunning();
}
+ /*
+ * TODO: this test can be flanky because it relies in the order the notifications are displayed,
+ * since mUiBot gets the first notification.
+ * Ideally, openProgressNotification() should return the whole notification, so DetailsUi
+ * could use it and find children instead, but unfortunately the notification object hierarchy
+ * is too complex and getting it from the notification text object would be to fragile
+ * (for instance, it could require navigating many parents up in the hierarchy).
+ */
+ public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception {
+ resetProperties();
+ sendBugreportStarted(ID, PID, NAME, 1000);
+ waitForScreenshotButtonEnabled(true);
+
+ DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
+ detailsUi.assertName(NAME);
+ detailsUi.assertTitle(mContext.getString(R.string.bugreport_info_title));
+ detailsUi.assertDescription(mContext.getString(R.string.bugreport_info_description));
+ detailsUi.nameField.setText(NEW_NAME);
+ detailsUi.titleField.setText(TITLE);
+ detailsUi.descField.setText(DESCRIPTION);
+ detailsUi.clickOk();
+
+ sendBugreportStarted(ID2, PID2, NAME2, 1000);
+
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
+ NEW_NAME, TITLE, DESCRIPTION, 1, RENAMED_SCREENSHOTS);
+
+ detailsUi = new DetailsUi(mUiBot, ID2);
+ detailsUi.assertName(NAME2);
+ detailsUi.assertTitle(mContext.getString(R.string.bugreport_info_title));
+ detailsUi.assertDescription(mContext.getString(R.string.bugreport_info_description));
+ detailsUi.nameField.setText(NEW_NAME2);
+ detailsUi.titleField.setText(TITLE2);
+ detailsUi.descField.setText(DESCRIPTION2);
+ detailsUi.clickOk();
+
+ // Must use a different zip file otherwise it will fail because zip already contains
+ // title.txt and description.txt entries.
+ extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2,
+ NEW_NAME2, TITLE2, DESCRIPTION2, 1, RENAMED_SCREENSHOTS);
+
+ assertServiceNotRunning();
+ }
+
/**
* Tests the scenario where the initial screenshot and dumpstate are finished while the user
* is changing the info in the details screen.
@@ -369,14 +454,14 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
waitForScreenshotButtonEnabled(true);
}
- DetailsUi detailsUi = new DetailsUi(mUiBot, PID);
+ DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
// Finish the bugreport while user's still typing the name.
detailsUi.nameField.setText(NEW_NAME);
- sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+ sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
// Wait until the share notification is received...
- waitShareNotification(PID);
+ waitShareNotification(ID);
// ...then close notification bar.
mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
@@ -390,8 +475,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
detailsUi.clickOk();
// Finally, share bugreport.
- Bundle extras = acceptBugreportAndGetSharedIntent(PID);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+ Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
assertServiceNotRunning();
@@ -402,8 +487,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
// Send notification and click on share.
- sendBugreportFinished(NO_PID, mPlainTextPath, null);
- acceptBugreport(NO_PID);
+ sendBugreportFinished(NO_ID, mPlainTextPath, null);
+ acceptBugreport(NO_ID);
// Handle the warning
mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
@@ -425,9 +510,9 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
}
public void testShareBugreportAfterServiceDies() throws Exception {
- sendBugreportFinished(NO_PID, mPlainTextPath, NO_SCREENSHOT);
+ sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
killService();
- Bundle extras = acceptBugreportAndGetSharedIntent(NO_PID);
+ Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
}
@@ -463,32 +548,38 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
private void assertProgressNotification(String name, String percent) {
// TODO: it currently looks for 3 distinct objects, without taking advantage of their
// relationship.
- openProgressNotification(PID);
+ openProgressNotification(ID);
Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
mUiBot.getObject(name);
mUiBot.getObject(percent);
}
- private void openProgressNotification(int pid) {
- String title = mContext.getString(R.string.bugreport_in_progress_title, pid);
+ private UiObject openProgressNotification(int id) {
+ String title = mContext.getString(R.string.bugreport_in_progress_title, id);
Log.v(TAG, "Looking for progress notification title: '" + title + "'");
- mUiBot.getNotification(title);
+ return mUiBot.getNotification(title);
}
void resetProperties() {
// TODO: call method to remove property instead
- SystemProperties.set(PROGRESS_PROPERTY, "0");
- SystemProperties.set(MAX_PROPERTY, "0");
+ SystemProperties.set(PROGRESS_PROPERTY, "Reset");
+ SystemProperties.set(MAX_PROPERTY, "Reset");
+ SystemProperties.set(NAME_PROPERTY, "Reset");
}
/**
* Sends a "bugreport started" intent with the default values.
*/
private void sendBugreportStarted(int max) throws Exception {
+ sendBugreportStarted(ID, PID, NAME, max);
+ }
+
+ private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception {
Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(EXTRA_PID, PID);
- intent.putExtra(EXTRA_NAME, NAME);
+ intent.putExtra(EXTRA_ID, id);
+ intent.putExtra(EXTRA_PID, pid);
+ intent.putExtra(EXTRA_NAME, name);
intent.putExtra(EXTRA_MAX, max);
mContext.sendBroadcast(intent);
}
@@ -500,7 +591,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
*/
private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath,
String screenshotPath) {
- return sendBugreportFinishedAndGetSharedIntent(NO_PID, bugreportPath, screenshotPath);
+ return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath);
}
/**
@@ -508,10 +599,10 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
*
* @return extras sent in the shared intent.
*/
- private Bundle sendBugreportFinishedAndGetSharedIntent(int pid, String bugreportPath,
+ private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
String screenshotPath) {
- sendBugreportFinished(pid, bugreportPath, screenshotPath);
- return acceptBugreportAndGetSharedIntent(pid);
+ sendBugreportFinished(id, bugreportPath, screenshotPath);
+ return acceptBugreportAndGetSharedIntent(id);
}
/**
@@ -519,8 +610,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
*
* @return extras sent in the shared intent.
*/
- private Bundle acceptBugreportAndGetSharedIntent(int pid) {
- acceptBugreport(pid);
+ private Bundle acceptBugreportAndGetSharedIntent(int id) {
+ acceptBugreport(id);
mUiBot.chooseActivity(UI_NAME);
return mListener.getExtras();
}
@@ -528,25 +619,25 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
/**
* Waits for the notification to share the finished bugreport.
*/
- private void waitShareNotification(int pid) {
- mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, pid));
+ private void waitShareNotification(int id) {
+ mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, id));
}
/**
* Accepts the notification to share the finished bugreport.
*/
- private void acceptBugreport(int pid) {
- mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, pid));
+ private void acceptBugreport(int id) {
+ mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id));
}
/**
* Sends a "bugreport finished" intent.
*/
- private void sendBugreportFinished(int pid, String bugreportPath, String screenshotPath) {
+ private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) {
Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- if (pid != NO_PID) {
- intent.putExtra(EXTRA_PID, pid);
+ if (id != NO_ID) {
+ intent.putExtra(EXTRA_ID, id);
}
if (bugreportPath != null) {
intent.putExtra(EXTRA_BUGREPORT, bugreportPath);
@@ -563,7 +654,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
*/
private void assertActionSendMultiple(Bundle extras, String bugreportContent,
String screenshotContent) throws IOException {
- assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE,
+ assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE,
NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS);
}
@@ -573,6 +664,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
* @param extras extras received in the intent
* @param bugreportContent expected content in the bugreport file
* @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any
+ * @param id emulated dumpstate id
* @param pid emulated dumpstate pid
* @param name expected subject
* @param name bugreport name as provided by the user (or received by dumpstate)
@@ -582,7 +674,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
* @param renamedScreenshots whether the screenshots are expected to be renamed
*/
private void assertActionSendMultiple(Bundle extras, String bugreportContent,
- String screenshotContent, int pid, String subject,
+ String screenshotContent, int id, int pid, String subject,
String name, String title, String description,
int numberScreenshots, boolean renamedScreenshots) throws IOException {
String body = extras.getString(Intent.EXTRA_TEXT);
@@ -745,7 +837,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
fail("Service status didn't change to " + expectRunning);
}
- private static void createTextFile(String path, String content) throws IOException {
+ private void createTextFile(String path, String content) throws IOException {
Log.v(TAG, "createFile(" + path + ")");
try (Writer writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(path)))) {
@@ -781,7 +873,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
* Gets the notification button used to take a screenshot.
*/
private UiObject getScreenshotButton() {
- openProgressNotification(PID);
+ openProgressNotification(ID);
return mUiBot.getVisibleObject(
mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
}
@@ -833,15 +925,28 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
/**
* Gets the UI objects by opening the progress notification and clicking DETAILS.
*/
- DetailsUi(UiBot uiBot, int pid) throws UiObjectNotFoundException {
- openProgressNotification(pid);
- detailsButton = mUiBot.getVisibleObject(
- mContext.getString(R.string.bugreport_info_action).toUpperCase());
- mUiBot.click(detailsButton, "details_button");
+ DetailsUi(UiBot uiBot, int id) throws UiObjectNotFoundException {
+ this(uiBot, id, true);
+ }
+
+ /**
+ * Gets the UI objects by opening the progress notification and clicking on DETAILS or in
+ * the notification itself.
+ */
+ DetailsUi(UiBot uiBot, int id, boolean clickDetails) throws UiObjectNotFoundException {
+ UiObject notification = openProgressNotification(id);
+ detailsButton = mUiBot.getVisibleObject(mContext.getString(
+ R.string.bugreport_info_action).toUpperCase());
+
+ if (clickDetails) {
+ mUiBot.click(detailsButton, "details_button");
+ } else {
+ mUiBot.click(notification, "notification");
+ }
// TODO: unhardcode resource ids
UiObject dialogTitle = mUiBot.getVisibleObjectById("android:id/alertTitle");
assertEquals("Wrong title", mContext.getString(R.string.bugreport_info_dialog_title,
- pid), dialogTitle.getText().toString());
+ id), dialogTitle.getText().toString());
nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name");
titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title");
descField = mUiBot.getVisibleObjectById("com.android.shell:id/description");
@@ -849,6 +954,28 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
cancelButton = mUiBot.getObjectById("android:id/button2");
}
+ private void assertField(String name, UiObject field, String expected) {
+ try {
+ String actual = field.getText().toString();
+ assertEquals("Wrong value on field '" + name + "'", expected, actual);
+ } catch (UiObjectNotFoundException e) {
+ // Should not happen...
+ throw new IllegalStateException("field not found: " + name, e);
+ }
+ }
+
+ void assertName(String expected) {
+ assertField("name", nameField, expected);
+ }
+
+ void assertTitle(String expected) {
+ assertField("title", titleField, expected);
+ }
+
+ void assertDescription(String expected) {
+ assertField("description", descField, expected);
+ }
+
/**
* Takes focus away from the name field so it can be validated.
*/
@@ -858,7 +985,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
}
void reOpen() {
- openProgressNotification(PID);
+ openProgressNotification(ID);
mUiBot.click(detailsButton, "details_button");
}
diff --git a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
index 712347ab4fb7..57809acc84b1 100644
--- a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
+++ b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
@@ -106,6 +106,10 @@ public final class IntentFilterVerificationReceiver extends BroadcastReceiver {
try {
ArrayList<String> sourceAssets = new ArrayList<String>();
for (String host : hostList) {
+ // "*.example.tld" is validated via https://example.tld
+ if (host.startsWith("*.")) {
+ host = host.substring(2);
+ }
sourceAssets.add(createWebAssetString(scheme, host));
}
extras.putStringArrayList(DirectStatementService.EXTRA_SOURCE_ASSET_DESCRIPTORS,
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 88313bb50378..ad3c26b29c59 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -1,11 +1,25 @@
LOCAL_PATH:= $(call my-dir)
+
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := SystemUI-proto-tags
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) $(call all-Iaidl-files-under, src) \
+LOCAL_SRC_FILES := $(call all-proto-files-under,src) \
src/com/android/systemui/EventLogTags.logtags
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# ------------------
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+
LOCAL_STATIC_JAVA_LIBRARIES := \
Keyguard \
android-support-v7-recyclerview \
@@ -13,13 +27,12 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v7-appcompat \
android-support-v14-preference \
android-support-v17-leanback \
- framework-protos
+ framework-protos \
+ SystemUI-proto-tags
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_PACKAGE_NAME := SystemUI
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index c74e4112dada..c590ec7a97dd 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -335,8 +335,9 @@
android:exported="true"
android:theme="@style/PipTheme"
android:launchMode="singleTop"
+ android:taskAffinity=""
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
- android:resizeable="true"
+ android:resizeableActivity="true"
android:supportsPictureInPicture="true"
androidprv:alwaysFocusable="true"
android:excludeFromRecents="true" />
@@ -345,8 +346,9 @@
android:exported="true"
android:theme="@style/PipTheme"
android:launchMode="singleTop"
+ android:taskAffinity=""
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
- android:resizeable="true"
+ android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:excludeFromRecents="true" />
<activity
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 9c36b5a79c02..5e08fcbf8f52 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2015 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,30 +14,25 @@ Copyright (C) 2015 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
+ android:width="48dp"
+ android:height="48dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:pathData="M24.0,2.0C11.8,2.0 2.0,11.8 2.0,24.0c0.0,6.1 2.5,11.6 6.4,15.6L39.6,8.4C35.6,4.5 30.1,2.0 24.0,2.0z"
- android:fillColor="#E91E63"/>
+ android:fillColor="#00796B"
+ android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
<path
- android:pathData="M39.6,8.4L8.4,39.6c4.0,4.0 9.5,6.4 15.6,6.4c12.2,0.0 22.0,-9.8 22.0,-22.0C46.0,17.9 43.5,12.4 39.6,8.4z"
- android:fillColor="#F06292"/>
+ android:fillColor="#00796B"
+ android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
<path
- android:pathData="M45.9,25.9L34.0,14.0L14.0,34.0l11.9,11.9C36.5,45.0 45.0,36.5 45.9,25.9z"
- android:fillAlpha="0.33"
- android:fillColor="#E91E63"/>
+ android:fillColor="#40000000"
+ android:pathData="M44.0,35.5l-12.0,-12.0l0.0,-4.0z"/>
<path
- android:pathData="M24.0,24.0c0.0,0.0 0.0,2.2 0.0,5.0s0.0,5.0 0.0,5.0l10.0,-10.0L34.0,14.0L24.0,24.0z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#40000000"
+ android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
<path
- android:pathData="M24.0,24.0L14.0,14.0l0.0,10.0l10.0,10.0c0.0,0.0 0.0,-2.2 0.0,-5.0S24.0,24.0 24.0,24.0z"
- android:fillColor="#EEEEEE"/>
- <path
- android:pathData="M14.0,34.0l10.0,0.0 -10.0,-10.0z"
- android:fillColor="#DDDDDD"/>
- <path
- android:pathData="M34.0,34.0l0.0,-10.0 -10.0,10.0z"
- android:fillColor="#DDDDDD"/>
+ 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"/>
</vector>
+
+
diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
new file mode 100644
index 000000000000..7ddb40c503a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0 0h24v24H0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_colorize.xml b/packages/SystemUI/res/drawable/ic_night_mode.xml
index 79fd6d907264..caa7a47ee5b4 100644
--- a/packages/SystemUI/res/drawable/ic_colorize.xml
+++ b/packages/SystemUI/res/drawable/ic_night_mode.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2015 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.
diff --git a/packages/SystemUI/res/drawable/ic_night_mode_disabled.xml b/packages/SystemUI/res/drawable/ic_night_mode_disabled.xml
new file mode 100644
index 000000000000..010815a41819
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_night_mode_disabled.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<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="#4DFFFFFF"
+ android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-3.12,3.12 -1.93,-1.91 -1.41,1.41 1.42,1.42L3.0,16.25L3.0,21.0l4.75,0.0l8.92,-8.92 1.42,1.42 1.41,-1.41 -1.92,-1.92 3.12,-3.12c0.4,0.0 0.4,-1.0 0.01,-1.42zM6.92,19.0L5.0,17.08l8.06,-8.06 1.92,1.92L6.92,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
new file mode 100644
index 000000000000..d9a4f7bd9137
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
@@ -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.
+-->
+<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="#FFFFFF"
+ android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
new file mode 100644
index 000000000000..b8fa99e1dbae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
@@ -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.
+-->
+<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="#FFFFFF"
+ android:pathData="M8 5v14l11-7z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
new file mode 100644
index 000000000000..a45f9a2ac798
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="17.0dp"
+ android:height="17.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="
+ M9.0,16.0l2.0,0.0L11.0,8.0L9.0,8.0l0.0,8.0z
+ m3.0,-14.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0z
+ m0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0z
+ m1.0,-4.0l2.0,0.0l0.0,-8.0l-2.0,0.0l0.0,8.0z"/>
+ </vector>
+</inset>
diff --git a/packages/DocumentsUI/res/values-af/config.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 843a8aad4051..5cabb77a6971 100644
--- a/packages/DocumentsUI/res/values-af/config.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,9 +12,13 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <size
+ android:width="36dp"
+ android:height="36dp" />
+ <solid
+ android:color="#4DFFFFFF" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
new file mode 100644
index 000000000000..86fda0d31346
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_close_white" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_close_white" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
new file mode 100644
index 000000000000..332c669de154
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_fullscreen_white_24dp" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_fullscreen_white_24dp" />
+</selector>
diff --git a/packages/DocumentsUI/res/values-am/config.xml b/packages/SystemUI/res/drawable/tv_pip_outline.xml
index 843a8aad4051..c84438c2e55e 100644
--- a/packages/DocumentsUI/res/values-am/config.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_outline.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,9 +12,9 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke android:width="2dp" android:color="#EEEEEE" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
new file mode 100644
index 000000000000..d277b07c199e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_pause_white_24dp" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_pause_white_24dp" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_play_button.xml b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
new file mode 100644
index 000000000000..fecdc095dac4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
+</selector>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
index 6f98509b2300..6f153c1086a1 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -41,26 +41,6 @@
</FrameLayout>
- <FrameLayout
- android:id="@+id/lights_out"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/ends_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" />
-
- <LinearLayout
- android:id="@+id/center_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="horizontal" />
-
- </FrameLayout>
-
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/battery_detail.xml b/packages/SystemUI/res/layout/battery_detail.xml
index ea4db4b14182..99121a9966d6 100644
--- a/packages/SystemUI/res/layout/battery_detail.xml
+++ b/packages/SystemUI/res/layout/battery_detail.xml
@@ -14,51 +14,88 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<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="wrap_content"
- android:paddingTop="16dp"
- android:background="?android:attr/selectableItemBackground"
- android:clickable="true">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:scaleType="fitCenter"
- android:adjustViewBounds="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentStart="true"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="32dp" />
+ android:orientation="vertical">
<TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
+ android:id="@+id/charge_and_estimation"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_toStartOf="@android:id/toggle"
- android:layout_toEndOf="@android:id/icon"
- android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"
- android:text="@string/battery_detail_switch_title" />
+ android:paddingStart="72dp"
+ android:paddingBottom="@dimen/battery_detail_graph_space_top"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/colorAccent" />
- <TextView
- android:id="@android:id/summary"
- android:layout_width="wrap_content"
+ <com.android.settingslib.graph.UsageView
+ android:id="@+id/battery_usage"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_toStartOf="@android:id/toggle"
- android:layout_toEndOf="@android:id/icon"
- android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary"
- android:text="@string/battery_detail_switch_summary" />
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="24dp"
+ systemui:sideLabels="@array/battery_labels"
+ android:colorAccent="?android:attr/colorAccent"
+ systemui:textColor="#66FFFFFF" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"
+ android:layout_marginTop="@dimen/battery_detail_graph_space_bottom"
+ android:layout_marginBottom="8dp" />
- <Switch
- android:id="@android:id/toggle"
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:id="@+id/switch_container"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
- android:layout_marginEnd="16dp"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="32dp" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toStartOf="@android:id/toggle"
+ android:layout_toEndOf="@android:id/icon"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"
+ android:text="@string/battery_detail_switch_title" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_toStartOf="@android:id/toggle"
+ android:layout_toEndOf="@android:id/icon"
+ android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary"
+ android:text="@string/battery_detail_switch_summary" />
+
+ <Switch
+ android:id="@android:id/toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginEnd="16dp"
+ android:clickable="false"
+ android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
-</RelativeLayout>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/calibrate_sliders.xml
index 1f6066e5eaf0..0dec8a18caa4 100644
--- a/packages/SystemUI/res/layout/preference_matrix.xml
+++ b/packages/SystemUI/res/layout/calibrate_sliders.xml
@@ -94,11 +94,4 @@
android:layout_weight="1" />
</LinearLayout>
- <Button
- android:id="@+id/apply"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:text="@string/color_apply" />
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 7ea5027b78f4..cfaf01826885 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -27,6 +27,7 @@
<com.android.systemui.stackdivider.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
+ android:contentDescription="@string/accessibility_divider"
android:background="@null"/>
</com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 142d13a4129b..2bf4d9cb535f 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -42,26 +42,6 @@
</FrameLayout>
- <FrameLayout
- android:id="@+id/lights_out"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/ends_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" />
-
- <LinearLayout
- android:id="@+id/center_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="horizontal" />
-
- </FrameLayout>
-
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 3b7b3696ea20..7601efc92a78 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -42,26 +42,6 @@
</FrameLayout>
- <FrameLayout
- android:id="@+id/lights_out"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.android.systemui.statusbar.phone.ReverseLinearLayout
- android:id="@+id/ends_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" />
-
- <com.android.systemui.statusbar.phone.ReverseLinearLayout
- android:id="@+id/center_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical" />
-
- </FrameLayout>
-
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/color_matrix_settings.xml b/packages/SystemUI/res/layout/night_mode_settings.xml
index 3725e78cc481..3725e78cc481 100644
--- a/packages/SystemUI/res/layout/color_matrix_settings.xml
+++ b/packages/SystemUI/res/layout/night_mode_settings.xml
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index e550d9c02396..62f2b479cde9 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -26,7 +26,7 @@
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="8dp"
- android:background="@color/notification_guts_bg_color" >
+ android:background="@color/notification_guts_bg_color">
<!-- header -->
<LinearLayout
@@ -58,8 +58,38 @@
android:layout_gravity="bottom|start"
android:visibility="gone" />
</LinearLayout>
+ <!-- Importance radio buttons -->
+ <RadioGroup
+ android:id="@+id/importance_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dip"
+ android:paddingEnd="8dp" >
+ <RadioButton
+ android:id="@+id/silent_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:text="@string/show_silently"
+ style="@style/TextAppearance.NotificationGuts.Primary"
+ android:buttonTint="#858383" />
+ <RadioButton
+ android:id="@+id/block_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:text="@string/block"
+ style="@style/TextAppearance.NotificationGuts.Primary"
+ android:buttonTint="#858383" />
+ <RadioButton
+ android:id="@+id/reset_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ style="@style/TextAppearance.NotificationGuts.Primary"
+ android:buttonTint="#858383" />
+ </RadioGroup>
<!-- Importance slider -->
<LinearLayout
+ android:id="@+id/importance_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
@@ -67,7 +97,8 @@
android:clickable="false"
android:focusable="false"
android:paddingBottom="8dip"
- android:paddingEnd="8dp" >
+ android:paddingEnd="8dp"
+ android:visibility="gone">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
@@ -126,27 +157,6 @@
android:tint="@color/notification_guts_icon_tint" />
</FrameLayout>
-
- <RadioGroup
- android:id="@+id/apply_to"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- <RadioButton android:id="@+id/apply_to_topic"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:visibility="gone"
- android:buttonTint="#858383"
- />
- <RadioButton android:id="@+id/apply_to_app"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:text="@string/apply_to_app"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:visibility="gone"
- android:buttonTint="#858383"
- />
- </RadioGroup>
</LinearLayout>
<!-- buttons -->
<LinearLayout
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
new file mode 100644
index 000000000000..52d07fcc5cb7
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
@@ -0,0 +1,39 @@
+<?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 may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.NotificationSettingsIconRow
+ 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_height="wrap_content"
+ >
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/gear_icon"
+ android:layout_width="@dimen/notification_gear_width"
+ android:layout_height="@dimen/notification_gear_height"
+ android:paddingTop="@dimen/notification_gear_top_padding"
+ android:paddingStart="@dimen/notification_gear_padding"
+ android:paddingEnd="@dimen/notification_gear_padding"
+ android:paddingBottom="@dimen/notification_gear_padding"
+ android:src="@drawable/ic_settings"
+ android:tint="@color/notification_gear_color"
+ android:visibility="invisible"
+ android:alpha="0"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ />
+
+</com.android.systemui.statusbar.NotificationSettingsIconRow> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 73a92d905a3d..582ad48c189e 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -22,53 +22,21 @@
android:background="@drawable/qs_customizer_background"
android:gravity="center_horizontal">
- <LinearLayout
+ <Toolbar
+ android:id="@*android:id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="28dp"
- android:paddingEnd="8dp">
-
- <ImageView
- android:id="@+id/close"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:padding="16dp"
- android:src="@drawable/ic_close_white" />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- <Button
- android:id="@+id/save"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:background="?android:attr/selectableItemBackground"
- android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse"
- android:textColor="?android:attr/colorAccent"
- android:text="@string/save" />
-
- <Button
- android:id="@+id/reset"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:background="?android:attr/selectableItemBackground"
- android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse"
- android:textColor="?android:attr/colorAccent"
- android:text="@*android:string/reset" />
-
- </LinearLayout>
+ android:layout_marginTop="28dp"
+ android:navigationContentDescription="@*android:string/action_bar_up_description"
+ style="?android:attr/toolbarStyle" />
<android.support.v7.widget.RecyclerView
android:id="@android:id/list"
android:layout_width="@dimen/notification_panel_width"
android:layout_height="0dp"
- android:layout_weight="1" />
+ android:layout_weight="1"
+ android:scrollIndicators="top"
+ android:scrollbars="vertical" />
<View
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index ddff0f031fb6..858f48737544 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -14,12 +14,35 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- Extends LinearLayout -->
+<com.android.systemui.qs.QSDetail
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/qs_detail_background"
+ android:paddingBottom="8dp"
+ android:clickable="true"
+ android:visibility="invisible"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/qs_detail_header"
+ layout="@layout/qs_detail_header"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/qs_detail_background"
- android:paddingBottom="8dp"
- android:orientation="vertical">
+ android:layout_height="wrap_content"
+ android:layout_marginTop="28dp"
+ />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/qs_detail_header_progress"
+ android:src="@drawable/indeterminate_anim"
+ android:alpha="0"
+ android:background="@color/qs_detail_progress_track"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ systemui:hasOverlappingRendering="false"
+ />
<FrameLayout
android:id="@android:id/content"
@@ -27,30 +50,6 @@
android:layout_height="0dp"
android:layout_weight="1" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingEnd="8dp"
- android:gravity="end">
-
- <TextView
- android:id="@android:id/button2"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:minWidth="132dp"
- android:textAppearance="@style/TextAppearance.QS.DetailButton"
- android:focusable="true" />
-
- <TextView
- android:id="@android:id/button1"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minWidth="88dp"
- android:textAppearance="@style/TextAppearance.QS.DetailButton"
- android:focusable="true"/>
-
- </LinearLayout>
-</LinearLayout>
+ <include layout="@layout/qs_detail_buttons" />
+
+</com.android.systemui.qs.QSDetail>
diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml
new file mode 100644
index 000000000000..03ed62b3e600
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_buttons.xml
@@ -0,0 +1,42 @@
+<?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="wrap_content"
+ android:paddingEnd="8dp"
+ android:gravity="end">
+
+ <TextView
+ android:id="@android:id/button2"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:minWidth="132dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@android:id/button1"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="88dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:focusable="true"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index 153e35f1f675..df46271b5d64 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -19,7 +19,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="@dimen/qs_panel_padding"
- android:visibility="invisible"
android:background="@drawable/btn_borderless_rect"
android:gravity="center">
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index eef08baed736..a246e0dffdd9 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -19,4 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tile_page"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 127bddd71c43..9dd3ad284217 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -18,13 +18,35 @@
<com.android.systemui.qs.PagedTileLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <com.android.systemui.qs.PageIndicator
- android:id="@+id/page_indicator"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"
- android:gravity="center" />
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false">
+
+ <FrameLayout
+ android:id="@+id/page_decor"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_gravity="bottom">
+
+ <com.android.systemui.qs.PageIndicator
+ android:id="@+id/page_indicator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@android:id/edit"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:minWidth="88dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:textColor="#4DFFFFFF"
+ android:focusable="true"
+ android:text="@string/qs_edit" />
+
+ </FrameLayout>
</com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index bb37b83af336..994d3c943671 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -19,12 +19,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/qs_background_primary"
- android:paddingBottom="8dp"
- android:elevation="2dp">
+ android:clipToPadding="false"
+ android:clipChildren="false">
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
android:background="#0000"
+ android:layout_marginTop="@dimen/status_bar_header_height"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp" />
+
+ <include layout="@layout/quick_status_bar_expanded_header" />
+
+ <include android:id="@+id/qs_detail" layout="@layout/qs_detail" />
+
</com.android.systemui.qs.QSContainer>
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 07ac6a58e351..0a9baa0aac09 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -32,21 +32,32 @@
>
<LinearLayout
- android:id="@+id/expanded_group"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="48dp"
android:gravity="center"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal"
android:layout_alignParentEnd="true"
- android:layout_marginTop="30dp"
- android:layout_marginEnd="16dp">
+ android:layout_marginTop="28dp"
+ android:layout_marginEnd="12dp">
+
+ <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentEnd="true"
+ android:background="@drawable/ripple_drawable" >
+ <ImageView android:id="@+id/multi_user_avatar"
+ android:layout_width="@dimen/multi_user_avatar_expanded_size"
+ android:layout_height="@dimen/multi_user_avatar_expanded_size"
+ android:layout_gravity="center"
+ android:scaleType="centerInside"/>
+ </com.android.systemui.statusbar.phone.MultiUserSwitch>
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/settings_button_container"
android:layout_width="48dp"
- android:layout_height="@dimen/status_bar_header_height"
+ android:layout_height="48dp"
android:clipChildren="false"
android:clipToPadding="false">
@@ -68,24 +79,12 @@
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+ <com.android.systemui.statusbar.phone.ExpandableIndicator
+ android:id="@+id/expand_indicator"
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_alignParentEnd="true"
- android:background="@drawable/ripple_drawable" >
- <ImageView android:id="@+id/multi_user_avatar"
- android:layout_width="@dimen/multi_user_avatar_expanded_size"
- android:layout_height="@dimen/multi_user_avatar_expanded_size"
- android:layout_gravity="center"
- android:scaleType="centerInside"/>
- </com.android.systemui.statusbar.phone.MultiUserSwitch>
+ android:padding="12dp" />
- <ImageView
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:padding="12dp"
- android:src="@drawable/ic_expand_less"
- android:tint="@android:color/white" />
</LinearLayout>
<TextView
@@ -104,44 +103,62 @@
android:gravity="center_vertical" />
<LinearLayout
- android:id="@+id/date_time_group"
+ android:id="@+id/date_time_alarm_group"
android:layout_width="wrap_content"
- android:layout_height="25dp"
+ android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
- android:orientation="horizontal">
-
- <include layout="@layout/split_clock_view"
+ android:layout_marginTop="8dp"
+ android:layout_marginStart="16dp"
+ android:gravity="start"
+ android:orientation="vertical">
+ <LinearLayout
+ android:id="@+id/date_time_group"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="16dp"
- android:layout_marginTop="4dp"
- android:id="@+id/clock" />
+ android:layout_height="19dp"
+ android:orientation="horizontal">
- <com.android.systemui.statusbar.policy.DateView
- android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="6dp"
- android:layout_marginTop="4dp"
- android:drawableStart="@drawable/header_dot"
- android:drawablePadding="6dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
- android:textSize="@dimen/qs_time_collapsed_size"
- android:gravity="top"
- systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
+ <include layout="@layout/split_clock_view"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/clock" />
+
+ <com.android.systemui.statusbar.policy.DateView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="6dp"
+ android:drawableStart="@drawable/header_dot"
+ android:drawablePadding="6dp"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+ android:textSize="@dimen/qs_time_collapsed_size"
+ android:gravity="top"
+ systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ android:id="@+id/alarm_status_collapsed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawablePadding="6dp"
+ android:drawableStart="@drawable/ic_access_alarms_small"
+ android:textColor="#64ffffff"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
+ android:paddingStart="6dp"
+ android:gravity="top"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone" />
+ </LinearLayout>
<com.android.systemui.statusbar.AlphaOptimizedButton
android:id="@+id/alarm_status"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginTop="4dp"
- android:drawablePadding="6dp"
+ android:layout_height="20dp"
+ android:paddingTop="3dp"
+ android:drawablePadding="8dp"
android:drawableStart="@drawable/ic_access_alarms_small"
android:textColor="#64ffffff"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:paddingStart="6dp"
android:gravity="top"
android:background="?android:attr/selectableItemBackground"
android:visibility="gone" />
@@ -152,21 +169,13 @@
android:background="#0000"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="25dp"
+ android:layout_marginTop="28dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_alignParentEnd="true"
android:clipChildren="false"
android:clipToPadding="false" />
- <include
- android:id="@+id/qs_detail_header"
- layout="@layout/qs_detail_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="28dp"
- />
-
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/qs_detail_header_progress"
android:src="@drawable/indeterminate_anim"
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index b4543bdeb57f..94b099e5f446 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -28,10 +28,26 @@
android:clipChildren="false"
android:clipToPadding="false"
android:descendantFocusability="beforeDescendants"
+ android:layout_gravity="center"
android:gravity="center"
android:paddingStart="@dimen/recents_tv_grid_row_padding"
android:paddingEnd="@dimen/recents_tv_grid_row_padding"
- android:focusable="true"/>
+ android:focusable="true" />
-</com.android.systemui.recents.tv.views.RecentsTvView>
+ <View
+ android:id="@+id/pip_shade"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:background="#76000000"/>
+ <!-- Placeholder view to handle key events for PIP when it's focused.
+ Size and positions will be adjusted to comply with
+ config_pictureInPictureBoundsInRecents -->
+ <View
+ android:id="@+id/pip"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:visibility="invisible"
+ android:focusable="true" />
+</com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index deb8e91b5049..fa6575824552 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -26,29 +26,52 @@
android:layout_width="@dimen/recents_task_view_header_icon_width"
android:layout_height="@dimen/recents_task_view_header_icon_height"
android:layout_gravity="center_vertical|start"
- android:padding="9dp" />
- <TextView
- android:id="@+id/title"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="12dp"
+ android:paddingEnd="16dp" />
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="64dp"
- android:layout_marginEnd="112dp"
- android:textSize="16sp"
- android:textColor="#ffffffff"
- android:text="@string/recents_empty_message"
- android:fontFamily="sans-serif-medium"
- android:singleLine="true"
- android:maxLines="2"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ android:layout_marginStart="56dp"
+ android:layout_marginEnd="56dp"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textSize="16sp"
+ android:textColor="#ffffffff"
+ android:text="@string/recents_empty_message"
+ android:fontFamily="sans-serif-medium"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+ <TextView
+ android:id="@+id/sub_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textSize="11sp"
+ android:textColor="#ffffffff"
+ android:text="@string/recents_launch_non_dockable_task_label"
+ android:fontFamily="sans-serif-medium"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:visibility="gone" />
+ </LinearLayout>
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/move_task"
android:layout_width="@dimen/recents_task_view_header_button_width"
android:layout_height="@dimen/recents_task_view_header_button_height"
android:layout_marginEnd="@dimen/recents_task_view_header_button_width"
android:layout_gravity="center_vertical|end"
- android:padding="15dp"
+ android:padding="13dp"
android:src="@drawable/star"
android:background="?android:selectableItemBackground"
android:alpha="0"
@@ -58,7 +81,7 @@
android:layout_width="@dimen/recents_task_view_header_button_width"
android:layout_height="@dimen/recents_task_view_header_button_height"
android:layout_gravity="center_vertical|end"
- android:padding="15dp"
+ android:padding="13dp"
android:src="@drawable/recents_dismiss_light"
android:background="?android:selectableItemBackground"
android:alpha="0"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
index 10659a3e48e3..1becdab0e39f 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
@@ -23,13 +23,16 @@
android:layout_width="@dimen/recents_task_view_header_icon_width"
android:layout_height="@dimen/recents_task_view_header_icon_height"
android:layout_gravity="center_vertical|start"
- android:padding="9dp" />
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="12dp"
+ android:paddingEnd="16dp" />
<TextView
android:id="@+id/app_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="64dp"
+ android:layout_marginStart="56dp"
android:layout_marginEnd="112dp"
android:textSize="16sp"
android:textColor="#ffffffff"
@@ -44,7 +47,7 @@
android:layout_width="@dimen/recents_task_view_header_button_width"
android:layout_height="@dimen/recents_task_bar_height"
android:layout_gravity="center_vertical|end"
- android:padding="15dp"
+ android:padding="13dp"
android:background="?android:selectableItemBackground"
android:src="@drawable/recents_info_light" />
</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index cce07bdaa45d..818df3b46fd7 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,6 +42,7 @@
android:background="@null"
android:singleLine="true"
android:ellipsize="start"
+ android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
android:imeOptions="actionSend" />
<FrameLayout
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 89abe2dc2c4c..289b1d9db32c 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,32 +39,11 @@
android:clipToPadding="false"
android:clipChildren="false">
- <com.android.systemui.statusbar.phone.ObservableScrollView
- android:id="@+id/scroll_view"
+ <include
+ layout="@layout/qs_panel"
android:layout_width="@dimen/notification_panel_width"
- android:layout_height="match_parent"
- android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:scrollbars="none"
- android:overScrollMode="never"
- android:fillViewport="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <include
- layout="@layout/qs_panel"
- android:layout_marginTop="@dimen/status_bar_header_height_expanded"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <!-- A view to reserve space for the collapsed stack -->
- <!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
- <View
- android:id="@+id/reserve_notification_space"
- android:layout_height="@dimen/min_stack_height"
- android:layout_width="match_parent" />
- </LinearLayout>
- </com.android.systemui.statusbar.phone.ObservableScrollView>
+ android:layout_height="wrap_content"
+ android:layout_gravity="@integer/notification_panel_layout_gravity" />
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
@@ -90,12 +69,6 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
- <ViewStub
- android:id="@+id/status_bar_header"
- android:layout_width="@dimen/notification_panel_width"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_gravity="@integer/notification_panel_layout_gravity" />
-
<com.android.systemui.statusbar.AlphaOptimizedView
android:id="@+id/qs_navbar_scrim"
android:layout_height="96dp"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index f699fce27043..7df6bc695555 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -22,6 +22,7 @@
android:focusable="true"
android:clickable="true"
>
+
<com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -65,4 +66,9 @@
/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
+ <com.android.systemui.statusbar.notification.FakeShadowView
+ android:id="@+id/fake_shadow"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
</com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 62fdd4264841..e456984c5f36 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -23,6 +23,14 @@
android:clickable="true"
>
+ <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_height="match_parent"
+ />
+
<com.android.systemui.statusbar.NotificationBackgroundView
android:id="@+id/backgroundNormal"
android:layout_width="match_parent"
@@ -68,4 +76,9 @@
android:layout_height="wrap_content"
/>
+ <com.android.systemui.statusbar.notification.FakeShadowView
+ android:id="@+id/fake_shadow"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
</com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
new file mode 100644
index 000000000000..efe63d74b97e
--- /dev/null
+++ b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+<!-- extends LinearLayout -->
+<com.android.systemui.tuner.TunerZenModePanel
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tuner_zen_mode_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:visibility="gone"
+ android:orientation="vertical" >
+
+ <View
+ android:id="@+id/zen_embedded_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginBottom="12dp"
+ android:layout_marginTop="8dp"
+ android:background="@color/qs_tile_divider" />
+
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_marginStart="16dp"
+ android:id="@+id/tuner_zen_switch"
+ layout="@layout/qs_detail_header" />
+
+ <include layout="@layout/zen_mode_panel" />
+
+ <include
+ android:id="@+id/tuner_zen_buttons"
+ layout="@layout/qs_detail_buttons" />
+
+</com.android.systemui.tuner.TunerZenModePanel>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 3562c644e61e..1fec49e65b51 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -18,36 +18,93 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="end"
- android:paddingStart="10dp"
- android:paddingEnd="10dp"
- android:background="#88FFFFFF"
- android:gravity="center_vertical" >
-
- <Button android:id="@+id/full"
- android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:paddingTop="350dp"
+ android:background="#CC000000"
+ android:gravity="top|center_horizontal"
+ android:clipChildren="false">
+
+ <LinearLayout
+ android:layout_width="34dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/pip_fullscreen"
- android:textSize="10sp"
- android:focusable="true" />
+ android:layout_marginEnd="3dp"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:clipChildren="false">
+
+ <ImageView android:id="@+id/full_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_full_button" />
- <Button android:id="@+id/exit"
- android:layout_width="match_parent"
+ <TextView android:id="@+id/full_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_fullscreen"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:clipChildren="false" />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/play_pause"
+ android:layout_width="34dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/pip_exit"
- android:textSize="10sp"
- android:focusable="true" />
+ android:layout_marginStart="3dp"
+ android:layout_marginEnd="3dp"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:clipChildren="false">
+
+ <ImageView android:id="@+id/play_pause_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_pause_button" />
- <Button android:id="@+id/cancel"
- android:layout_width="match_parent"
+ <TextView android:id="@+id/play_pause_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_pause"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:clipChildren="false" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="34dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/pip_cancel"
- android:textSize="10sp"
- android:focusable="true" />
+ android:layout_marginStart="3dp"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:clipChildren="false">
+
+ <ImageView android:id="@+id/close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_close_button" />
+
+ <TextView android:id="@+id/close_desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:visibility="invisible"
+ android:text="@string/pip_close"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:clipChildren="false" />
+ </LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
index ef395558af64..f031bb466bd7 100644
--- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml
+++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
@@ -18,34 +18,43 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pip_onboarding"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C00288D1"
- android:gravity="center"
- android:orientation="vertical" >
+ android:gravity="top|center_horizontal"
+ android:orientation="vertical">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="30sp"
- android:textColor="@android:color/white"
- android:text="@string/pip_onboarding_title" />
+ <!-- A rectangle arounds the PIP.
+ Size and positions will be programatically set up
+ to comply with config_defaultPictureInPictureBounds. -->
<ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_sysbar_home" />
+ android:id="@+id/pip_outline"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:src="@drawable/tv_pip_outline" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="30dp"
- android:textSize="13sp"
- android:textColor="@android:color/white"
+ android:layout_marginTop="24dp"
+ android:fontFamily="sans-serif"
+ android:textSize="16sp"
+ android:textColor="#EEEEEE"
+ android:lineSpacingMultiplier="1.28"
android:text="@string/pip_onboarding_description" />
<Button
android:id="@+id/close"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="15sp"
+ android:layout_height="36dp"
+ android:layout_marginTop="24dp"
+ android:gravity="center"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:fontFamily="sans-serif-condensed"
+ android:textSize="16sp"
+ android:textColor="#026089"
android:textAllCaps="true"
- android:text="@string/pip_onboarding_button" />
+ android:text="@string/pip_onboarding_button"
+ android:background="#EEEEEE"
+ android:elevation="4dp" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index 6d9c48d44dc6..ebd362ca29fb 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -17,13 +17,38 @@
*/
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/guide_overlay"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:padding="3dp"
- android:textSize="13sp"
- android:textColor="#111111"
- android:background="#99EEEEEE"
- android:text="@string/pip_hold_home" />
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/guide_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:padding="3dp"
+ android:textSize="13sp"
+ android:textColor="#111111"
+ android:background="#99EEEEEE"
+ android:text="@string/pip_hold_home" />
+ <LinearLayout
+ android:id="@+id/guide_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:orientation="horizontal">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_fullscreen_white_24dp" />
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_pause_white_24dp" />
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_close_white" />
+ </LinearLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 34796cd8d53c..baec8ef344cd 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,25 +13,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/volume_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
android:background="@drawable/volume_dialog_background"
- android:translationZ="4dp" >
-
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_expand_button"
- style="@style/VolumeButtons"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_alignParentLeft="true"
- android:clickable="true"
- android:soundEffectsEnabled="false"
- android:src="@drawable/ic_volume_collapse_animation"
- tools:ignore="RtlHardcoded" />
+ android:translationZ="4dp"
+ android:paddingTop="8dp">
<LinearLayout
android:id="@+id/volume_dialog_content"
@@ -39,14 +29,34 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
- android:paddingTop="8dp" >
+ android:paddingStart="8dp">
<!-- volume rows added and removed here! :-) -->
+ <LinearLayout
+ android:id="@+id/volume_row_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/volume_button_size"
+ android:orientation="vertical"/>
<include layout="@layout/volume_zen_footer" />
<!-- Only shown from Tuner setting -->
- <include layout="@layout/zen_mode_panel" />
+ <include layout="@layout/tuner_zen_mode_panel" />
</LinearLayout>
+ <com.android.keyguard.AlphaOptimizedImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/volume_expand_button"
+ style="@style/VolumeButtons"
+ android:layout_width="@dimen/volume_button_size"
+ android:layout_height="@dimen/volume_button_size"
+ android:clickable="true"
+ android:soundEffectsEnabled="false"
+ android:src="@drawable/ic_volume_collapse_animation"
+ tools:ignore="RtlHardcoded"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"/>
+
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 91e931da1f3e..57bac4117e8d 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -13,13 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
- android:id="@+id/volume_dialog_row"
- android:paddingEnd="8dp"
- android:paddingStart="8dp" >
+ android:id="@+id/volume_dialog_row" >
<TextView
android:id="@+id/volume_row_header"
@@ -31,7 +30,8 @@
android:paddingBottom="0dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
- android:paddingTop="4dp" />
+ android:paddingTop="4dp"
+ android:visibility="gone" />
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/volume_row_icon"
@@ -55,12 +55,4 @@
android:paddingEnd="8dp"
android:paddingStart="8dp" />
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_settings_button"
- style="@style/VolumeButtons"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_alignParentEnd="true"
- android:layout_below="@id/volume_row_header" />
-
</RelativeLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index 28447d772c86..f30023dc8ef4 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -32,9 +32,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingEnd="8dp"
- android:paddingStart="8dp" >
+ android:orientation="horizontal" >
<ImageView
android:id="@+id/volume_zen_icon"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 3a514adb4ec2..61d4f14c6068 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Skermkiekie geneem."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Raak om jou skermkiekie te sien."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Kon nie skermkiekie neem nie."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan nie skermkiekie neem nie oor beperkte bergingspasie of die program of organisasie verbied dit."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan weens beperkte bergingspasie nie skermkiekie stoor nie."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-lêeroordrag-opsies"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Heg as \'n mediaspeler (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Heg as \'n kamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tyd."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tyd."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flitslig af."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flitslig aan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flitslig afgeskakel."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flitslig aangeskakel."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skermvaspen"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kon nie <xliff:g id="APP">%s</xliff:g> begin nie."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is in veiligmodus gedeaktiveer."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Geskiedenis"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vee uit"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Hierdie program steun nie veelvuldige vensters nie"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Program steun nie veelvuldige vensters nie"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Volkome\nstilte"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Net\nprioriteit"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Net\nwekkers"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Alles"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laai tans vinnig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laai tans stadig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktiveer versneller om skerm te verdeel deur op te swiep"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktiveer die verdeling van die skerm deur op te swiep"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiveer gebaar om skerm te verdeel deur van die Oorsig-knoppie af op te swiep"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Skakel aan"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Pas toe op <xliff:g id="TOPIC_NAME">%1$s</xliff:g>-kennisgewings"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Pas toe op alle kennisgewings van hierdie program af"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Geblokkeer"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Min belang"</string>
<string name="default_importance" msgid="8192107689995742653">"Normale belang"</string>
<string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
<string name="max_importance" msgid="5089005872719563894">"Dringende belang"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Moet nooit hierdie kennisgewings wys nie"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Wys onderaan die kennisgewinglys sonder \'n geluid"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Wys hierdie kennisgewings sonder geluide"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Wys boaan die kennisgewinglys en maak \'n geluid"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Verskyn vlugtig op die skerm en maak \'n geluid"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
<string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleure"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Aandkleure"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Gepasmaakte kleure"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Outo"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Onbekende kleure"</string>
- <string name="color_transform" msgid="6985460408079086090">"Kleurverandering"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Wys kitsinstellings-teël"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Aktiveer gepasmaakte omskepping"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Kleur en voorkoms"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nagmodus"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibreer skerm"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aan"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Af"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Skakel outomaties aan"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Skakel oor na Nagmodus soos gepas vir ligging en tyd van die dag"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Wanneer Nagmodus aan is"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Gebruik donkertema vir Android-bedryfstelsel"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Verstel tint"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Verstel helderheid"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Die donkertema word toegepas op kernareas van Android-bedryfstelsel wat gewoonlik in \'n ligtema gewys word, soos instellings."</string>
<string name="color_apply" msgid="9212602012641034283">"Pas toe"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Bevestig instellings"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Sommige kleurinstellings kan hierdie toestel onbruikbaar maak. Klik OK om hierdie kleurinstellings te bevestig; andersins sal hierdie instellings ná 10 sekondes teruggestel word."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Verminder werkverrigting en agtergronddata"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Tuis"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Onlangs"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Wys \'moenie steur nie\' in volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Laat volledige beheer van \'moenie steur nie\' toe in die volumedialoog."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume en Moenie steur nie"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Aktiveer \'moenie steur nie\' met volume af"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Wys saam met volumekontroles"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Moenie steur nie"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppieskortpad"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Verlaat \'moenie steur nie\' met volume op"</string>
<string name="battery" msgid="7498329822413202973">"Battery"</string>
<string name="clock" msgid="7416090374234785905">"Horlosie"</string>
<string name="headset" msgid="4534219457597457353">"Kopstuk"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Oorfone is gekoppel"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Kopstuk is gekoppel"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Aktiveer of deaktiveer ikone om op die statusbalk gewys te word."</string>
<string name="data_saver" msgid="5037565123367048522">"Databespaarder"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Databespaarder is aan"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Databespaarder is af"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Kies Sleutelbordknoppie"</string>
<string name="preview" msgid="9077832302472282938">"Voorskou"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om teëls by te voeg"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Wysig"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Tyd"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Wys ure, minute en sekondes"</item>
+ <item msgid="1427801730816895300">"Wys ure en minute (verstek)"</item>
+ <item msgid="3830170141562534721">"Moenie hierdie ikoon wys nie"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Wys altyd persentasie"</item>
+ <item msgid="2139628951880142927">"Wys persentasie wanneer gelaai word (verstek)"</item>
+ <item msgid="3327323682209964956">"Moenie hierdie ikoon wys nie"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Skermverdeler"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Skuif af"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Skuif op"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Skuif links"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Skuif regs"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 39a53b39c3d4..6d70c8a1a8ec 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ቅጽበታዊ ገጽ እይታ ተቀርጿል"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"የእርስዎን ቅጽበታዊ ገጽ እይታ ለማየት ይንኩ"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ቅጽበታዊ ገጽ እይታ መቅረጽ አልተቻለም::"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"በተገደበ የማከማቻ ቦታ ምክንያት ወይም በመተግበሪያው ወይም በድርጅትዎ ስለማይፈቀድ የማያ ገጽ ቅጽበታዊ እይታዎችን ማንሳት አይቻልም።"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ባለው የተገደበ የማከማቻ ቦታ ምክንያት ቅጽበታዊ ገጽ ዕይታን ማስቀመጥ አይችልም።"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም።"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"የUSB ፋይል ሰደዳ አማራጮች"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"እንደ ማህደረ አጫዋች (MTP) ሰካ"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"እንደ ካሜራ (PTP) ሰካ"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ተጨማሪ ጊዜ።"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ያነሰ ጊዜ።"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"የባትሪ ብርሃን ጠፍቷል።"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"የባትሪ ብርሃን በርቷል።"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"የባትሪ ብርሃን ጠፍቷል።"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"የባትሪ ብርሃን በርቷል።"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ማያ ገጽ መሰካት"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> በጥንቃቄ ሁነታ ውስጥ ታግዷል።"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ታሪክ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ጥረግ"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ይህ መተግበሪያ ብዝሃ-መስኮትን አይደግፍም"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"መተግበሪያው ብዝሃ-መስኮትን አይደግፍም"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"ሙሉ ለሙሉ\nጸጥታ"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ቅድሚያ ተሰጪ\nብቻ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ማንቂያዎች\nብቻ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ሁሉም"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ሁሉም\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ኃይል በፍጥነት በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ኃይል በዝግታ በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
<string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"የተከፈለ ማያ ገጽ ወደላይ አንሸራትቶ ማፍጠንን ያንቁ"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"የተከፈለ ማያ ገጽ ወደ ላይ የማንሸራተት ጣት ምልክትን ያንቁ"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ከአጠቃላይ እይታ አዝራሩ ወደ ላይ በማንሸራተት ወደ የተከፈለ ማያ ገጽ የሚገቡበትን የጣት ምልክት ያንቁ"</string>
<string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"አብራ"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"በ<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ማሳወቂያዎች ላይ ተግብር"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ከዚህ መተግበሪያ በሚመጡ ሁሉም ማሳወቂያዎች ላይ ተግብር"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"የታገዱ"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"ዝቅተኛ አስፈላጊነት"</string>
<string name="default_importance" msgid="8192107689995742653">"መደበኛ አስፈላጊነት"</string>
<string name="high_importance" msgid="1527066195614050263">"ከፍተኛ አስፈላጊነት"</string>
<string name="max_importance" msgid="5089005872719563894">"አስቸኳይ አስፈላጊነት"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"እነዚህን ማሳወቂያዎች በጭራሽ አታሳይ"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"በማሳወቂያ ዝርዝሩ ታችኛውን ክፍል ላይ በጸጥታ አሳይ"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"በማሳወቂያዎች ዝርዝር ላይኛው ክፍል ላይ አሳይና ድምፅ አሰማ"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"ወደ ገጸ ማያው ይመልከቱና ድምፅ ይቅረጹ"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
<string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"መደበኛ ቀለሞች"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"የለሊት ቀለሞች"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ብጁ ቀለሞች"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ራስ-ሰር"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"የማይታወቁ ቀለሞች"</string>
- <string name="color_transform" msgid="6985460408079086090">"የቀለም ማሻሻያ"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"የፈጣን ቅንብሮች ሰቅን አሳይ"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"ብጁ ቅየራን አንቃ"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"ቀለም እና መልክ"</string>
+ <string name="night_mode" msgid="3540405868248625488">"የሌሊት ሁነታ"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ማሳያን ይለኩ"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"በርቷል"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ጠፍቷል"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"በራስ-ሰር አብራ"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ለአካባቢው እና ለሰዓቱ ተገቢ በሆነ መልኩ ወደ የማታ ሁነታ ለውጥ"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"የማታ ሁነታ ሲበራ"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"ለAndroid ስርዓተ ክወና ጨለማ ገጽታን ተጠቀም"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ቅልም አስተካክል"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ብሩህነት አስተካክል"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ጨለማ ገጽታው እንደ ቅንብሮች ያሉ በመደበኛነት በብርሃን ገጽታ በሚታዩ የAndroid ስርዓተ ክወና ዋና ክፍሎች ላይ ይተገበራል።"</string>
<string name="color_apply" msgid="9212602012641034283">"ተግብር"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ቅንብሮችን ያረጋግጡ"</string>
<string name="color_revert_message" msgid="9116001069397996691">"አንዳንድ የቀለም ቅንብሮች ይህን መሣሪያ የማይጠቅም ሊያደርጉት ይችላሉ። እነዚህን የቀለም ቅንብሮች ለማረጋገጥ እሺ የሚለውን ጠቅ ያድርጉ፣ አለበለዚያ እነዚህ ቅንብሮች ከ10 ሰከንዶች በኋላ ዳግም ይጀምራሉ።"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ባትሪ (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"አፈጻጸምን እና የጀርባ ውሂብን ይቀንሳል"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"መነሻ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"የቅርብ ጊዜዎቹ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ተመለስ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"በድምጽ ውስጥ አትረብሽን አሳይ"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"በድምጽ ንግግር ውስጥ አትረብሽን ሙሉ ቁጥጥር ይፍቀዱ።"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ድምጽ እና አትረብሽ"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ድምጽ ሲቀነስ አትረብሽ አስገባ"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ከድምፅ መቆጣጠሪያዎች ጋር አሳይ"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"አትረብሽ"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"የድምፅ አዝራሮች አቋራጭ"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ድምጽ ሲጨመር አትረብሽን ትተህ ውጣ"</string>
<string name="battery" msgid="7498329822413202973">"ባትሪ"</string>
<string name="clock" msgid="7416090374234785905">"ሰዓት"</string>
<string name="headset" msgid="4534219457597457353">"ጆሮ ማዳመጫ"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"የጆር ማዳመጫዎች ተገናኝተዋል"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"የጆሮ ማዳመጫ ተገናኝቷል"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"አዶዎች በሁኔታ አሞሌ ላይ እንዲታዩ ወይም እንዳይታዩ ያንቁ ወይም ያሰናክሉ።"</string>
<string name="data_saver" msgid="5037565123367048522">"ውሂብ ቆጣቢ"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ውሂብ ቆጣቢ በርቷል"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ውሂብ ቆጣቢ ጠፍቷል"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"የቁልፍ ሰሌዳ አዝራር ይምረጡ"</string>
<string name="preview" msgid="9077832302472282938">"ቅድመ-እይታ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ሰቆችን ለማከል ይጎትቱ"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"አርትዕ"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"ሰዓት"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ሰዓቶችን፣ ደቂቃዎችን፣ ሴኮንዶችን አሳይ"</item>
+ <item msgid="1427801730816895300">"ሰዓቶችን እና ደቂቃዎችን አሳይ (ነባሪ)"</item>
+ <item msgid="3830170141562534721">"ይህን አዶ አታሳይ"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ሁልጊዜ መቶኛ አሳይ"</item>
+ <item msgid="2139628951880142927">"የባትሪ ኃይል በሚሞላበት ጊዜ መቶኛ አሳይ (ነባሪ)"</item>
+ <item msgid="3327323682209964956">"ይህን አዶ አታሳይ"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"የተከፈለ የማያ ገጽ ከፋይ"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ወደ ታች ሂድ"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ወደ ላይ ሂድ"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ወደ ግራ ሂድ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ወደ ቀኝ ሂድ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 12f64082405e..181f68be1384 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -77,7 +77,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"تم التقاط لقطة الشاشة."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"المس لعرض لقطة الشاشة."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"تعذر التقاط لقطة الشاشة."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"يتعذر التقاط لقطة شاشة نظرًا لأن مساحة التخزين المتاحة محدودة، أو نظرًا لعدم سماح التطبيق أو المؤسسة بذلك."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"يتعذر حفظ لقطة الشاشة نظرًا لأن مساحة التخزين المتاحة محدودة."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"غير مسموح بالتقاط لقطات شاشة نظرًا لإذن يتعلق بالتطبيق أو بالمؤسسة."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏خيارات نقل الملفات عبر USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏تحميل كمشغل وسائط (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"‏تحميل ككاميرا (PTP)"</string>
@@ -210,6 +211,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"وقت أكثر."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"وقت أقل."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"إيقاف الفلاش."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"تطبيق المصباح اليدوي غير متاح."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"تشغيل الفلاش."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"تم إيقاف الفلاش."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"تم تشغيل الفلاش."</string>
@@ -305,8 +307,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"تثبيت الشاشة"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"تعذر بدء <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"تم تعطيل <xliff:g id="APP">%s</xliff:g> في الوضع الآمن."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"السجلّ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"محو"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"لا يتيح هذا التطبيق النوافذ المتعددة."</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"لا يتيح التطبيق النوافذ المتعددة."</string>
<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>
@@ -336,8 +341,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"كتم الصوت\nتمامًا"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"الأولوية \nفقط"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"التنبيهات\nفقط"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"الكل"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"الكل\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"جارٍ الشحن سريعًا (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"جارٍ الشحن ببطء (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
@@ -450,38 +453,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
<string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"تمكين مسارع تقسيم الشاشة بالتمرير السريع لأعلى"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"تمكين إيماءة تقسيم الشاشة بالتمرير السريع لأعلى"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"تمكين الإيماء لإدخال تقسيم الشاشة من خلال التمرير السريع لأعلى من زر النظرة العامة"</string>
<string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"تشغيل"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"التطبيق على إشعارات <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"التطبيق في جميع الإشعارات من هذا التطبيق"</string>
+ <string name="show_silently" msgid="6841966539811264192">"عرض الإشعارات بدون تنبيه صوتي"</string>
+ <string name="block" msgid="2734508760962682611">"حظر كل الإشعارات"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"عدم كتم التنبيه الصوتي"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"عدم كتم التنبيه الصوتي أو حظر الإشعار"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"عرض الإعدادات الكاملة لمدى الأهمية"</string>
<string name="blocked_importance" msgid="5198578988978234161">"تم الحظر"</string>
+ <string name="min_importance" msgid="1901894910809414782">"الأقل أهمية"</string>
<string name="low_importance" msgid="4109929986107147930">"أهمية منخفضة"</string>
<string name="default_importance" msgid="8192107689995742653">"أهمية عادية"</string>
<string name="high_importance" msgid="1527066195614050263">"أهمية عالية"</string>
<string name="max_importance" msgid="5089005872719563894">"أهمية ملحَّة"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"عدم عرض هذه الإشعارات"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"العرض أسفل قائمة الإشعارات بدون تنبيه صوتي"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"عرض هذه الإشعارات بدون تنبيه صوتي"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"العرض أعلى قائمة الإشعارات مع تنبيه صوتي"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"الظهور سريعًا على الشاشة مع تنبيه صوتي"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"عرض الإشعار بأسفل قائمة الإشعارات بدون تنبيه صوتي"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"عرض هذه الإشعارات بدون تنبيه صوتي"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"السماح لهذه الإشعارات بإصدار تنبيهات صوتية"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"يتم عرض الإشعار بسرعة على الشاشة مع السماح بإصدار تنبيه صوتي"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"عرض هذا الإشعار بأعلى قائمة الإشعارات وعرضه بسرعة على الشاشة مع السماح بإصدار تنبيه صوتي"</string>
<string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
<string name="notification_done" msgid="5279426047273930175">"تم"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ألوان عادية"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ألوان ليلية"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ألوان مخصصة"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"تلقائي"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"ألوان غير معروفة"</string>
- <string name="color_transform" msgid="6985460408079086090">"إشعار الألوان"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"إظهار قسم الإعدادات السريعة"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"تمكين التحويل المخصص"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"اللون والمظهر"</string>
+ <string name="night_mode" msgid="3540405868248625488">"الوضع الليلي"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"معايرة الشاشة"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"تشغيل"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"إيقاف"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"التشغيل تلقائيًا"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"التبديل إلى الوضع الليلي بما يتناسب مع الموقع والوقت من اليوم"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"عند تشغيل الوضع الليلي"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"‏استخدام مظهر معتم لنظام التشغيل Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ضبط التلوين الخفيف"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ضبط السطوع"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"‏يتم تطبيق المظهر المعتم على المناطق الأساسية في نظام التشغيل Android والتي يتم عرضها عادة في مظهر مضيء، مثل الإعدادات."</string>
<string name="color_apply" msgid="9212602012641034283">"تطبيق"</string>
<string name="color_revert_title" msgid="4746666545480534663">"تأكيد الإعدادات"</string>
<string name="color_revert_message" msgid="9116001069397996691">"يمكن أن تتسبب بعض إعدادات الألوان في تعطيل إمكانية استخدام الجهاز. يمكنك النقر على \"موافق\" لتأكيد إعدادات الألوان هذه، وإلا فستتم إعادة تعيين هذه الإعدادات بعد 10 ثوانٍ."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"البطارية (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"لخفض مستوى الأداء وبيانات الخلفية"</string>
@@ -489,21 +501,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"الشاشة الرئيسية"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"الأحدث"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"رجوع"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"إظهار خيار \"الرجاء عدم الإزعاج\" في مستوى الصوت"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"السماح بالتحكم الكامل في خيار \"الرجاء عدم الإزعاج\" ضمن مربع حوار مستوى الصوت."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"إعدادات مستوى الصوت و\"الرجاء عدم الإزعاج\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"تشغيل \"الرجاء عدم الإزعاج\" عند خفض مستوى الصوت"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"عرض مع عناصر التحكم في مستوى الصوت"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"الرجاء عدم الإزعاج"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"اختصار أزرار مستوى الصوت"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"تعطيل \"الرجاء عدم الإزعاج\" عند رفع مستوى الصوت"</string>
<string name="battery" msgid="7498329822413202973">"البطارية"</string>
<string name="clock" msgid="7416090374234785905">"ساعة"</string>
<string name="headset" msgid="4534219457597457353">"سماعة الرأس"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"تم توصيل سماعات رأس"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"تم توصيل سماعات رأس"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"يمكنك تمكين أو تعطيل الرموز بحيث لا تظهر في شريط الحالة."</string>
<string name="data_saver" msgid="5037565123367048522">"توفير البيانات"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"تم تشغيل توفير البيانات"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"تم تعطيل توفير البيانات"</string>
<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>
@@ -525,4 +536,22 @@
<string name="select_keycode" msgid="7413765103381924584">"تحديد زر لوحة المفاتيح"</string>
<string name="preview" msgid="9077832302472282938">"معاينة"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"اسحب لإضافة مربعات"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"تعديل"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"الوقت"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"عرض الساعات والدقائق والثواني"</item>
+ <item msgid="1427801730816895300">"عرض الساعات والدقائق (افتراضي)"</item>
+ <item msgid="3830170141562534721">"عدم عرض هذا الرمز"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"عرض النسبة المئوية دائمًا"</item>
+ <item msgid="2139628951880142927">"عرض النسبة المئوية عند الشحن (افتراضي)"</item>
+ <item msgid="3327323682209964956">"عدم عرض هذا الرمز"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"غير ذلك"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"أداة تقسيم الشاشة"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"نقل لأسفل"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"نقل لأعلى"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"نقل لليسار"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"نقل لليمين"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 2cae44032dd1..9e88f35e63f1 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinşot çəkildi."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Skrinşotunuza baxmaq üçün toxunun"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Skrinşot götürülə bilinmədi."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Yaddaş ehtiyatının az olması səbəbindən skrinşot çəkmək olmur və ya bunu etmək ya tətbiq, ya da şirkət tərəfindən qadağan olunub."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Yaddaş ehtiyatının az olması səbəbindən skrinşotu yadda saxlamaq olmur."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Tətbiq və ya təşkilatınız tərəfindən skrinşot çəkməyə icazə verilmir."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB fayl transferi seçimləri"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer (MTP) kimi montaj edin"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera kimi birləşdir (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha çox vaxt."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha az vaxt."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Fənər deaktiv."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Fənər əlçatan deyil."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Fənər aktiv."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Fənər deaktivdir."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Fənər aktivdir."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sancağı"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"axtarış"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlana bilmir."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> güvənli rejimdə deaktiv edildi."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Tarixçə"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Təmizləyin"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu tətbiq çoxsaylı pəncərəni dəstəkləmir"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu tətbiq çoxsaylı pəncərəni dəstəkləyir"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Tam\nsakitlik"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnız\nprioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnız\nalarmlar"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Bütün"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Bütün\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sürətli qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ləng qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
<string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Bölünmüş ekran sürüşdürməsi akseleratorunu aktiv edin"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bölünmüş ekran sürüşdürməsi aktiv edin"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Jestlərin icmal düyməsindən yuxarı sürüşdürərək bölünmüş ekrana daxil olmasını aktiv edin"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivləşdirin"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> bildirişlərinə müraciət edin"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Bu tətbiqdən olan bütün bildirişlərə müraciət edin"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Bildirişləri səssiz göstərin"</string>
+ <string name="block" msgid="2734508760962682611">"Bütün bildirişləri blok edin"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Səssiz etməyin"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Səssiz və ya blok etməyin"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tam əhəmiyyətlilik ayarlarını göstərin"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bloklanmış"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Minimum əhəmiyyətli"</string>
<string name="low_importance" msgid="4109929986107147930">"Az əhəmiyyətli"</string>
<string name="default_importance" msgid="8192107689995742653">"Normal əhəmiyyətli"</string>
<string name="high_importance" msgid="1527066195614050263">"Çox əhəmiyyətli"</string>
<string name="max_importance" msgid="5089005872719563894">"Təcili əhəmiyyətli"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirişləri heç vaxt göstərməyin"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildişləri səssiz göstərin"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Bildirişlər siyahısında yuxarıda göstərin və səsli edin"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Ekranda nəzər salın və səsli edin"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildişləri səssiz göstərin"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirişi səsli edin"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Ekranda nəzər salın və səsə icazə verin"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Bildirişlər siyahısında yuxarıda göstərin, ekrana nəzər salın və səsə icazə verin"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
<string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normal rənglər"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Gecə rəngləri"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Xüsusi rənglər"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Avto"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Naməlum rəng"</string>
- <string name="color_transform" msgid="6985460408079086090">"Rəng modifikasiyası"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Cəld ayarlar örtüyünü göstərin"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Xüsusi dəyişikliyi aktiv edin"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Rəng və görünüş"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Gecə rejimi"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Ekranı kalibrləyin"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aktiv"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Deaktiv"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Avtomatik aktivləşdirin"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Məkana və günün vaxtına uyğun olaraq Gecə Rejiminə keçin"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Gecə Rejimi aktiv olduqda"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS üçün tünd tema istifadə edin"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Çaları nizamlayın"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Parlaqlığı nizamlayın"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tünd tema Android OS sisteminin adətən işıqlı tema göstərilən Ayarlar kimi əsas sahələri üçün tətbiq edilir."</string>
<string name="color_apply" msgid="9212602012641034283">"Tətbiq edin"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Ayarları təsdiq edin"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Bəzi renk ayarları bu cihazı yararsız edə bilər. Bu rənk ayarlarını təsdiq etmək üçün OK basın, əks halda bu ayarlar 10 saniyə sonra sıfırlanacaq."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Enerji (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Əsas səhifə"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Sonuncular"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Səsdə \"narahat etməyin\" rejimini göstərin"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Səs dioloqunda \"narahat etməyin\" rejiminin tam nərarətinə icazə verin."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Səs və \"narahat etməyin\" rejimi"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Aşağı səsdə \"narahat etməyin\" rejimini daxil edin"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Həcm nəzarəti ilə göstərin"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Narahat etməyin"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Səs düymələri qısayolu"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Yuxarı səsdə \"narahat etməyin\" rejimini daxil edin"</string>
<string name="battery" msgid="7498329822413202973">"Batareya"</string>
<string name="clock" msgid="7416090374234785905">"Saat"</string>
<string name="headset" msgid="4534219457597457353">"Qulaqlıq"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Qulaqlıq qoşulub"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Qulaqlıq qoşulub"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"İkonaların status panelində görünməsini aktiv və ya deaktiv edin."</string>
<string name="data_saver" msgid="5037565123367048522">"Data Qənaəti"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Qənaəti aktivdir"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Qənaəti deaktivdir"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatura Düyməsi Seçin"</string>
<string name="preview" msgid="9077832302472282938">"Önizləmə"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Xanalar əlavə etmək üçün sürüşdürün"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Redaktə edin"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Vaxt"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Saat, dəqiqə və saniyəni göstərin"</item>
+ <item msgid="1427801730816895300">"Saat və dəqiqəni göstərin (defolt)"</item>
+ <item msgid="3830170141562534721">"Bu piktoqramı göstərməyin"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Faizi həmişə göstərin"</item>
+ <item msgid="2139628951880142927">"Enerji dolan zaman faizi göstərin (defolt)"</item>
+ <item msgid="3327323682209964956">"Bu piktoqramı göstərməyin"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Digər"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Bölünmüş ekran ayırıcısı"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Aşağıya keçin"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yuxarıya keçin"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola köçürün"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa köçürün"</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 6fe44848acf0..2e4724b1a4c7 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -74,7 +74,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Snimak ekrana je napravljen."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite da biste videli snimak ekrana."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nije moguće napraviti snimak ekrana."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Nije moguće snimiti ekran zbog nedovoljne memorije ili to ne dozvoljava aplikacija ili organizacija."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Čuvanje snimka ekrana nije uspelo zbog ograničenog memorijskog prostora."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikacija ili organizacija ne dozvoljavaju pravljenje snimaka ekrana."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prenosa datoteka"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Priključi kao medija plejer (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Priključi kao kameru (PTP)"</string>
@@ -207,6 +208,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Baterijska lampa je isključena."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Baterijska lampa je uključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Baterijska lampa je isključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Baterijska lampa je uključena."</string>
@@ -302,8 +305,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kačenje ekrana"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g> nije uspelo."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je onemogućena u bezbednom režimu."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Istorija"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Obriši"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ova aplikacija ne podržava režim sa više prozora"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava režim sa više prozora"</string>
<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>
@@ -333,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\npriorit. prekidi"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Sve"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Svi\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (pun je za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo se puni (napuniće se za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo se puni (napuniće se za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Sekunde na satu se prikazuju na statusnoj traci. To može da utiče na trajanje baterije."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Preuredi Brza podešavanja"</string>
<string name="show_brightness" msgid="6613930842805942519">"Prikaži osvetljenost u Brzim podešavanjima"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogući ubrzavač za prevlačenje nagore za podeljeni ekran"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret za prevlačenje nagore za podeljeni ekran"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućava pokret za prelazak na podeljeni ekran prevlačenjem nagore od dugmeta Pregled"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Primeni na obaveštenja o temi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Primeni na sva obaveštenja iz ove aplikacije"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blokirana"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
<string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
<string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
<string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Ova obaveštenja se prikazuju bez zvuka"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Prikazuju se u vrhu liste obaveštenja i emituje se zvuk"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Nakratko se prikazuju na ekranu i emituje se zvuk"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normalne boje"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatski"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
- <string name="color_transform" msgid="6985460408079086090">"Izmena boja"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži pločicu Brza podešavanja"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Omogući prilagođenu transformaciju"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Noćni režim"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrišite ekran"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Uključeno"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Isključeno"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Automatski uključi"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Pređite na noćni režim u zavisnosti od lokacije i doba dana"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kada je noćni režim uključen"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Koristi tamnu temu za Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Prilagodi senku"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Prilagodi osvetljenost"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tamna tema se primenjuje na ključne delove Android OS-a koji se obično prikazuju u svetloj temi, poput Podešavanja."</string>
<string name="color_apply" msgid="9212602012641034283">"Primeni"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Potvrdite podešavanja"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Neka podešavanja boja mogu da učine uređaj neupotrebljivim. Kliknite na Potvrdi da biste potvrdili ova podešavanja boja, pošto će se u suprotnom ova podešavanja resetovati nakon 10 sekundi."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Baterija (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje performanse i pozadinske podatke"</string>
@@ -486,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni sadržaj"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Prikaži podešavanje Ne uznemiravaj u dijalogu za jačinu zvuka"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Dozvoljava potpunu kontrolu podešavanja Ne uznemiravaj u dijalogu za jačinu zvuka."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Jačina zvuka i Ne uznemiravaj"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Uđi u režim Ne uznemiravaj kada je zvuk utišan"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži sa kontrolama jačine zvuka"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za jačinu zvuka"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Izađi iz režima Ne uznemiravaj kada je zvuk pojačan"</string>
<string name="battery" msgid="7498329822413202973">"Baterija"</string>
<string name="clock" msgid="7416090374234785905">"Sat"</string>
<string name="headset" msgid="4534219457597457353">"Naglavne slušalice"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalice su povezane"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Naglavne slušalice su povezane"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Omogućite ili onemogućite prikazivanje ikona na statusnoj traci."</string>
<string name="data_saver" msgid="5037565123367048522">"Ušteda podataka"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ušteda podataka je uključena"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ušteda podataka je isključena"</string>
<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>
@@ -522,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Izaberite dugme za tastaturu"</string>
<string name="preview" msgid="9077832302472282938">"Pregled"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Prevucite da biste dodali pločice"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Izmeni"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Vreme"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Prikaži sate, minute i sekunde"</item>
+ <item msgid="1427801730816895300">"Prikaži sate i minute (podrazumevano)"</item>
+ <item msgid="3830170141562534721">"Ne prikazuj ovu ikonu"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Uvek prikazuj procenat"</item>
+ <item msgid="2139628951880142927">"Prikaži procenat tokom punjenja (podrazumevano)"</item>
+ <item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Razdelnik podeljenog ekrana"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomeri nadole"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomeri ulevo"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomeri udesno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 1fa969e35985..c97a6a52b288 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Екранната снимка е заснета."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Докоснете, за да видите екранната си снимка."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Екранната снимка не можа да бъде заснета."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Не може да се направи екр. снимка поради недостиг на място или забрана от прилож. или организацията ви."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Екранната снимка не може да се запази поради ограничено място в хранилището."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Правенето на екранни снимки не е разрешено от приложението или организацията ви."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Опции за пренос на файлове чрез USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Свързване като медиен плейър (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Свързване като камера (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повече време."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"По-малко време."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фенерчето е изключено."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фенерчето е включено."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фенерчето е изключено."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фенерчето е включено."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"фиксиране на екрана"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложението <xliff:g id="APP">%s</xliff:g> е деактивирано в безопасния режим."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"История"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Изчистване"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Това приложение не поддържа няколко прозореца"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Приложението не поддържа няколко прозореца"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Пълна\nтишина"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nс приоритет"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nбудилници"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Всички"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Всички\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Зарежда се бързо (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Зарежда се бавно (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
<string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Актив. на жеста за разделен екран с прек. на пръст нагоре"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделяне на екрана с прекарване на пръст нагоре: Активиране"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Активиране на жеста за влизане в режим на разделен екран чрез прокарване на пръст нагоре от бутона за общ преглед"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включване"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Прилагане за известията на тема „<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Прилагане за всички известия от това приложение"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Малка важност"</string>
<string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
<string name="high_importance" msgid="1527066195614050263">"Голяма важност"</string>
<string name="max_importance" msgid="5089005872719563894">"Неотложна важност"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Тези известия не се показват"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Беззвучно показване най-долу в списъка с известия"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Тези известия се показват без звук"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Показване най-горе в списъка с известия и издаване на звуков сигнал"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Показване на екрана и издаване на звуков сигнал"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Нормални цветове"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Нощни цветове"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Персонализирани цветове"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Автоматично"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Неизвестни цветове"</string>
- <string name="color_transform" msgid="6985460408079086090">"Промяна на цветовете"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показване на плочката за бързи настройки"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Активиране на персонализираното трансформиране"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Цвят и облик"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Нощен режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Калибриране на дисплея"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Вкл."</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Изкл."</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматично включване"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Превключване към нощен режим според местоположението и часа от денонощието"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"При включен нощен режим"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Ползв. на тъмната тема за опер. с-ма Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Коригиране на нюансирането"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Коригиране на яркостта"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Тъмната тема се прилага към основните области на операционната система Android, които обикновено се показват със светла тема, като например настройките."</string>
<string name="color_apply" msgid="9212602012641034283">"Прилагане"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Потвърждаване на настройките"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Някои настройки за цветовете могат да направят това устройство неизползваемо. За да ги потвърдите, кликнете върху „OK“. В противен случай те ще бъдат нулирани след 10 секунди."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Батерия (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Намалява ефективността и данните на заден план"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Начало"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Скорошни"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Показване на „Не безпокойте“ в прозореца за силата на звука"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Достъп до всички опции за управление на „Не безпокойте“ в диалоговия прозорец за силата на звука."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Сила на звука и „Не безпокойте“"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Вкл. на „Не безпокойте“ при намаляване на силата на звука"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показване с контролите за силата на звука"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не безпокойте"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Пряк път към бутоните за силата на звука"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Изкл. на „Не безпокойте“ при увеличаване на силата на звука"</string>
<string name="battery" msgid="7498329822413202973">"Батерия"</string>
<string name="clock" msgid="7416090374234785905">"Часовник"</string>
<string name="headset" msgid="4534219457597457353">"Слушалки"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Слушалките (без микрофон) са свързани"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Слушалките са свързани"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Активиране или деактивиране на показването на икони в лентата на състоянието."</string>
<string name="data_saver" msgid="5037565123367048522">"Икономия на данни"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Функцията „Икономия на данни“ е включена"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Функцията „Икономия на данни“ е изключена"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Избиране на клавиш от клавиатурата"</string>
<string name="preview" msgid="9077832302472282938">"Визуализация"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Преместете с плъзгане, за да добавите плочки"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Редактиране"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Час"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Показване на часовете, минутите и секундите"</item>
+ <item msgid="1427801730816895300">"Показване на часовете и минутите (по подразбиране)"</item>
+ <item msgid="3830170141562534721">"Тази икона да не се показва"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Процентът винаги да се показва"</item>
+ <item msgid="2139628951880142927">"Процентът да се показва при зареждане (по подразбиране)"</item>
+ <item msgid="3327323682209964956">"Тази икона да не се показва"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Разделител в режима за разделен екран"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Преместване надолу"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместване нагоре"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместване наляво"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместване надясно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 92b7bccbbbf2..f59f3cab2567 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"স্ক্রীনশট নেওয়া হযেছে৷"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"আপনার স্ক্রীনশট দেখতে স্পর্শ করুন৷"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"সঞ্চয়স্থান সীমিত হওয়ার ফলে স্ক্রীনশট নেওয়া যাবে না, অথবা এটি অ্যাপ্লিকেশানটি অথবা আপনার প্রতিষ্ঠানের দ্বারা অনুমোদিত নয়৷"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"সঞ্চয়স্থান সীমিত থাকায় স্ক্রীনশটটি সংরক্ষণ করা যাবে না৷"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"অ্যাপ্লিকেশান বা আপনার প্রতিষ্ঠান স্ক্রীনশটগুলি নেওয়া অনুমতি দেয়নি৷"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ফাইল স্থানান্তরের বিকল্পগুলি"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"একটি মিডিয়া প্লেয়ার হিসাবে মাউন্ট করুন (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"একটি ক্যামেরা হিসাবে মাউন্ট করুন (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"বেশি সময়।"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"কম সময়।"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ফ্ল্যাশলাইট বন্ধ আছে।"</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ফ্ল্যাশলাইট অনুপলব্ধ৷"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ফ্ল্যাশলাইট চালু আছে।"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ফ্ল্যাশলাইট বন্ধ হয়েছে।"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ফ্ল্যাশলাইট চালু হয়েছে।"</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"স্ক্রীন পিন করা"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"নিরাপদ মোডে <xliff:g id="APP">%s</xliff:g> অক্ষম করা হয়েছে৷"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ইতিহাস"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"সাফ করুন"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"এই অ্যাপ্লিকেশানটি মাল্টি-উইন্ডো সমর্থন করে না"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"অ্যাপ্লিকেশানগুলি মাল্টি-উইন্ডো সমর্থন করে না"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"একদম\nনিরব"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"শুধুমাত্র\nঅগ্রাধিকার"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"শুধুমাত্র\nঅ্যালার্মগুলি"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"সমস্ত"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"সমস্ত\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"দ্রুত চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ধীরে ধীরে চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
<string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"অ্যাকসেলেটর উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীন সক্ষম করুন"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীনে প্রবেশ করার অঙ্গভঙ্গি সক্ষম করুন"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\'এক নজরে\' বোতাম থেকে উপরের দিকে সোয়াইপ করে, বিভক্ত-স্ক্রীনে প্রবেশ করতে অঙ্গভঙ্গি সক্ষম করুন"</string>
<string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth চালু করবেন?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে Bluetooth চালু করতে হবে।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"চালু করুন"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> বিজ্ঞপ্তিগুলিতে প্রয়োগ করুন"</string>
- <string name="apply_to_app" msgid="363016783939815960">"এই অ্যাপ্লিকেশনের থেকে সব বিজ্ঞপ্তিতে প্রয়োগ করুন"</string>
+ <string name="show_silently" msgid="6841966539811264192">"নীরবভাবে বিজ্ঞপ্তিগুলি দেখায়"</string>
+ <string name="block" msgid="2734508760962682611">"সমস্ত বিজ্ঞপ্তি অবরুদ্ধ করুন"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"নীরব করবেন না"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"নীরব বা অবরুদ্ধ করবেন না"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"সম্পূর্ণ গুরুত্বপূর্ণ সেটিংস দেখায়"</string>
<string name="blocked_importance" msgid="5198578988978234161">"অবরুদ্ধ"</string>
+ <string name="min_importance" msgid="1901894910809414782">"ন্যূনতম গুরুত্ব"</string>
<string name="low_importance" msgid="4109929986107147930">"কম গুরুত্ব"</string>
<string name="default_importance" msgid="8192107689995742653">"সাধারণ গুরুত্ব"</string>
<string name="high_importance" msgid="1527066195614050263">"বেশি গুরুত্ব"</string>
<string name="max_importance" msgid="5089005872719563894">"জরুরি গুরুত্ব"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"এই বিজ্ঞপ্তিগুলি কখনোই দেখানো হবে না"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে দেখানো হয়"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"নিঃশব্দে এই বিজ্ঞপ্তিগুলি দেখানো হয়"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং শব্দ করে"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"স্ক্রীনের উপরে দেখানো হয় এবং শব্দ করে"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে দেখানো হয়"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"নিঃশব্দে এই বিজ্ঞপ্তিগুলি দেখানো হয়"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"এই বিজ্ঞপ্তিগুলিকে শব্দ করার মঞ্জুরি দেয়"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"স্ক্রীনের উপরে প্রদর্শিত এবং শব্দ করার মঞ্জুরি দেয়"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং স্ক্রীনের উপরে প্রদর্শিত এবং শব্দ করার মঞ্জুরি দেয়"</string>
<string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
<string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"স্বাভাবিক রঙ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"রাতের রঙ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"কাস্টম রঙ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"স্বয়ংক্রিয়ভাবে"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"অজানা রঙ"</string>
- <string name="color_transform" msgid="6985460408079086090">"রঙ সংশোধন"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"দ্রুত সেটিংস টাইল দেখান"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"কাস্টম রূপান্তর সক্ষম করুন"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"রঙ এবং চেহারা"</string>
+ <string name="night_mode" msgid="3540405868248625488">"রাতের মোড"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"প্রদর্শন ক্যালিব্রেট করুন"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"চালু আছে"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"বন্ধ আছে"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"স্বয়ংক্রিয়ভাবে চালু করুন"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"অবস্থান এবং সময়ের হিসাবে উপযুক্ত রাতের মোডে পাল্টান"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"যখন রাতের মোড চালু থাকবে"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS এর জন্য গাঢ় থিম ব্যবহার করুন"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"টিন্ট সমন্বয় করুন"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"উজ্জ্বলতা সমন্বয় করুন"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Android OS এর মূল অংশগুলিতে গাঢ় থিম প্রয়োগ করা হয়েছে যেটা সাধারণত একটি হালকা থিমে প্রদর্শিত হয়, যেমন সেটিংস৷"</string>
<string name="color_apply" msgid="9212602012641034283">"প্রয়োগ করুন"</string>
<string name="color_revert_title" msgid="4746666545480534663">"সেটিংস নিশ্চিত করুন"</string>
<string name="color_revert_message" msgid="9116001069397996691">"কিছু রঙের সেটিংস এই ডিভাইসকে ব্যবহারের অযোগ্য করে দিতে পারে৷ এই রঙের সেটিংস নিশ্চিত করতে ওকে এ ক্লিক করুন, অন্যথায় ১০ সেকেন্ড পরে এই সেটিংস পুনরায় সেট হবে৷"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ব্যাটারি (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"হোম"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"সাম্প্রতিকগুলি"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"পিছনে"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"ভলিউমে \'বিরক্ত করবেন না\' দেখাবেন না"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ভলিউম ডায়লগে \"বিরক্ত করবেন না\" এর পূর্ণ নিয়ন্ত্রণের মঞ্জুরি দিন৷"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ভলিউম এবং \'বিরক্ত করবেন না\'"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ভলিউম কমানোর মাধ্যেমে \'বিরক্ত করবেন না\' চালু করুন"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ভলিউম নিয়ন্ত্রণ সহ দেখান"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"বিরক্ত করবেন না"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ভলিউম বোতামের শর্টকাট"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ভলিউম বাড়ানোর মাধ্যেমে \'বিরক্ত করবেন না\' থেকে প্রস্থান করুন"</string>
<string name="battery" msgid="7498329822413202973">"ব্যাটারি"</string>
<string name="clock" msgid="7416090374234785905">"ঘড়ি"</string>
<string name="headset" msgid="4534219457597457353">"হেডসেট"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"হেডফোনগুলি সংযুক্ত হয়েছে"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"হেডসেট সংযুক্ত হয়েছে"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"স্থিতি দন্ডে দেখানোর জন্য আইকনগুলিকে সক্ষম বা অক্ষম করুন৷"</string>
<string name="data_saver" msgid="5037565123367048522">"ডেটা সেভার"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ডেটা সেভার চালু আছে"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ডেটা সেভার বন্ধ আছে"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"কীবোর্ডের বোতাম নির্বাচন করুন"</string>
<string name="preview" msgid="9077832302472282938">"পূর্বরূপ দেখুন"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"টাইলগুলি যোগ করার জন্য টেনে আনুন"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা করুন"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"সময়"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ঘন্টা, মিনিট, এবং সেকেন্ড দেখান"</item>
+ <item msgid="1427801730816895300">"ঘন্টা এবং মিনিট দেখান (ডিফল্ট)"</item>
+ <item msgid="3830170141562534721">"এই আইকনটি দেখাবেন না"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"সর্বদা শতাংশ দেখান"</item>
+ <item msgid="2139628951880142927">"চার্জ করার সময় শতাংশ দেখান (ডিফল্ট)"</item>
+ <item msgid="3327323682209964956">"এই আইকনটি দেখাবেন না"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"অন্যান্য"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"বিভক্ত-স্ক্রীন বিভাজক"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"নীচে সরান"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"উপরে সরান"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বামে সরান"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ডানে সরান"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 10eed980a833..865b1adc1f4e 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -19,951 +19,511 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
- <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
- <skip />
- <!-- no translation found for status_bar_recent_remove_item_title (6026395868129852968) -->
- <skip />
- <!-- no translation found for status_bar_recent_inspect_item_title (7793624864528818569) -->
- <skip />
- <!-- no translation found for status_bar_no_recent_apps (7374907845131203189) -->
- <skip />
- <!-- no translation found for status_bar_accessibility_dismiss_recents (4576076075226540105) -->
- <skip />
- <!-- no translation found for status_bar_accessibility_recent_apps (9138535907802238759) -->
- <!-- no translation found for status_bar_no_notifications_title (4755261167193833213) -->
- <skip />
- <!-- no translation found for status_bar_ongoing_events_title (1682504513316879202) -->
- <skip />
- <!-- no translation found for status_bar_latest_events_title (6594767438577593172) -->
- <skip />
- <!-- no translation found for battery_low_title (6456385927409742437) -->
- <skip />
- <!-- no translation found for battery_low_percent_format (2900940511201380775) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_saver_started (6859235584035338833) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
- <!-- no translation found for invalid_charger_title (3515740382572798460) -->
- <skip />
- <!-- no translation found for invalid_charger_text (5474997287953892710) -->
- <skip />
- <!-- no translation found for battery_low_why (4553600287639198111) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_title (5299585433050361634) -->
- <skip />
- <!-- no translation found for battery_saver_confirmation_ok (7507968430447930257) -->
- <skip />
- <!-- no translation found for battery_saver_start_action (5576697451677486320) -->
- <skip />
- <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
- <skip />
- <!-- no translation found for status_bar_settings_wifi_button (1733928151698311923) -->
- <skip />
- <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
- <skip />
- <!-- no translation found for status_bar_settings_mute_label (554682549917429396) -->
- <skip />
- <!-- no translation found for status_bar_settings_auto_brightness_label (511453614962324674) -->
- <skip />
- <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
- <skip />
- <!-- no translation found for bluetooth_tethered (7094101612161133267) -->
- <skip />
- <!-- no translation found for status_bar_input_method_settings_configure_input_methods (3504292471512317827) -->
- <skip />
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
- <!-- no translation found for usb_device_permission_prompt (834698001271562057) -->
- <skip />
- <!-- no translation found for usb_accessory_permission_prompt (5171775411178865750) -->
- <skip />
- <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
- <skip />
- <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
- <skip />
- <!-- no translation found for usb_accessory_uri_prompt (513450621413733343) -->
- <skip />
- <!-- no translation found for title_usb_accessory (4966265263465181372) -->
- <skip />
- <!-- no translation found for label_view (6304565553218192990) -->
- <skip />
- <!-- no translation found for always_use_device (1450287437017315906) -->
- <skip />
- <!-- no translation found for always_use_accessory (1210954576979621596) -->
- <skip />
- <!-- no translation found for usb_debugging_title (4513918393387141949) -->
- <skip />
- <!-- no translation found for usb_debugging_message (2220143855912376496) -->
- <skip />
- <!-- no translation found for usb_debugging_always (303335496705863070) -->
- <skip />
- <!-- no translation found for usb_debugging_secondary_user_title (6353808721761220421) -->
- <skip />
- <!-- no translation found for usb_debugging_secondary_user_message (8572228137833020196) -->
- <skip />
- <!-- no translation found for compat_mode_on (6623839244840638213) -->
- <skip />
- <!-- no translation found for compat_mode_off (4434467572461327898) -->
- <skip />
- <!-- no translation found for screenshot_saving_ticker (7403652894056693515) -->
- <skip />
- <!-- no translation found for screenshot_saving_title (8242282144535555697) -->
- <skip />
- <!-- no translation found for screenshot_saving_text (2419718443411738818) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (6461865960961414961) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (1152839647677558815) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (705781116746922771) -->
- <skip />
- <!-- no translation found for screenshot_failed_text (1260203058661337274) -->
- <skip />
- <!-- no translation found for usb_preference_title (6551050377388882787) -->
- <skip />
- <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
- <skip />
- <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
- <skip />
- <!-- no translation found for installer_cd_button_title (2312667578562201583) -->
- <skip />
- <!-- no translation found for accessibility_back (567011538994429120) -->
- <skip />
- <!-- no translation found for accessibility_home (8217216074895377641) -->
- <skip />
- <!-- no translation found for accessibility_menu (316839303324695949) -->
- <skip />
- <!-- no translation found for accessibility_recent (5208608566793607626) -->
- <skip />
- <!-- no translation found for accessibility_search_light (1103867596330271848) -->
- <skip />
- <!-- no translation found for accessibility_camera_button (8064671582820358152) -->
- <skip />
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
- <!-- no translation found for accessibility_voice_assist_button (487611083884852965) -->
- <skip />
- <!-- no translation found for accessibility_unlock_button (128158454631118828) -->
- <skip />
- <!-- no translation found for accessibility_unlock_button_fingerprint (8214125623493923751) -->
- <skip />
- <!-- no translation found for accessibility_unlock_without_fingerprint (7541705575183694446) -->
- <skip />
- <!-- no translation found for unlock_label (8779712358041029439) -->
- <skip />
- <!-- no translation found for phone_label (2320074140205331708) -->
- <skip />
- <!-- no translation found for voice_assist_label (3956854378310019854) -->
- <skip />
- <!-- no translation found for camera_label (7261107956054836961) -->
- <skip />
- <!-- no translation found for recents_caption_resize (3517056471774958200) -->
- <skip />
- <!-- no translation found for cancel (6442560571259935130) -->
- <skip />
- <!-- no translation found for accessibility_compatibility_zoom_button (8461115318742350699) -->
- <skip />
- <!-- no translation found for accessibility_compatibility_zoom_example (4220687294564945780) -->
- <skip />
- <!-- no translation found for accessibility_bluetooth_connected (2707027633242983370) -->
- <skip />
- <!-- no translation found for accessibility_bluetooth_disconnected (7416648669976870175) -->
- <skip />
- <!-- no translation found for accessibility_no_battery (358343022352820946) -->
- <skip />
- <!-- no translation found for accessibility_battery_one_bar (7774887721891057523) -->
- <skip />
- <!-- no translation found for accessibility_battery_two_bars (8500650438735009973) -->
- <skip />
- <!-- no translation found for accessibility_battery_three_bars (2302983330865040446) -->
- <skip />
- <!-- no translation found for accessibility_battery_full (8909122401720158582) -->
- <skip />
- <!-- no translation found for accessibility_no_phone (4894708937052611281) -->
- <skip />
- <!-- no translation found for accessibility_phone_one_bar (687699278132664115) -->
- <skip />
- <!-- no translation found for accessibility_phone_two_bars (8384905382804815201) -->
- <skip />
- <!-- no translation found for accessibility_phone_three_bars (8521904843919971885) -->
- <skip />
- <!-- no translation found for accessibility_phone_signal_full (6471834868580757898) -->
- <skip />
- <!-- no translation found for accessibility_no_data (4791966295096867555) -->
- <skip />
- <!-- no translation found for accessibility_data_one_bar (1415625833238273628) -->
- <skip />
- <!-- no translation found for accessibility_data_two_bars (6166018492360432091) -->
- <skip />
- <!-- no translation found for accessibility_data_three_bars (9167670452395038520) -->
- <skip />
- <!-- no translation found for accessibility_data_signal_full (2708384608124519369) -->
- <skip />
- <!-- no translation found for accessibility_wifi_name (7202151365171148501) -->
- <skip />
- <!-- no translation found for accessibility_bluetooth_name (8441517146585531676) -->
- <skip />
- <!-- no translation found for accessibility_no_wimax (4329180129727630368) -->
- <skip />
- <!-- no translation found for accessibility_wimax_one_bar (4170994299011863648) -->
- <skip />
- <!-- no translation found for accessibility_wimax_two_bars (9176236858336502288) -->
- <skip />
- <!-- no translation found for accessibility_wimax_three_bars (6116551636752103927) -->
- <skip />
- <!-- no translation found for accessibility_wimax_signal_full (2768089986795579558) -->
- <skip />
- <!-- no translation found for accessibility_ethernet_disconnected (5896059303377589469) -->
- <skip />
- <!-- no translation found for accessibility_ethernet_connected (2692130313069182636) -->
- <skip />
- <!-- no translation found for accessibility_no_signal (7064645320782585167) -->
- <skip />
- <!-- no translation found for accessibility_not_connected (6395326276213402883) -->
- <skip />
- <!-- no translation found for accessibility_zero_bars (3806060224467027887) -->
- <skip />
- <!-- no translation found for accessibility_one_bar (1685730113192081895) -->
- <skip />
- <!-- no translation found for accessibility_two_bars (6437363648385206679) -->
- <skip />
- <!-- no translation found for accessibility_three_bars (2648241415119396648) -->
- <skip />
- <!-- no translation found for accessibility_signal_full (9122922886519676839) -->
- <skip />
- <!-- no translation found for accessibility_desc_on (2385254693624345265) -->
- <skip />
- <!-- no translation found for accessibility_desc_off (6475508157786853157) -->
- <skip />
- <!-- no translation found for accessibility_desc_connected (8366256693719499665) -->
- <skip />
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_gprs (1606477224486747751) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_1x (994133468120244018) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_hspa (2032328855462645198) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_3g (8628562305003568260) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_3.5g (8664845609981692001) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_4g (7741000750630089612) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_lte (5413468808637540658) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_cdma (6132648193978823023) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_roaming (5977362333466556094) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_edge (4477457051631979278) -->
- <skip />
- <!-- no translation found for accessibility_data_connection_wifi (2324496756590645221) -->
- <skip />
- <!-- no translation found for accessibility_no_sim (8274017118472455155) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Sistemski UI"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Obriši"</string>
+ <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Uklanjanje sa spiska"</string>
+ <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informacije o aplikaciji"</string>
+ <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ovdje se prikazuju nedavno korišteni ekrani"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Odbaci nedavne aplikacije"</string>
+ <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+ <item quantity="one">%d ekran u Pregledu</item>
+ <item quantity="few">%d ekrana u Pregledu</item>
+ <item quantity="other">%d ekrana u Pregledu</item>
+ </plurals>
+ <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nema obavještenja"</string>
+ <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"U toku"</string>
+ <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavještenja"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Baterija je skoro prazna"</string>
+ <string name="battery_low_percent_format" msgid="2900940511201380775">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je štednja baterije."</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nKoristite samo priloženi punjač."</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje pomoću USB-a nije podržano."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Koristite isključivo priloženi punjač."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Postavke"</string>
+ <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Želite li uključiti štednju baterije?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Uključi"</string>
+ <string name="battery_saver_start_action" msgid="5576697451677486320">"Uključi štednju baterije"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+ <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatsko rotiranje ekrana"</string>
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"BEZV."</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Obavještenja"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"Dijeljenje Bluetooth veze"</string>
+ <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Postavljanje načina unosa"</string>
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tastatura"</string>
+ <string name="usb_device_permission_prompt" msgid="834698001271562057">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup USB uređaju?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup USB perifernom uređaju?"</string>
+ <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kada je ovaj USB uređaj spojen?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kada se poveže ovaj USB periferni uređaj?"</string>
+ <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nema instaliranih aplikacija za ovaj USB uređaj. Saznajte više o uređaju na <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB periferni uređaj"</string>
+ <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
+ <string name="always_use_device" msgid="1450287437017315906">"Koristiti kao zadanu opciju za ovaj USB uređaj"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Koristiti kao zadanu opciju za ovaj USB uređaj"</string>
+ <string name="usb_debugging_title" msgid="4513918393387141949">"Omogućiti otklanjanje grešaka preko USB-a?"</string>
+ <string name="usb_debugging_message" msgid="2220143855912376496">"RSA otisak prsta za otključavanje računara je: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="303335496705863070">"Uvijek dozvoli sa ovog računara"</string>
+ <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Uklanjanje pogreški putem USB-a nije dozvoljeno"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Korisnik koji je trenutno prijavljen na uređaju ne može uključiti opciju za otklanjanje grešaka koristeći USB. Da biste koristili ovu funkciju prebacite se na korisnika administratora."</string>
+ <string name="compat_mode_on" msgid="6623839244840638213">"Uvećaj prikaz na ekran"</string>
+ <string name="compat_mode_off" msgid="4434467572461327898">"Razvuci prikaz na ekran"</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Spašavanje snimka ekrana..."</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Spašavanje snimka ekrana..."</string>
+ <string name="screenshot_saving_text" msgid="2419718443411738818">"Spašavanje snimka ekrana u toku."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran snimljen."</string>
+ <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimka ekrana."</string>
+ <string name="screenshot_failed_title" msgid="705781116746922771">"Došlo je do greške prilikom snimanja ekrana."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snimak ekrana se ne može sačuvati zbog manjka prostora za pohranu."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikacija ili vaša organizacija ne dopuštaju pravljenje snimaka ekrana."</string>
+ <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa fajlova"</string>
+ <string name="use_mtp_button_title" msgid="4333504413563023626">"Reproduciranje medijskih sadržaja (MTP)"</string>
+ <string name="use_ptp_button_title" msgid="7517127540301625751">"Priključiti kao kameru (PTP)"</string>
+ <string name="installer_cd_button_title" msgid="2312667578562201583">"Instalirajte Android File Transfer za Mac"</string>
+ <string name="accessibility_back" msgid="567011538994429120">"Nazad"</string>
+ <string name="accessibility_home" msgid="8217216074895377641">"Dugme za početnu stranicu"</string>
+ <string name="accessibility_menu" msgid="316839303324695949">"Dugme Meni"</string>
+ <string name="accessibility_recent" msgid="5208608566793607626">"Pregled"</string>
+ <string name="accessibility_search_light" msgid="1103867596330271848">"Traži"</string>
+ <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
+ <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Glasovna pomoć"</string>
+ <string name="accessibility_unlock_button" msgid="128158454631118828">"Otključaj"</string>
+ <string name="accessibility_unlock_button_fingerprint" msgid="8214125623493923751">"Dugme za otključavanje, čeka se na otisak prsta"</string>
+ <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Otključaj bez korištenja otiska prsta"</string>
+ <string name="unlock_label" msgid="8779712358041029439">"otključaj"</string>
+ <string name="phone_label" msgid="2320074140205331708">"otvori telefon"</string>
+ <string name="voice_assist_label" msgid="3956854378310019854">"otvori glasovnu pomoć"</string>
+ <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberite novi raspored zadataka"</string>
+ <string name="cancel" msgid="6442560571259935130">"Prekini"</string>
+ <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
+ <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>
+ <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je povezan."</string>
+ <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth je isključen."</string>
+ <string name="accessibility_no_battery" msgid="358343022352820946">"Baterija prazna."</string>
+ <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Baterija na jednoj crtici."</string>
+ <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Baterija na dvije crtice."</string>
+ <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Baterija na tri crtice."</string>
+ <string name="accessibility_battery_full" msgid="8909122401720158582">"Baterija je puna."</string>
+ <string name="accessibility_no_phone" msgid="4894708937052611281">"Nema telefonskog signala."</string>
+ <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Telefonski signal na jednoj crtici."</string>
+ <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Telefonski signal na dvije crtice."</string>
+ <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Telefonski signal na tri crtice."</string>
+ <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Telefonski signal pun."</string>
+ <string name="accessibility_no_data" msgid="4791966295096867555">"Nema podataka."</string>
+ <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Prijenos podataka na jednoj crtici."</string>
+ <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Prijenos podataka na dvije crtice."</string>
+ <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Prijenos podataka na tri crtice."</string>
+ <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Signal za prijenos podataka pun."</string>
+ <string name="accessibility_wifi_name" msgid="7202151365171148501">"Povezan na <xliff:g id="WIFI">%s</xliff:g>."</string>
+ <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
+ <string name="accessibility_no_wimax" msgid="4329180129727630368">"Nema WiMAX signala."</string>
+ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX signal na jednoj crtici."</string>
+ <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX signal na dvije crtice."</string>
+ <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX signal na tri crtice."</string>
+ <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX signal pun."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="5896059303377589469">"Veza sa Ethernetom je prekinuta."</string>
+ <string name="accessibility_ethernet_connected" msgid="2692130313069182636">"Ethernet je spojen."</string>
+ <string name="accessibility_no_signal" msgid="7064645320782585167">"Nema signala."</string>
+ <string name="accessibility_not_connected" msgid="6395326276213402883">"Nije povezano."</string>
+ <string name="accessibility_zero_bars" msgid="3806060224467027887">"Nema crtica."</string>
+ <string name="accessibility_one_bar" msgid="1685730113192081895">"Jedna crtica."</string>
+ <string name="accessibility_two_bars" msgid="6437363648385206679">"Dvije crtice."</string>
+ <string name="accessibility_three_bars" msgid="2648241415119396648">"Tri crtice."</string>
+ <string name="accessibility_signal_full" msgid="9122922886519676839">"Pun signal."</string>
+ <string name="accessibility_desc_on" msgid="2385254693624345265">"Uključeno."</string>
+ <string name="accessibility_desc_off" msgid="6475508157786853157">"Isključeno."</string>
+ <string name="accessibility_desc_connected" msgid="8366256693719499665">"Povezano"</string>
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Povezivanje."</string>
+ <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
+ <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
+ <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
+ <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
+ <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
+ <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
+ <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
+ <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
+ <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Roming"</string>
+ <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
+ <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
+ <string name="accessibility_no_sim" msgid="8274017118472455155">"Nema SIM kartice."</string>
<string name="accessibility_cell_data_off" msgid="8000803571751407635">"Mobilni podaci isključeni"</string>
- <!-- no translation found for accessibility_bluetooth_tether (4102784498140271969) -->
- <skip />
- <!-- no translation found for accessibility_airplane_mode (834748999790763092) -->
- <skip />
- <!-- no translation found for accessibility_no_sims (3957997018324995781) -->
- <skip />
- <!-- no translation found for accessibility_carrier_network_change_mode (4017301580441304305) -->
- <skip />
- <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
- <skip />
- <!-- no translation found for accessibility_settings_button (799583911231893380) -->
- <skip />
- <!-- no translation found for accessibility_notifications_button (4498000369779421892) -->
- <skip />
- <!-- no translation found for accessibility_remove_notification (3603099514902182350) -->
- <skip />
- <!-- no translation found for accessibility_gps_enabled (3511469499240123019) -->
- <skip />
- <!-- no translation found for accessibility_gps_acquiring (8959333351058967158) -->
- <skip />
- <!-- no translation found for accessibility_tty_enabled (4613200365379426561) -->
- <skip />
- <!-- no translation found for accessibility_ringer_vibrate (666585363364155055) -->
- <skip />
- <!-- no translation found for accessibility_ringer_silent (9061243307939135383) -->
- <skip />
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Dijeljenje Bluetooth veze."</string>
+ <string name="accessibility_airplane_mode" msgid="834748999790763092">"Način rada u avionu."</string>
+ <string name="accessibility_no_sims" msgid="3957997018324995781">"Nema SIM kartice."</string>
+ <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Promjena mreže operatera."</string>
+ <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija na <xliff:g id="NUMBER">%d</xliff:g> posto."</string>
+ <string name="accessibility_settings_button" msgid="799583911231893380">"Postavke sistema."</string>
+ <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obavještenja."</string>
+ <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ukloniti obavještenje."</string>
+ <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS omogućen."</string>
+ <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Uspostavljanje GPS veze."</string>
+ <string name="accessibility_tty_enabled" msgid="4613200365379426561">"Omogućena opcija TeleTypewriter."</string>
+ <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Zvuk zvona na vibraciji."</string>
+ <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Zvuk zvona nečujan."</string>
<!-- no translation found for accessibility_casting (6887382141726543668) -->
<skip />
- <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
- <skip />
- <!-- no translation found for accessibility_recents_item_will_be_dismissed (395770242498031481) -->
- <skip />
- <!-- no translation found for accessibility_recents_item_dismissed (6803574935084867070) -->
- <skip />
- <!-- no translation found for accessibility_recents_all_items_dismissed (4464697366179168836) -->
- <skip />
- <!-- no translation found for accessibility_recents_item_launched (7616039892382525203) -->
- <skip />
- <!-- no translation found for accessibility_recents_task_header (1437183540924535457) -->
- <skip />
- <!-- no translation found for accessibility_notification_dismissed (854211387186306927) -->
- <skip />
- <!-- no translation found for accessibility_desc_notification_shade (4690274844447504208) -->
- <skip />
- <!-- no translation found for accessibility_desc_quick_settings (6186378411582437046) -->
- <skip />
- <!-- no translation found for accessibility_desc_lock_screen (5625143713611759164) -->
- <skip />
- <!-- no translation found for accessibility_desc_settings (3417884241751434521) -->
- <skip />
- <!-- no translation found for accessibility_desc_recent_apps (4876900986661819788) -->
- <skip />
- <!-- no translation found for accessibility_desc_close (7479755364962766729) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_user (1104846699869476855) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_wifi (5518210213118181692) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_wifi_changed_off (8716484460897819400) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_wifi_changed_on (6440117170789528622) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_mobile (4876806564086241341) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_battery (1480931583381408972) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_off (7786329360056634412) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_on (6406141469157599296) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_changed_off (66846307818850664) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_airplane_changed_on (8983005603505087728) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_priority_on (1448402297221249355) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_none_on (6882582132662613537) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_alarms_on (9152834845587554157) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_off (2371832603753738581) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_changed_off (898107593453022935) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_dnd_changed_on (4483780856613561039) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_off (2133631372372064339) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_on (7681999166216621838) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_connecting (6953242966685343855) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_connected (4306637793614573659) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_changed_off (2730003763480934529) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_bluetooth_changed_on (8722351798763206577) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_off (5119080556976115520) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_on (5809937096590102036) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_changed_off (8526845571503387376) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_location_changed_on (339403053079338468) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_alarm (3959908972897295660) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_close (3115847794692516306) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_more_time (3659274935356197708) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_less_time (2404728746293515623) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_off (4936432000069786988) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_on (2003479320007841077) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_changed_off (3303701786768224304) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_flashlight_changed_on (6531793301533894686) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_color_inversion_changed_off (4406577213290173911) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_color_inversion_changed_on (6897462320184911126) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_hotspot_changed_off (5004708003447561394) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_hotspot_changed_on (2890951609226476206) -->
- <skip />
- <!-- no translation found for accessibility_casting_turned_off (1430668982271976172) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
- <skip />
- <!-- no translation found for accessibility_brightness (8003681285547803095) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_3g_title (5281770593459841889) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_4g_title (1601769736881078016) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_mobile_title (4651001290947318931) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_title (3932437232199671967) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog (8453242888903772524) -->
- <skip />
- <!-- no translation found for data_usage_disabled_dialog_enable (1412395410306390593) -->
- <skip />
- <!-- no translation found for status_bar_settings_signal_meter_disconnected (1940231521274147771) -->
- <skip />
- <!-- no translation found for status_bar_settings_signal_meter_wifi_nossid (6557486452774597820) -->
- <skip />
- <!-- no translation found for gps_notification_searching_text (8574247005642736060) -->
- <skip />
- <!-- no translation found for gps_notification_found_text (4619274244146446464) -->
- <skip />
- <!-- no translation found for accessibility_location_active (2427290146138169014) -->
- <skip />
- <!-- no translation found for accessibility_clear_all (5235938559247164925) -->
- <skip />
- <!-- no translation found for status_bar_notification_inspect_item_title (5668348142410115323) -->
- <skip />
- <!-- no translation found for status_bar_notification_app_settings_title (5525260160341558869) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_off (4062780228931590069) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape (6731197337665366273) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_off_changed (8134601071026305153) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_landscape_changed (3135965553707519743) -->
- <skip />
- <!-- no translation found for accessibility_rotation_lock_on_portrait_changed (8922481981834012126) -->
- <skip />
- <!-- no translation found for dessert_case (1295161776223959221) -->
- <skip />
- <!-- no translation found for start_dreams (7219575858348719790) -->
- <skip />
- <!-- no translation found for ethernet_label (7967563676324087464) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_label (8735855737575028208) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_priority_label (483232950670692036) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_alarms_label (2559229444312445858) -->
- <skip />
- <!-- no translation found for quick_settings_dnd_none_label (5025477807123029478) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_label (6304190285170721401) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_multiple_devices_label (3912245565613684735) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_off_label (8159652146149219937) -->
- <skip />
- <!-- no translation found for quick_settings_bluetooth_detail_empty_text (4910015762433302860) -->
- <skip />
- <!-- no translation found for quick_settings_brightness_label (6968372297018755815) -->
- <skip />
- <!-- no translation found for quick_settings_rotation_unlocked_label (7305323031808150099) -->
- <skip />
- <!-- no translation found for quick_settings_rotation_locked_label (6359205706154282377) -->
- <skip />
- <!-- no translation found for quick_settings_rotation_locked_portrait_label (5102691921442135053) -->
- <skip />
- <!-- no translation found for quick_settings_rotation_locked_landscape_label (8553157770061178719) -->
- <skip />
- <!-- no translation found for quick_settings_ime_label (7073463064369468429) -->
- <skip />
- <!-- no translation found for quick_settings_location_label (5011327048748762257) -->
- <skip />
- <!-- no translation found for quick_settings_location_off_label (7464544086507331459) -->
- <skip />
- <!-- no translation found for quick_settings_media_device_label (1302906836372603762) -->
- <skip />
- <!-- no translation found for quick_settings_rssi_label (7725671335550695589) -->
- <skip />
- <!-- no translation found for quick_settings_rssi_emergency_only (2713774041672886750) -->
- <skip />
- <!-- no translation found for quick_settings_settings_label (5326556592578065401) -->
- <skip />
- <!-- no translation found for quick_settings_time_label (4635969182239736408) -->
- <skip />
- <!-- no translation found for quick_settings_user_label (5238995632130897840) -->
- <skip />
- <!-- no translation found for quick_settings_user_title (4467690427642392403) -->
- <skip />
- <!-- no translation found for quick_settings_user_new_user (9030521362023479778) -->
- <skip />
- <!-- no translation found for quick_settings_wifi_label (9135344704899546041) -->
- <skip />
- <!-- no translation found for quick_settings_wifi_not_connected (7171904845345573431) -->
- <skip />
- <!-- no translation found for quick_settings_wifi_no_network (2221993077220856376) -->
- <skip />
- <!-- no translation found for quick_settings_wifi_off_label (7558778100843885864) -->
- <skip />
- <!-- no translation found for quick_settings_wifi_detail_empty_text (269990350383909226) -->
- <skip />
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
- <!-- no translation found for quick_settings_casting (6601710681033353316) -->
- <skip />
- <!-- no translation found for quick_settings_cast_device_default_name (5367253104742382945) -->
- <skip />
- <!-- no translation found for quick_settings_cast_device_default_description (2484573682378634413) -->
- <skip />
- <!-- no translation found for quick_settings_cast_detail_empty_text (311785821261640623) -->
- <skip />
- <!-- no translation found for quick_settings_brightness_dialog_title (8599674057673605368) -->
- <skip />
- <!-- no translation found for quick_settings_brightness_dialog_auto_brightness_label (5064982743784071218) -->
- <skip />
- <!-- no translation found for quick_settings_inversion_label (8790919884718619648) -->
- <skip />
- <!-- no translation found for quick_settings_color_space_label (853443689745584770) -->
- <skip />
- <!-- no translation found for quick_settings_more_settings (326112621462813682) -->
- <skip />
- <!-- no translation found for quick_settings_done (3402999958839153376) -->
- <skip />
- <!-- no translation found for quick_settings_connected (1722253542984847487) -->
- <skip />
- <!-- no translation found for quick_settings_connecting (47623027419264404) -->
- <skip />
- <!-- no translation found for quick_settings_tethering_label (7153452060448575549) -->
- <skip />
- <!-- no translation found for quick_settings_hotspot_label (6046917934974004879) -->
- <skip />
- <!-- no translation found for quick_settings_notifications_label (4818156442169154523) -->
- <skip />
- <!-- no translation found for quick_settings_flashlight_label (2133093497691661546) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_title (8575062783675171695) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_data_usage (1964260360259312002) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_remaining_data (722715415543541249) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_over_limit (967669665390990427) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_data_used (1476810587475761478) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_data_limit (56011158504994128) -->
- <skip />
- <!-- no translation found for quick_settings_cellular_detail_data_warning (2440098045692399009) -->
- <skip />
- <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
- <skip />
- <!-- no translation found for recents_empty_message (8682129509540827999) -->
- <skip />
- <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
- <skip />
- <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
- <skip />
- <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
- <skip />
- <!-- no translation found for recents_launch_error_message (2969287838120550506) -->
- <skip />
+ <string name="accessibility_work_mode" msgid="2478631941714607225">"Poslovni režim"</string>
+ <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbaci aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> uklonjena."</string>
+ <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korištene aplikacije su odbačene."</string>
+ <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećem aplikaciju <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
+ <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavještenje je uklonjeno."</string>
+ <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Obavještenja sa sjenčenjem."</string>
+ <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Brze postavke."</string>
+ <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključan ekran."</string>
+ <string name="accessibility_desc_settings" msgid="3417884241751434521">"Postavke"</string>
+ <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
+ <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvori"</string>
+ <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Korisnik <xliff:g id="USER">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi je isključen."</string>
+ <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi je uključen."</string>
+ <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Podaci o mobilnoj mreži <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Stanje baterije <xliff:g id="STATE">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Isključen način rada u avionu."</string>
+ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Uključen način rada u avionu."</string>
+ <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Način rada u avionu je isključen."</string>
+ <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Način rada u avionu je uključen."</string>
+ <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Opcija Ne ometaj je uključena, čut će se samo prioritetna obavještenja."</string>
+ <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Opcija Ne ometaj je uključena, potpuna tišina."</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Opcija Ne ometaj je uključena, čut će se samo alarmi."</string>
+ <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Opcija Ne ometaj je isključena."</string>
+ <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Opcija Ne ometaj je isključena."</string>
+ <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Opcija Ne ometaj je uključena."</string>
+ <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth isključen."</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth uključen."</string>
+ <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth se povezuje."</string>
+ <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"Bluetooth je povezan."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"Bluetooth je isključen."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"Bluetooth je uključen."</string>
+ <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"Javljanje lokacije isključeno."</string>
+ <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Javljanje lokacije uključeno."</string>
+ <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Javljanje lokacije je isključeno."</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"Javljanje lokacije je uključeno."</string>
+ <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm je podešen na <xliff:g id="TIME">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Zatvori ploču."</string>
+ <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
+ <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
+ <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svjetiljka isključena."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
+ <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svjetiljka uključena."</string>
+ <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svjetiljka je isključena."</string>
+ <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svjetiljka je uključena."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Inverzija boja je isključena."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Inverzija boja je uključena."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilna pristupna tačka je isključena."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna pristupna tačka je uključena."</string>
+ <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Prebacivanje ekrana je zaustavljeno."</string>
+ <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Poslovni režim isključen."</string>
+ <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Poslovni režim uključen."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Poslovni režim je isključen."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Poslovni režim je uključen."</string>
+ <string name="accessibility_brightness" msgid="8003681285547803095">"Osvjetljenje ekrana"</string>
+ <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G prijenos podataka je pauzirano"</string>
+ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
+ <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
+ <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dostigli ste postavljeno ograničenje prijenosa podataka pa je uređaj zaustavio prijenos podataka za preostali dio ovog ciklusa.\n\nAko nastavite, operater vam može naplatiti dodatne troškove."</string>
+ <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
+ <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string>
+ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS signala"</string>
+ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija utvrđena GPS signalom"</string>
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Aktiviran je zahtjev za lokaciju"</string>
+ <string name="accessibility_clear_all" msgid="5235938559247164925">"Uklanjanje svih obavještenja."</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Postavke obavještenja"</string>
+ <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Postavke aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran je zaključan u vodoravnom prikazu."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran je zaključan u uspravnom prikazu."</string>
+ <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"Ekran će se sada automatski rotirati."</string>
+ <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Ekran je sada zaključan u vodoravnom položaju."</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Ekran je sada zaključan u uspravnom položaju."</string>
+ <string name="dessert_case" msgid="1295161776223959221">"Slika sa desertima"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
+ <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne ometaj"</string>
+ <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prioritetni prekidi"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Samo alarmi"</string>
+ <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Potpuna tišina"</string>
+ <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
+ <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (broj uređaja: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
+ <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth isključen."</string>
+ <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nema dostupnih uparenih uređaja"</string>
+ <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Osvjetljenje"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatsko rotiranje"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotiranje je zaključano"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Uspravno"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Vodoravno"</string>
+ <string name="quick_settings_ime_label" msgid="7073463064369468429">"Način unosa"</string>
+ <string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
+ <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Utvrđivanje lokacije isključeno"</string>
+ <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medijski uređaj"</string>
+ <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
+ <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Samo pozivi za hitne slučajeve"</string>
+ <string name="quick_settings_settings_label" msgid="5326556592578065401">"Postavke"</string>
+ <string name="quick_settings_time_label" msgid="4635969182239736408">"Vrijeme"</string>
+ <string name="quick_settings_user_label" msgid="5238995632130897840">"Ja"</string>
+ <string name="quick_settings_user_title" msgid="4467690427642392403">"Korisnik"</string>
+ <string name="quick_settings_user_new_user" msgid="9030521362023479778">"Novi korisnik"</string>
+ <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
+ <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nije povezano"</string>
+ <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
+ <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
+ <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nema dostupnih Wi-Fi mreža"</string>
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Prebacivanje"</string>
+ <string name="quick_settings_casting" msgid="6601710681033353316">"Prebacivanje"</string>
+ <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovani uređaj"</string>
+ <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Spreman za prebacivanje"</string>
+ <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nema dostupnih uređaja"</string>
+ <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Osvjetljenje"</string>
+ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
+ <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverzija boja"</string>
+ <string name="quick_settings_color_space_label" msgid="853443689745584770">"Način rada za ispravku boje"</string>
+ <string name="quick_settings_more_settings" msgid="326112621462813682">"Više postavki"</string>
+ <string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
+ <string name="quick_settings_connected" msgid="1722253542984847487">"Povezano"</string>
+ <string name="quick_settings_connecting" msgid="47623027419264404">"Povezivanje..."</string>
+ <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
+ <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Pristupna tačka"</string>
+ <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
+ <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
+ <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobilni podaci"</string>
+ <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Korištenje podataka"</string>
+ <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
+ <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Prekoračeno"</string>
+ <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskorišteno <xliff:g id="DATA_USED">%s</xliff:g>"</string>
+ <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
+ <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="recents_empty_message" msgid="8682129509540827999">"Ovdje se pojavljuju nedavno korišteni ekrani"</string>
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
+ <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kačenje ekrana"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraga"</string>
+ <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> je onemogućena u sigurnom načinu rada."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historija"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Obriši"</string>
- <!-- no translation found for recents_multistack_add_stack_dialog_split_horizontal (8848514474543427332) -->
- <skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_vertical (9075292233696180813) -->
- <skip />
- <!-- no translation found for recents_multistack_add_stack_dialog_split_custom (4177837597513701943) -->
- <skip />
- <!-- no translation found for expanded_header_battery_charged (5945855970267657951) -->
- <skip />
- <!-- no translation found for expanded_header_battery_charging (205623198487189724) -->
- <skip />
- <!-- no translation found for expanded_header_battery_charging_with_time (457559884275395376) -->
- <skip />
- <!-- no translation found for expanded_header_battery_not_charging (4798147152367049732) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
- <skip />
- <!-- no translation found for description_target_search (3091587249776033139) -->
- <skip />
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for zen_priority_introduction (3070506961866919502) -->
- <skip />
- <!-- no translation found for zen_priority_customize_button (7948043278226955063) -->
- <skip />
- <!-- no translation found for zen_silence_introduction_voice (2284540992298200729) -->
- <skip />
- <!-- no translation found for zen_silence_introduction (3137882381093271568) -->
- <skip />
- <!-- no translation found for keyguard_more_overflow_text (9195222469041601365) -->
- <skip />
- <!-- no translation found for speed_bump_explanation (1288875699658819755) -->
- <skip />
- <!-- no translation found for notification_tap_again (8524949573675922138) -->
- <skip />
- <!-- no translation found for keyguard_unlock (8043466894212841998) -->
- <skip />
- <!-- no translation found for phone_hint (4872890986869209950) -->
- <skip />
- <!-- no translation found for voice_hint (8939888732119726665) -->
- <skip />
- <!-- no translation found for camera_hint (7939688436797157483) -->
- <skip />
- <!-- no translation found for interruption_level_none_with_warning (5114872171614161084) -->
- <skip />
- <!-- no translation found for interruption_level_none (6000083681244492992) -->
- <skip />
- <!-- no translation found for interruption_level_priority (6426766465363855505) -->
- <skip />
- <!-- no translation found for interruption_level_alarms (5226306993448328896) -->
- <skip />
- <!-- no translation found for interruption_level_none_twoline (3957581548190765889) -->
- <skip />
- <!-- no translation found for interruption_level_priority_twoline (1564715335217164124) -->
- <skip />
- <!-- no translation found for interruption_level_alarms_twoline (3266909566410106146) -->
- <skip />
- <!-- no translation found for interruption_level_all (1330581184930945764) -->
- <skip />
- <!-- no translation found for interruption_level_all_twoline (3719402899156124780) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time (1757251776872835768) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time_fast (9018981952053914986) -->
- <skip />
- <!-- no translation found for keyguard_indication_charging_time_slowly (955252797961724952) -->
- <skip />
- <!-- no translation found for accessibility_multi_user_switch_switcher (7305948938141024937) -->
- <skip />
- <!-- no translation found for accessibility_multi_user_switch_switcher_with_current (8434880595284601601) -->
- <skip />
- <!-- no translation found for accessibility_multi_user_switch_inactive (1424081831468083402) -->
- <skip />
- <!-- no translation found for accessibility_multi_user_switch_quick_contact (3020367729287990475) -->
- <skip />
- <!-- no translation found for user_add_user (5110251524486079492) -->
- <skip />
- <!-- no translation found for user_new_user_name (426540612051178753) -->
- <skip />
- <!-- no translation found for guest_nickname (8059989128963789678) -->
- <skip />
- <!-- no translation found for guest_new_guest (600537543078847803) -->
- <skip />
- <!-- no translation found for guest_exit_guest (7187359342030096885) -->
- <skip />
- <!-- no translation found for guest_exit_guest_dialog_title (8480693520521766688) -->
- <skip />
- <!-- no translation found for guest_exit_guest_dialog_message (4155503224769676625) -->
- <skip />
- <!-- no translation found for guest_exit_guest_dialog_remove (7402231963862520531) -->
- <skip />
- <!-- no translation found for guest_wipe_session_title (6419439912885956132) -->
- <skip />
- <!-- no translation found for guest_wipe_session_message (8476238178270112811) -->
- <skip />
- <!-- no translation found for guest_wipe_session_wipe (5065558566939858884) -->
- <skip />
- <!-- no translation found for guest_wipe_session_dontwipe (1401113462524894716) -->
- <skip />
- <!-- no translation found for guest_notification_title (1585278533840603063) -->
- <skip />
- <!-- no translation found for guest_notification_text (335747957734796689) -->
- <skip />
- <!-- no translation found for guest_notification_remove_action (8820670703892101990) -->
- <skip />
- <!-- no translation found for user_logout_notification_title (1453960926437240727) -->
- <skip />
- <!-- no translation found for user_logout_notification_text (3350262809611876284) -->
- <skip />
- <!-- no translation found for user_logout_notification_action (1195428991423425062) -->
- <skip />
- <!-- no translation found for user_add_user_title (4553596395824132638) -->
- <!-- no translation found for user_add_user_title (2108112641783146007) -->
- <skip />
- <!-- no translation found for user_add_user_message_short (2161624834066214559) -->
- <!-- no translation found for user_add_user_message_short (1511354412249044381) -->
- <skip />
- <!-- no translation found for user_remove_user_title (4681256956076895559) -->
- <skip />
- <!-- no translation found for user_remove_user_message (1453218013959498039) -->
- <skip />
- <!-- no translation found for user_remove_user_remove (7479275741742178297) -->
- <skip />
- <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
- <skip />
- <!-- no translation found for battery_saver_notification_text (820318788126672692) -->
- <skip />
- <!-- no translation found for battery_saver_notification_action_text (109158658238110382) -->
- <skip />
- <!-- no translation found for media_projection_dialog_text (3071431025448218928) -->
- <skip />
- <!-- no translation found for media_projection_remember_text (3103510882172746752) -->
- <skip />
- <!-- no translation found for clear_all_notifications_text (814192889771462828) -->
- <skip />
- <!-- no translation found for media_projection_action_text (8470872969457985954) -->
- <skip />
- <!-- no translation found for empty_shade_text (708135716272867002) -->
- <skip />
- <!-- no translation found for device_owned_footer (3802752663326030053) -->
- <skip />
- <!-- no translation found for profile_owned_footer (8021888108553696069) -->
- <skip />
- <!-- no translation found for vpn_footer (2388611096129106812) -->
- <skip />
- <!-- no translation found for monitoring_title_device_owned (7121079311903859610) -->
- <skip />
- <!-- no translation found for monitoring_title_profile_owned (6790109874733501487) -->
- <skip />
- <!-- no translation found for monitoring_title (169206259253048106) -->
- <skip />
- <!-- no translation found for disable_vpn (4435534311510272506) -->
- <skip />
- <!-- no translation found for disconnect_vpn (1324915059568548655) -->
- <skip />
- <!-- no translation found for monitoring_description_device_owned (5780988291898461883) -->
- <skip />
- <!-- no translation found for monitoring_description_vpn (4445150119515393526) -->
- <skip />
- <!-- no translation found for monitoring_description_vpn_device_owned (3090670777499161246) -->
- <skip />
- <!-- no translation found for monitoring_description_vpn_profile_owned (2054949132145039290) -->
- <skip />
- <!-- no translation found for legacy_vpn_name (6604123105765737830) -->
- <skip />
- <!-- no translation found for monitoring_description_app (6259179342284742878) -->
- <skip />
- <!-- no translation found for monitoring_description_app_personal (484599052118316268) -->
- <skip />
- <!-- no translation found for monitoring_description_app_work (1754325860918060897) -->
- <skip />
- <!-- no translation found for monitoring_description_app_personal_work (4946600443852045903) -->
- <skip />
- <!-- no translation found for monitoring_description_vpn_app_device_owned (4970443827043261703) -->
- <skip />
- <!-- no translation found for keyguard_indication_trust_disabled (7412534203633528135) -->
- <skip />
- <!-- no translation found for hidden_notifications_title (7139628534207443290) -->
- <skip />
- <!-- no translation found for hidden_notifications_text (2326409389088668981) -->
- <skip />
- <!-- no translation found for hidden_notifications_cancel (3690709735122344913) -->
- <skip />
- <!-- no translation found for hidden_notifications_setup (41079514801976810) -->
- <skip />
- <!-- no translation found for zen_mode_and_condition (4462471036429759903) -->
- <skip />
- <!-- no translation found for volume_zen_end_now (3179845345429841822) -->
- <skip />
- <!-- no translation found for accessibility_volume_expand (5946812790999244205) -->
- <skip />
- <!-- no translation found for accessibility_volume_collapse (3609549593031810875) -->
- <skip />
- <!-- no translation found for screen_pinning_title (3273740381976175811) -->
- <skip />
- <!-- no translation found for screen_pinning_description (3577937698406151604) -->
- <skip />
- <!-- no translation found for screen_pinning_positive (3783985798366751226) -->
- <skip />
- <!-- no translation found for screen_pinning_negative (3741602308343880268) -->
- <skip />
- <!-- no translation found for quick_settings_reset_confirmation_title (748792586749897883) -->
- <skip />
- <!-- no translation found for quick_settings_reset_confirmation_message (2235970126803317374) -->
- <skip />
- <!-- no translation found for quick_settings_reset_confirmation_button (2660339101868367515) -->
- <skip />
- <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
- <skip />
- <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
- <skip />
- <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
- <skip />
- <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
- <skip />
- <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
- <skip />
- <!-- no translation found for managed_profile_foreground_toast (5421487114739245972) -->
- <skip />
- <!-- no translation found for system_ui_tuner (708224127392452018) -->
- <skip />
- <!-- no translation found for show_battery_percentage (5444136600512968798) -->
- <skip />
- <!-- no translation found for show_battery_percentage_summary (3215025775576786037) -->
- <skip />
- <!-- no translation found for quick_settings (10042998191725428) -->
- <skip />
- <!-- no translation found for status_bar (4877645476959324760) -->
- <skip />
- <!-- no translation found for overview (4018602013895926956) -->
- <skip />
- <!-- no translation found for demo_mode (2389163018533514619) -->
- <skip />
- <!-- no translation found for enable_demo_mode (4844205668718636518) -->
- <skip />
- <!-- no translation found for show_demo_mode (2018336697782464029) -->
- <skip />
- <!-- no translation found for status_bar_ethernet (5044290963549500128) -->
- <skip />
- <!-- no translation found for status_bar_alarm (8536256753575881818) -->
- <skip />
- <!-- no translation found for status_bar_work (6022553324802866373) -->
- <skip />
- <!-- no translation found for status_bar_airplane (7057575501472249002) -->
- <skip />
- <!-- no translation found for add_tile (2995389510240786221) -->
- <skip />
- <!-- no translation found for broadcast_tile (3894036511763289383) -->
- <skip />
- <!-- no translation found for zen_alarm_warning_indef (3482966345578319605) -->
- <skip />
- <!-- no translation found for zen_alarm_warning (444533119582244293) -->
- <skip />
- <!-- no translation found for alarm_template (3980063409350522735) -->
- <skip />
- <!-- no translation found for alarm_template_far (4242179982586714810) -->
- <skip />
- <!-- no translation found for accessibility_quick_settings_detail (2579369091672902101) -->
- <skip />
- <!-- no translation found for accessibility_status_bar_hotspot (4099381329956402865) -->
- <skip />
- <!-- no translation found for accessibility_managed_profile (6613641363112584120) -->
- <skip />
- <!-- no translation found for tuner_warning_title (7094689930793031682) -->
- <skip />
- <!-- no translation found for tuner_warning (8730648121973575701) -->
- <skip />
- <!-- no translation found for tuner_persistent_warning (8597333795565621795) -->
- <skip />
- <!-- no translation found for got_it (2239653834387972602) -->
- <skip />
- <!-- no translation found for tuner_toast (603429811084428439) -->
- <skip />
- <!-- no translation found for remove_from_settings (8389591916603406378) -->
- <skip />
- <!-- no translation found for remove_from_settings_prompt (6069085993355887748) -->
- <skip />
- <!-- no translation found for activity_not_found (348423244327799974) -->
- <skip />
- <!-- no translation found for clock_seconds (7689554147579179507) -->
- <skip />
- <!-- no translation found for clock_seconds_desc (6282693067130470675) -->
- <skip />
- <!-- no translation found for qs_rearrange (8060918697551068765) -->
- <skip />
- <!-- no translation found for show_brightness (6613930842805942519) -->
- <skip />
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Uključi akcelerator za dijeljenje ekrana prevlačenjem nagore"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ova aplikacija ne podržava rad sa više prozora"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava rad sa više prozora"</string>
+ <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>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Do kraja punjenja preostalo <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ne puni se"</string>
+ <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža može \n biti nadzirana"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Traži"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Povucite gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Povucite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="zen_priority_introduction" msgid="3070506961866919502">"Zvukovi i vibracije vas neće uznemiravati, osim alarma, podsjetnika, događaja i pozivalaca koje odredite."</string>
+ <string name="zen_priority_customize_button" msgid="7948043278226955063">"Prilagodi"</string>
+ <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Ovim se blokiraju SVI zvukovi i vibracije, uključujući alarme, muziku, videozapise i igre. I dalje ćete moći obavljati pozive."</string>
+ <string name="zen_silence_introduction" msgid="3137882381093271568">"Ovim se blokiraju SVI zvukovi i vibracije, uključujući alarme, muziku, video zapise i igre."</string>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
+ <string name="speed_bump_explanation" msgid="1288875699658819755">"Prikaži manje važna obavještenja ispod"</string>
+ <string name="notification_tap_again" msgid="8524949573675922138">"Dodirnite ponovo da otvorite"</string>
+ <string name="keyguard_unlock" msgid="8043466894212841998">"Prevucite prema gore da otključate"</string>
+ <string name="phone_hint" msgid="4872890986869209950">"Prevucite preko ikone da otvorite telefon"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"Prevucite preko ikone za glasovnu pomoć"</string>
+ <string name="camera_hint" msgid="7939688436797157483">"Prevucite od ikone da otvorite kameru"</string>
+ <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Potpuna tišina. Ovo će utišati i čitače ekrana."</string>
+ <string name="interruption_level_none" msgid="6000083681244492992">"Potpuna tišina"</string>
+ <string name="interruption_level_priority" msgid="6426766465363855505">"Samo prioritetni prekidi"</string>
+ <string name="interruption_level_alarms" msgid="5226306993448328896">"Samo alarmi"</string>
+ <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
+ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetni prekidi"</string>
+ <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (do kraja preostalo <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do pune baterije)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do pune baterije)"</string>
+ <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Zamijeni korisnika"</string>
+ <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Zamijeni korisnika. Trenutni korisnik je <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"Pokaži profil"</string>
+ <string name="user_add_user" msgid="5110251524486079492">"Dodaj korisnika"</string>
+ <string name="user_new_user_name" msgid="426540612051178753">"Novi korisnik"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+ <string name="guest_new_guest" msgid="600537543078847803">"Dodaj gosta"</string>
+ <string name="guest_exit_guest" msgid="7187359342030096885">"Ukloni gosta"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"Želite li ukloniti gosta?"</string>
+ <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Sve aplikacije i svi podaci iz ove sesije bit će izbrisani."</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Ukloni"</string>
+ <string name="guest_wipe_session_title" msgid="6419439912885956132">"Zdravo! Lijepo je opet vidjeti goste."</string>
+ <string name="guest_wipe_session_message" msgid="8476238178270112811">"Želite li nastaviti sesiju?"</string>
+ <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Počni ispočetka"</string>
+ <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Da, nastavi"</string>
+ <string name="guest_notification_title" msgid="1585278533840603063">"Korisnik koji je gost"</string>
+ <string name="guest_notification_text" msgid="335747957734796689">"Da izbrišete aplikacije i podatke, uklonite gosta"</string>
+ <string name="guest_notification_remove_action" msgid="8820670703892101990">"UKLONI GOSTA"</string>
+ <string name="user_logout_notification_title" msgid="1453960926437240727">"Odjavi korisnika"</string>
+ <string name="user_logout_notification_text" msgid="3350262809611876284">"Odjavi trenutnog korisnika"</string>
+ <string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
+ <string name="user_add_user_title" msgid="4553596395824132638">"Želite dodati novog korisnika?"</string>
+ <string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba treba uspostaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Zaista želite ukloniti korisnika?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika bit će izbrisani."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"Minimizira rad i prijenos podataka u pozadini"</string>
+ <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi štednju baterije"</string>
+ <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će početi snimati sve što se prikaže na ekranu."</string>
+ <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj opet"</string>
+ <string name="clear_all_notifications_text" msgid="814192889771462828">"Očisti sve"</string>
+ <string name="media_projection_action_text" msgid="8470872969457985954">"Pokreni odmah"</string>
+ <string name="empty_shade_text" msgid="708135716272867002">"Nema obavještenja"</string>
+ <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj može biti nadziran"</string>
+ <string name="profile_owned_footer" msgid="8021888108553696069">"Profil može biti nadziran"</string>
+ <string name="vpn_footer" msgid="2388611096129106812">"Mreža može biti nadzirana"</string>
+ <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Praćenje uređaja"</string>
+ <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Praćenje profila"</string>
+ <string name="monitoring_title" msgid="169206259253048106">"Praćenje mreže"</string>
+ <string name="disable_vpn" msgid="4435534311510272506">"Isključi VPN"</string>
+ <string name="disconnect_vpn" msgid="1324915059568548655">"Prekini VPN vezu"</string>
+ <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane sa vašim uređajem i informacije o lokaciji uređaja, kao i upravljati njima. Za više informacija kontaktirajte svog administratora."</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>
+ <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane sa vašim uređajem i informacije o lokaciji uređaja, kao i upravljati njima.\n\nPovezani ste na VPN, koji može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Vašim profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora.\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="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%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\nZa više informacija kontaktirajte svog administratora."</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="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane sa vašim uređajem i informacije o lokaciji uređaja, kao i upravljati njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</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>
+ <string name="hidden_notifications_text" msgid="2326409389088668981">"Vidi ih prije otključavanja"</string>
+ <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ne, hvala"</string>
+ <string name="hidden_notifications_setup" msgid="41079514801976810">"Postavi"</string>
+ <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
+ <string name="volume_zen_end_now" msgid="3179845345429841822">"Završi sada"</string>
+ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
+ <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="3577937698406151604">"Ovim ekran ostaje prikazan dok ga ne otkačite. Da biste ga otkačili dodirnite i držite Nazad."</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>
+ <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Pojavit će se sljedeći put kada opciju uključite u postavkama."</string>
+ <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
+ <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> želi funkcionirati kao dijaloški okvir za jačinu zvuka."</string>
+ <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Dozvoli"</string>
+ <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
+ <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dijaloški okvir za jačinu zvuka"</string>
+ <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da vratite original."</string>
+ <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Koristite svoj profil za posao"</string>
+ <string name="system_ui_tuner" msgid="708224127392452018">"Podešavač za korisničko sučelje sistema"</string>
+ <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži ugrađeni postotak baterije"</string>
+ <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazuje postotak nivoa baterije unutar ikone na statusnoj traci kada se baterija ne puni"</string>
+ <string name="quick_settings" msgid="10042998191725428">"Brze postavke"</string>
+ <string name="status_bar" msgid="4877645476959324760">"Statusna traka"</string>
+ <string name="overview" msgid="4018602013895926956">"Pregled"</string>
+ <string name="demo_mode" msgid="2389163018533514619">"Način demonstracije"</string>
+ <string name="enable_demo_mode" msgid="4844205668718636518">"Omogući način demonstracije"</string>
+ <string name="show_demo_mode" msgid="2018336697782464029">"Prikaži način demonstracije"</string>
+ <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
+ <string name="status_bar_alarm" msgid="8536256753575881818">"Alarm"</string>
+ <string name="status_bar_work" msgid="6022553324802866373">"Profil za posao"</string>
+ <string name="status_bar_airplane" msgid="7057575501472249002">"Način rada u avionu"</string>
+ <string name="add_tile" msgid="2995389510240786221">"Dodaj pločicu"</string>
+ <string name="broadcast_tile" msgid="3894036511763289383">"Pločica za informacije"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g> ako prije toga ovo ne isključite"</string>
+ <string name="zen_alarm_warning" msgid="444533119582244293">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="alarm_template" msgid="3980063409350522735">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="alarm_template_far" msgid="4242179982586714810">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"Brze postavke, <xliff:g id="TITLE">%s</xliff:g>."</string>
+ <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Pristupna tačka"</string>
+ <string name="accessibility_managed_profile" msgid="6613641363112584120">"Profil za posao"</string>
+ <string name="tuner_warning_title" msgid="7094689930793031682">"Zabava za neke, ali ne za sve"</string>
+ <string name="tuner_warning" msgid="8730648121973575701">"Podešavač za korisničko sučelje sistema vam omogućava dodatne načine da podesite i prilagodite Androidovo sučelje. Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string>
+ <string name="tuner_persistent_warning" msgid="8597333795565621795">"Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string>
+ <string name="got_it" msgid="2239653834387972602">"Jasno mi je"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"Čestitamo! Podešavač za korisničko sučelje sistema je dodan u Postavke"</string>
+ <string name="remove_from_settings" msgid="8389591916603406378">"Ukloni iz Postavki"</string>
+ <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Želite li ukloniti Podešavač za korisničko sučelje sistema iz Postavki i prestati koristiti sve njegove funkcije?"</string>
+ <string name="activity_not_found" msgid="348423244327799974">"Aplikacija nije instalirana na uređaju"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Prikaži sekunde"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaži sekunde na statusnoj traci. Može skratiti trajanje baterije."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi \"Brze postavke\""</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvjetljenje u opciji \"Brze postavke\""</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogućiti potez za podjelu ekrana prevlačenjem prema gore"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Uključite pokrete prstima da biste ušli u podijeljeni ekran tako što ćete od dugmeta Pregled prevući prstom prema gore"</string>
- <!-- no translation found for experimental (6198182315536726162) -->
- <skip />
- <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
- <skip />
- <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
- <skip />
- <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
- <skip />
- <!-- no translation found for apply_to_topic (3641403489318659666) -->
- <skip />
- <!-- no translation found for apply_to_app (363016783939815960) -->
- <skip />
- <!-- no translation found for blocked_importance (5198578988978234161) -->
- <skip />
- <!-- no translation found for low_importance (4109929986107147930) -->
- <skip />
- <!-- no translation found for default_importance (8192107689995742653) -->
- <skip />
- <!-- no translation found for high_importance (1527066195614050263) -->
- <skip />
- <!-- no translation found for max_importance (5089005872719563894) -->
- <skip />
- <!-- no translation found for notification_importance_blocked (2397192642657872872) -->
- <skip />
- <!-- no translation found for notification_importance_low (4383563267370859725) -->
- <skip />
- <!-- no translation found for notification_importance_default (4926529615920610817) -->
- <skip />
- <!-- no translation found for notification_importance_high (3222680136612408223) -->
- <skip />
- <!-- no translation found for notification_importance_max (5236987171904756134) -->
- <skip />
- <!-- no translation found for notification_more_settings (816306283396553571) -->
- <skip />
- <!-- no translation found for notification_done (5279426047273930175) -->
- <skip />
- <!-- no translation found for color_matrix_none (2121957926040543148) -->
- <skip />
- <!-- no translation found for color_matrix_night (5943817622105307072) -->
- <skip />
- <!-- no translation found for color_matrix_custom (3655576492322298713) -->
- <skip />
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatski"</string>
- <!-- no translation found for color_matrix_unknown (2709202104256265107) -->
- <skip />
- <!-- no translation found for color_transform (6985460408079086090) -->
- <skip />
- <!-- no translation found for color_matrix_show_qs (1763244354399276679) -->
- <skip />
- <!-- no translation found for color_enable_custom (6729001308217347501) -->
- <skip />
- <!-- no translation found for color_apply (9212602012641034283) -->
- <skip />
- <!-- no translation found for color_revert_title (4746666545480534663) -->
- <skip />
- <!-- no translation found for color_revert_message (9116001069397996691) -->
- <skip />
- <!-- no translation found for battery_panel_title (3476715163685592453) -->
- <skip />
- <!-- no translation found for battery_detail_charging_summary (1279095653533044008) -->
- <skip />
- <!-- no translation found for battery_detail_switch_title (6285872470260795421) -->
- <skip />
- <!-- no translation found for battery_detail_switch_summary (9049111149407626804) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_system (6472647649616541064) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_system_home (3054369431319891965) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_system_recents (3154851905021926744) -->
- <skip />
- <!-- no translation found for keyboard_shortcut_group_system_back (2207004531216446378) -->
- <skip />
- <!-- no translation found for tuner_full_zen_title (5905081395132280054) -->
- <skip />
- <!-- no translation found for tuner_full_zen_summary (6883568374520596402) -->
- <skip />
- <!-- no translation found for volume_and_do_not_disturb (3114580364524650941) -->
- <skip />
- <!-- no translation found for volume_down_silent (66962568467719591) -->
- <skip />
- <!-- no translation found for volume_up_silent (7141255269783588286) -->
- <skip />
- <!-- no translation found for battery (7498329822413202973) -->
- <skip />
- <!-- no translation found for clock (7416090374234785905) -->
- <skip />
- <!-- no translation found for headset (4534219457597457353) -->
- <skip />
- <!-- no translation found for accessibility_status_bar_headphones (9156307120060559989) -->
- <skip />
- <!-- no translation found for accessibility_status_bar_headset (8666419213072449202) -->
- <skip />
- <!-- no translation found for tuner_status_bar_explanation (9032196769944137864) -->
- <skip />
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
+ <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
+ <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
+ <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
+ <string name="low_importance" msgid="4109929986107147930">"Mali značaj"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normalan značaj"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Visok značaj"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Hitan značaj"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikada ne prikazuj ova obavještenja"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
+ <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Noćni način rada"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibracija zaslona"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Uključeno"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Isključeno"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Automatsko uključivanje"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Prebaciti u Noćni način rada u skladu sa lokacijom i dobom dana"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kada je Noćni režim rada uključen"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Koristiti tamne teme za OS Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Prilagođavanje nijanse"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Podešavanje osvijetljenosti"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tamna tema se primjenjuje na ključna područja OS Android koja se obično prikazuju u svijetloj temi, kao što je meni Postavke."</string>
+ <string name="color_apply" msgid="9212602012641034283">"Prihvati"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Potvrdi postavke"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"S nekim postavkama boja ovaj uređaj može biti neupotrebljiv. Kliknite U redu da biste potvrdili ove postavke boja ili sačekajte 10 sekundi da se postavke vrate na početnu vrijednost."</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>
+ <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ograničava rad i prijenos podataka u pozadini"</string>
+ <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
+ <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početak"</string>
+ <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni ekrani"</string>
+ <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazad"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikazati sa kontrolama jačine zvuka"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne ometaj"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za Jačinu zvuka"</string>
+ <string name="volume_up_silent" msgid="7141255269783588286">"Deaktiviraj režim Ne ometaj kada se zvuk pojača"</string>
+ <string name="battery" msgid="7498329822413202973">"Baterija"</string>
+ <string name="clock" msgid="7416090374234785905">"Sat"</string>
+ <string name="headset" msgid="4534219457597457353">"Slušalice s mikrofonom"</string>
+ <string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalice su priključene"</string>
+ <string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Slušalice s mikrofonom su priključene"</string>
<string name="data_saver" msgid="5037565123367048522">"Ušteda podataka"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ušteda podataka je uključena"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ušteda podataka je isključena"</string>
<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>
@@ -973,8 +533,7 @@
<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>
- <!-- no translation found for reset (2448168080964209908) -->
- <skip />
+ <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>
@@ -986,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Odaberite dugme na tastaturi"</string>
<string name="preview" msgid="9077832302472282938">"Pregledaj"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali polja"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Prikaži sate, minute i sekunde"</item>
+ <item msgid="1427801730816895300">"Prikaži sate i minute (zadano)"</item>
+ <item msgid="3830170141562534721">"Ne prikazuj ovu ikonu"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Uvijek prikaži postotak"</item>
+ <item msgid="2139628951880142927">"Pokaži postotak u toku punjenja (zadano)"</item>
+ <item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik ekrana"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomjeri dolje"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomjeri gore"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomjeri lijevo"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomjeri desno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 8b1e568af523..3243f7423f71 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"S\'ha fet una captura de pantalla."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toca per veure la captura de pantalla."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"No s\'ha pogut fer una captura de pantalla."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"No es pot fer la captura perquè no hi ha prou espai, o l\'organització o l\'aplicació no ho permet."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"La captura de pantalla no es pot desar perquè no hi ha prou espai d\'emmagatzematge."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"L\'aplicació o l\'organització no permeten fer captures de pantalla."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcions transf. fitxers USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Munta com a reproductor multimèdia (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Munta com a càmera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Més temps"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menys temps"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Llanterna desactivada"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Llanterna activada"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Llanterna desactivada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Llanterna activada."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixació de pantalla"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"En mode segur, l\'aplicació <xliff:g id="APP">%s</xliff:g> està desactivada."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Esborra"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aquesta aplicació no admet el mode multifinestra"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'aplicació no admet el mode multifinestra"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silenci\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Totes"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Totes\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Accelerador per activar pantalla dividida en lliscar amunt"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activa el gest per dividir la pantalla en lliscar cap amunt"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa el gest per entrar al mode de pantalla dividida en lliscar cap amunt des del botó Visió general"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplica a les notificacions sobre <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplica a totes les notificacions d\'aquesta aplicació"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloquejades"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importància baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importància normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importància alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Importància urgent"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"No mostris mai aquestes notificacions"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostra de manera silenciosa a la part inferior de la llista de notificacions"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostra aquestes notificacions de manera silenciosa"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostra a la part superior de la llista de notificacions i emet un so"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostra a la pantalla i emet un so"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
<string name="notification_done" msgid="5279426047273930175">"Fet"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Colors normals"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Colors nocturns"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Colors personalitzats"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automàtica"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Colors desconeguts"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificació del color"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostra el mosaic de Configuració ràpida"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Activa la transformació personalitzada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Color i aparença"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Mode nocturn"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibra la pantalla"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Activat"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desactivat"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activa automàticament"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Canvia al mode nocturn d\'acord amb la ubicació i l\'hora del dia"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Quan el mode nocturn estigui activat"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Fes servir un tema fosc per a Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajusta el color"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajusta la brillantor"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"El tema fosc s\'aplica a les àrees clau d\'Android OS que normalment es mostren amb un tema clar, com ara Configuració."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplica"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirma la configuració"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algunes opcions de configuració de color poden deixar el dispositiu inservible. Fes clic a D\'acord per confirmar la configuració de color; en cas contrari, la configuració es restablirà al cap de 10 segons."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inici"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Enrere"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostra el mode No molesteu al volum"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permet el control complet del mode No molesteu al quadre de diàleg de volum."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volum i mode No molesteu"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Activa el mode No molesteu abaixant el volum"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra amb els controls de volum"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molesteu"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Drecera per als botons de volum"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Desactiva el mode No molesteu apujant el volum"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Rellotge"</string>
<string name="headset" msgid="4534219457597457353">"Auriculars"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculars connectats"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculars connectats"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activa o desactiva les icones a la barra d\'estat."</string>
<string name="data_saver" msgid="5037565123367048522">"Economitzador de dades"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"L\'extensió Economitzador de dades està activada"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"L\'extensió Economitzador de dades està desactivada"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Selecciona un botó de teclat"</string>
<string name="preview" msgid="9077832302472282938">"Previsualització"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrossega per afegir camps"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Edita"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostra les hores, els minuts i els segons"</item>
+ <item msgid="1427801730816895300">"Mostra les hores i els minuts (opció predeterminada)"</item>
+ <item msgid="3830170141562534721">"No mostris aquesta icona"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Mostra sempre el percentatge"</item>
+ <item msgid="2139628951880142927">"Mostra el percentatge quan es carregui (opció predeterminada)"</item>
+ <item msgid="3327323682209964956">"No mostris aquesta icona"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalles"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mou avall"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mou amunt"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mou a l\'esquerra"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mou a la dreta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e6f5f0dd2beb..b5b40373803f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Snímek obrazovky Snímek obrazovky pořízen."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Snímek obrazovky zobrazíte dotykem."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Snímek obrazovky se nepodařilo zachytit."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Snímek obrazovky nelze pořídit kvůli nedostatku místa, nebo to aplikace či vaše organizace zakazuje."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímek obrazovky nelze pořídit kvůli nedostatku místa v úložišti."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Možnosti přenosu souborů pomocí rozhraní USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Připojit jako přehrávač médií (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Připojit jako fotoaparát (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Delší doba"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší doba"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svítilna je vypnutá."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svítilna je zapnutá."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svítilna je vypnutá."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svítilna je zapnutá."</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"připnutí obrazovky"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikace <xliff:g id="APP">%s</xliff:g> je v nouzovém režimu zakázána."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historie"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vymazat"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Tato aplikace režim v několika oknech nepodporuje"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikace režim v několika oknech nepodporuje"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Úplné\nticho"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Pouze\nprioritní"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Pouze\nbudíky"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Vše"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Všechna\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Rychlé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pomalé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
<string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivovat rozdělenou obrazovku přejetím prstem"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovat rozdělenou obrazovku přejetím prstem nahoru"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovat rozdělenou obrazovku přejetím prstem nahoru od tlačítka Přehled."</string>
<string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnout"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Použít u oznámení z aplikace <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Použít u všech oznámení z této aplikace"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blokováno"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Nízká důležitost"</string>
<string name="default_importance" msgid="8192107689995742653">"Normální důležitost"</string>
<string name="high_importance" msgid="1527066195614050263">"Vysoká důležitost"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgentní důležitost"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Tato oznámení nikdy nezobrazovat"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Tato oznámení zobrazovat na začátku seznamu a upozornit na ně zvukem"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normální barvy"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Noční barvy"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastní barvy"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automaticky"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznámé barvy"</string>
- <string name="color_transform" msgid="6985460408079086090">"Změna barev"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Zobrazit dlaždici Rychlé nastavení"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Umožnit převod na vlastní barvy"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Barva a vzhled"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Noční režim"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrovat displej"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Zapnuto"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Vypnuto"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Zapnout automaticky"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Přejít do nočního režimu automaticky na základě místa a denní doby"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Když je noční režim zapnutý"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Použít v systému Android tmavý motiv"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Upravit tónování"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Upravit jas"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavních oblastech systému Android, které jsou běžně zobrazovány ve světlém motivu (například Nastavení), se použije tmavý motiv."</string>
<string name="color_apply" msgid="9212602012641034283">"Použít"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Ověření nastavení"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Některá nastavení barev mohou způsobit, že zařízení nebude použitelné. Kliknutím na OK toto nastavení barev potvrdíte, v opačném případě se nastavení po 10 sekundách resetuje."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Baterie (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omezuje výkon a data na pozadí"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Plocha"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Poslední"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zpět"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Zobrazovat panel Nerušit v dialogu Hlasitost"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Umožňuje povolit úplné ovládání režimu Nerušit v dialogu Hlasitost."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hlasitost a režim Nerušit"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Při snížení hlasitosti přejít do režimu Nerušit"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazit včetně ovládacích prvků hlasitosti"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušit"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Zkratka tlačítek hlasitosti"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Při zvýšení hlasitosti ukončit režim Nerušit"</string>
<string name="battery" msgid="7498329822413202973">"Baterie"</string>
<string name="clock" msgid="7416090374234785905">"Hodiny"</string>
<string name="headset" msgid="4534219457597457353">"Náhlavní souprava"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Sluchátka připojena"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Náhlavní souprava připojena"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Umožňuje aktivovat nebo deaktivovat zobrazení ikon na stavovém řádku."</string>
<string name="data_saver" msgid="5037565123367048522">"Spořič dat"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Spořič dat je zapnutý"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Spořič dat je vypnutý"</string>
<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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Vyberte klávesu na klávesnici"</string>
<string name="preview" msgid="9077832302472282938">"Náhled"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dlaždice přidáte přetažením"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Upravit"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Čas"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Zobrazovat hodiny, minuty a sekundy"</item>
+ <item msgid="1427801730816895300">"Zobrazovat hodiny a minuty (výchozí nastavení)"</item>
+ <item msgid="3830170141562534721">"Tuto ikonu nezobrazovat"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Vždy zobrazovat procento"</item>
+ <item msgid="2139628951880142927">"Zobrazovat procento při nabíjení (výchozí nastavení)"</item>
+ <item msgid="3327323682209964956">"Tuto ikonu nezobrazovat"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Čára rozdělující obrazovku"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Přesunout dolů"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Přesunout nahoru"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Přesunout vlevo"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Přesunout vpravo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1919842de314..f4987d7f4852 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Skærmbilledet er gemt."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Tryk for at se dit skærmbillede."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Skærmbilledet kunne ikke tages."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Skærmbilledet kan ikke tages pga. begrænset lagerplads, eller det tillades ikke af appen eller din organisation."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Skærmbilledet kan ikke gemmes pga. begrænset lagerplads."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Appen eller din organisation tillader ikke, at du tager skærmbilleder."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Muligheder for USB-filoverførsel"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Isæt som en medieafspiller (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Isæt som et kamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mere tid."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelygten er slået fra."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelygten er slået til."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelygten er slået fra."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelygten er slået til."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"bliv i app"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er deaktiveret i sikker tilstand."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historik"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ryd"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Denne app understøtter ikke flere vinduer"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen understøtter ikke flere vinduer"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nstilhed"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Oplader (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hurtig opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langsom opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
<string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivér bevægelsen stryg opad for at dele skærmen"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivér bevægelsen Stryg opad for at dele skærmen"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivér bevægelse for at dele skærmen ved at stryge opad fra knappen Oversigt"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Anvend for underretninger vedrørende <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Anvend for alle underretninger fra denne app"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blokeret"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Lille vigtighed"</string>
<string name="default_importance" msgid="8192107689995742653">"Normal vigtighed"</string>
<string name="high_importance" msgid="1527066195614050263">"Stor vigtighed"</string>
<string name="max_importance" msgid="5089005872719563894">"Presserende vigtighed"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Vis aldrig disse underretninger"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Vis lydløst nederst på listen over underretninger"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse underretninger lydløst"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på listen over underretninger, og giv lyd"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Vis på skærmen, og giv lyd"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Almindelige farver"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nattefarver"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Tilpassede farver"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisk"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Ukendte farver"</string>
- <string name="color_transform" msgid="6985460408079086090">"Farveændring"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Vis feltet Hurtige indstillinger"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Aktivér tilpasset farveændring"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Farve og udseende"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nattilstand"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrer skærmen"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Til"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Fra"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Slå automatisk til"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Skift til natfunktion alt efter stedet og tidspunktet"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Når natfunktion er slået til"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Brug mørkt tema til Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Juster farvetonen"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Juster lysstyrken"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Det mørke tema anvendes på centrale områder i Android OS, der normalt vises med lyst tema, f.eks. Indstillinger."</string>
<string name="color_apply" msgid="9212602012641034283">"Anvend"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Bekræft indstillingerne"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Nogle farveindstillinger kan medføre, at du ikke kan bruge enheden. Klik på OK for at bekræfte disse farveindstillinger. Ellers nulstilles disse indstillinger efter ti sekunder."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batteri (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reducerer ydeevne og baggrundsdata"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Vis Forstyr ikke i Lydstyrke"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Tillad fuld kontrol over Forstyr ikke i dialogboksen Lydstyrke."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Lydstyrke og Forstyr ikke"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Aktivér Forstyr ikke med Lydstyrke ned"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med lydstyrkeregulering"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Forstyr ikke"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Genvej til lydstyrkeknapper"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Afslut Forstyr ikke med Lydstyrke op"</string>
<string name="battery" msgid="7498329822413202973">"Batteri"</string>
<string name="clock" msgid="7416090374234785905">"Ur"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Hovedtelefoner er tilsluttet"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset er forbundet"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Slå visning af ikoner i statusbjælken til eller fra."</string>
<string name="data_saver" msgid="5037565123367048522">"Datasparefunktion"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datasparefunktionen er slået til"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datasparefunktionen er slået fra"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Vælg tastaturknap"</string>
<string name="preview" msgid="9077832302472282938">"Eksempelvisning"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Træk for at tilføje felter"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Rediger"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Tid"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Vis timer, minutter og sekunder"</item>
+ <item msgid="1427801730816895300">"Vis timer og minutter (standard)"</item>
+ <item msgid="3830170141562534721">"Vis ikke dette ikon"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Vis altid procent"</item>
+ <item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
+ <item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til delt skærm"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flyt ned"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flyt op"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flyt til venstre"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flyt til højre"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b69ef339e42e..ac0adbb4259b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot aufgenommen"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Zum Ansehen berühren"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot konnte nicht aufgenommen werden."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Screenshot nicht möglich. Entweder zu wenig Speicher oder die App/dein Unternehmen lässt dies nicht zu."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Speichern des Screenshots aufgrund von zu wenig Speicher nicht möglich."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Die App oder Ihr Unternehmen lässt das Erstellen von Screenshots nicht zu."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-Dateiübertragungsoptionen"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Als Medienplayer (MTP) bereitstellen"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Als Kamera (PTP) bereitstellen"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mehr Zeit"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Weniger Zeit"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taschenlampe deaktiviert"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taschenlampe aktiviert"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Die Taschenlampe ist deaktiviert."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Die Taschenlampe ist aktiviert."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Bildschirmfixierung"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ist im abgesicherten Modus deaktiviert."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Verlauf"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Löschen"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Diese App unterstützt den Mehrfenstermodus nicht"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App unterstützt Mehrfenstermodus nicht"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Laut-\nlos"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Nur\nwichtige"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Nur\nWecker"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Wird schnell aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wird langsam aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
<string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiviert die Bewegung zum Teilen des Bildschirms, bei der von der Schaltfläche \"Übersicht\" nach oben gewischt wird"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivieren"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Für Benachrichtigungen über <xliff:g id="TOPIC_NAME">%1$s</xliff:g> anwenden"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Auf alle Benachrichtigungen dieser App anwenden"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blockiert"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Geringe Wichtigkeit"</string>
<string name="default_importance" msgid="8192107689995742653">"Reguläre Wichtigkeit"</string>
<string name="high_importance" msgid="1527066195614050263">"Hohe Wichtigkeit"</string>
<string name="max_importance" msgid="5089005872719563894">"Sehr hohe Wichtigkeit"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Diese Benachrichtigungen niemals anzeigen"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Ohne Ton am Ende der Benachrichtigungsliste anzeigen"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mit Ton ganz oben in der Benachrichtigungsliste anzeigen"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mit Ton auf dem Display einblenden"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
<string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Standardfarben"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nachtfarben"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Benutzerdefinierte Farben"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisch"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Unbekannte Farben"</string>
- <string name="color_transform" msgid="6985460408079086090">"Farben ändern"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Kachel \"Schnelleinstellungen\" anzeigen"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Benutzerdefinierte Anpassung aktivieren"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Farbe und Darstellung"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nachtmodus"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Bildschirm kalibrieren"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"An"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Aus"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Automatisch aktivieren"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Abhängig von Standort und Tageszeit in den Nachtmodus wechseln"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Bei aktiviertem Nachtmodus"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Dunkles Design unter Android OS verwenden"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Farbton anpassen"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Helligkeit anpassen"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Das dunkle Design wird unter Android OS in allen Hauptbereichen übernommen, die normalerweise hell dargestellt werden, wie beispielsweise Einstellungen."</string>
<string name="color_apply" msgid="9212602012641034283">"Übernehmen"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Einstellungen bestätigen"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Einige Farbeinstellungen können dazu führen, dass das Gerät nicht mehr genutzt werden kann. Klicke auf \"OK\", um diese Farbeinstellungen zu bestätigen. Anderenfalls werden diese Einstellungen in 10 Sekunden zurückgesetzt."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Akku (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduzierung der Leistung und Hintergrunddaten"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startseite"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Letzte"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Zurück"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"\"Bitte nicht stören\" bei der Lautstärkeregelung anzeigen"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Volle Kontrolle von \"Bitte nicht stören\" im kleinen Fenster zur Lautstärkeregelung erlauben."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Lautstärke und \"Bitte nicht stören\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"\"Bitte nicht stören\" bei \"Leiser\" aktivieren"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Einschließlich Lautstärkeregler anzeigen"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bitte nicht stören"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Tastenkombination für Lautstärketasten"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"\"Bitte nicht stören\" bei \"Lauter\" deaktivieren"</string>
<string name="battery" msgid="7498329822413202973">"Akku"</string>
<string name="clock" msgid="7416090374234785905">"Uhr"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Mit Kopfhörer verbunden"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Mit Headset verbunden"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Symbole in der Statusleiste ein- bzw. ausblenden"</string>
<string name="data_saver" msgid="5037565123367048522">"Datenkomprimierung"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datenkomprimierung aktiviert"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datenkomprimierung deaktiviert"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Taste auswählen"</string>
<string name="preview" msgid="9077832302472282938">"Vorschau"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Zum Hinzufügen von Kacheln ziehen"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Bearbeiten"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Uhrzeit"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Stunden, Minuten und Sekunden anzeigen"</item>
+ <item msgid="1427801730816895300">"Stunden und Minuten anzeigen (Standardeinstellung)"</item>
+ <item msgid="3830170141562534721">"Dieses Symbol nicht anzeigen"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Prozentwert immer anzeigen"</item>
+ <item msgid="2139628951880142927">"Prozentwert beim Laden anzeigen (Standardeinstellung)"</item>
+ <item msgid="3327323682209964956">"Dieses Symbol nicht anzeigen"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Bildschirmteiler"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Nach unten verschieben"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Nach oben verschieben"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Nach links verschieben"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Nach rechts verschieben"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 31df4da96bcc..754c92e240c9 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Λήφθηκε το στιγμιότυπο οθόνης ."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Αγγίξτε για να δείτε το στιγμιότυπο οθόνης σας"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Αδύνατη λήψη στιγμ. οθόνης λόγω περιορισμένου αποθ.χώρου ή αποκλεισμού από εφαρμογή ή οργανισμό."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Δεν είναι δυνατή η αποθήκευση του στιγμιότυπου οθόνης λόγω περιορισμένου χώρου αποθήκευσης."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Η λήψη στιγμιοτύπων οθόνης δεν επιτρέπεται από την εφαρμογή ή από τον οργανισμό σας."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Επιλογές μεταφοράς αρχείων μέσω USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Προσάρτηση ως μονάδας αναπαραγωγής μέσων (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Προσάρτηση ως κάμερας (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Περισσότερη ώρα."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Λιγότερη ώρα."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ανενεργός φακός."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ενεργός φακός."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ο φακός απενεργοποιήθηκε."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ο φακός ενεργοποιήθηκε."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> έχει απενεργοποιηθεί στην ασφαλή λειτουργία."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Ιστορικό"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Εκκαθάριση"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Η εφαρμογή αυτή δεν υποστηρίζει τη λειτουργία πολλαπλών παραθύρων"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Η εφαρμογή δεν υποστηρίζει τη λειτουργία πολλαπλών παραθύρων"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Πλήρης\nσίγαση"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Μόνο\nπροτεραιότητας"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Μόνο\nειδοποιήσεις"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Όλα"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Όλες\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Γρήγορη φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Αργή φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
<string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ενεργοποίηση επιτάχυνσης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ενεργοποίηση κίνησης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ενεργοποίηση κίνησης για μετάβαση σε διαχωρισμό οθόνης μέσω ολίσθησης επάνω από το κουμπί \"Επισκόπηση\""</string>
<string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ενεργοποίηση"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Να εφαρμοστεί στις ειδοποιήσεις <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Να εφαρμοστεί σε όλες τις ειδοποιήσεις από αυτήν την εφαρμογή"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Αποκλεισμένες"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Μικρής βαρύτητας"</string>
<string name="default_importance" msgid="8192107689995742653">"Κανονικής βαρύτητας"</string>
<string name="high_importance" msgid="1527066195614050263">"Μεγάλης βαρύτητας"</string>
<string name="max_importance" msgid="5089005872719563894">"Επείγουσες"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Να εμφανίζονται στο κάτω τμήμα της λίστας ειδοποιήσεων χωρίς τίτλο"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων με ήχο"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Να προβάλλονται στην οθόνη και να συνοδεύονται από κάποιον ήχο"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
<string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Κανονικά χρώματα"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Νυχτερινά χρώματα"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Προσαρμοσμένα χρώματα"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Αυτόματο"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Άγνωστα χρώματα"</string>
- <string name="color_transform" msgid="6985460408079086090">"Τροποποίηση χρωμάτων"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Εμφάνιση πλακιδίου Γρήγορων ρυθμίσεων"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Ενεργοποίηση προσαρμοσμένου μετασχηματισμού"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Χρώμα και εμφάνιση"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Νυχτερινή λειτουργία"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Βαθμονόμηση οθόνης"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Ενεργή"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Ανενεργή"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Αυτόματη ενεργοποίηση"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Αλλαγή σε νυχτερινή λειτουργία όπως απαιτείται βάσει τοποθεσίας και ώρας της ημέρας"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Όταν είναι ενεργή η νυχτερινή λειτουργία"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Χρήση σκοτεινού θέματος για Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ρύθμιση απόχρωσης"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ρύθμιση φωτεινότητας"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Το σκούρο θέμα εφαρμόζεται σε βασικές περιοχές του λειτουργικού συστήματος Android οι οποίες συνήθως εμφανίζονται με φωτεινό θέμα, όπως οι Ρυθμίσεις."</string>
<string name="color_apply" msgid="9212602012641034283">"Εφαρμογή"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Επιβεβαίωση ρυθμίσεων"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Ορισμένες ρυθμίσεις χρωμάτων μπορεί να μην επιτρέπουν τη χρήση αυτής της συσκευής. Κάντε κλικ στην επιλογή OK για να επιβεβαιώσετε αυτές τις ρυθμίσεις χρωμάτων, διαφορετικά θα γίνει επαναφορά αυτών των ρυθμίσεων μετά από 10 δευτερόλεπτα."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Μπαταρία (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Αρχική οθόνη"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Πρόσφατα"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Πίσω"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Εμφάνιση λειτουργίας \"Μην ενοχλείτε\" στην ένταση ήχου"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Να επιτρέπεται ο πλήρης έλεγχος της λειτουργίας \"Μην ενοχλείτε\" στο παράθυρο διαλόγου ελέγχου έντασης."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ένταση ήχου και λειτουργία \"Μην ενοχλείτε\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Ενεργοποίηση λειτουργίας \"Μην ενοχλείτε\" κατά τη μείωση της έντασης ήχου"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Εμφάνιση με στοιχεία ελέγχου έντασης ήχου"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Μην ενοχλείτε"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Συντόμευση κουμπιών έντασης ήχου"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Απενεργοποίηση λειτουργίας \"Μην ενοχλείτε\" κατά την αύξηση της έντασης ήχου"</string>
<string name="battery" msgid="7498329822413202973">"Μπαταρία"</string>
<string name="clock" msgid="7416090374234785905">"Ρολόι"</string>
<string name="headset" msgid="4534219457597457353">"Ακουστικά"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Τα ακουστικά συνδέθηκαν"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Τα ακουστικά συνδέθηκαν"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ενεργοποίηση ή απενεργοποίηση εμφάνιση εικονιδίων στη γραμμή κατάστασης."</string>
<string name="data_saver" msgid="5037565123367048522">"Εξοικονόμηση δεδομένων"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Η Εξοικονόμηση δεδομένων είναι ενεργοποιημένη"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Η Εξοικονόμηση δεδομένων είναι απενεργοποιημένη"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Επιλογή κουμπιού πληκτρολογίου"</string>
<string name="preview" msgid="9077832302472282938">"Προεπισκόπηση"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Σύρετε για να προσθέσετε πλακίδια"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Επεξεργασία"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Ώρα"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Να εμφανίζονται ώρες, λεπτά και δευτερόλεπτα"</item>
+ <item msgid="1427801730816895300">"Να εμφανίζονται ώρες και λεπτά (προεπιλογή)"</item>
+ <item msgid="3830170141562534721">"Να μην εμφανίζεται αυτό το εικονίδιο"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Να εμφανίζεται πάντα ποσοστό"</item>
+ <item msgid="2139628951880142927">"Να εμφανίζεται ποσοστό κατά τη φόρτιση (προεπιλογή)"</item>
+ <item msgid="3327323682209964956">"Να μην εμφανίζεται αυτό το εικονίδιο"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Διαχωριστικό οθόνης"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Μετακίνηση προς τα κάτω"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Μετακίνηση προς τα επάνω"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Μετακίνηση αριστερά"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Μετακίνηση δεξιά"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 783536f2ee97..cbb1ecf577a1 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organisation."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Can\'t save screenshot due to limited storage space."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Taking screenshots is not allowed by the app or your organisation."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"More time."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Less time."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torch off."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torch unavailable."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torch on."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torch turned off."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torch turned on."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nsilence"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"All\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Enable split-screen swipe-up accelerator"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Show notifications silently"</string>
+ <string name="block" msgid="2734508760962682611">"Block all notifications"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Don\'t silence"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Don\'t silence or block"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Show full importance settings"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Min importance"</string>
<string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
<string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
<string name="high_importance" msgid="1527066195614050263">"High importance"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Silently show at the bottom of the notification list"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Silently show these notifications"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Allow these notifications to make sounds"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Peek on to the screen and allow sound"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Show at the top of the notifications list, peek on to the screen and allow sound"</string>
<string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
<string name="notification_done" msgid="5279426047273930175">"Finished"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
- <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Colour and appearance"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrate display"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"On"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Off"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Turn on automatically"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Switch into Night Mode as appropriate for location and time of day"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"When Night Mode is on"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Use dark theme for Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Adjust tint"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Adjust brightness"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"The dark theme is applied to core areas of Android OS that are normally displayed in a light theme, such as Settings."</string>
<string name="color_apply" msgid="9212602012641034283">"Apply"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Show Do Not Disturb in volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Allow full control of Do Not Disturb in the volume dialogue."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume and Do Not Disturb"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Enter Do Not Disturb on volume down"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Exit Do Not Disturb on volume up"</string>
<string name="battery" msgid="7498329822413202973">"Battery"</string>
<string name="clock" msgid="7416090374234785905">"Clock"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphones connected"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset connected"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Enable or disable icons from being shown in the status bar."</string>
<string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver is on"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver is off"</string>
<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>
@@ -508,7 +519,7 @@
<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">"Savings"</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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
<string name="preview" msgid="9077832302472282938">"Preview"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"(edit)"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Time"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Show hours, minutes and seconds"</item>
+ <item msgid="1427801730816895300">"Show hours and minutes (default)"</item>
+ <item msgid="3830170141562534721">"Don\'t show this icon"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Always show percentage"</item>
+ <item msgid="2139628951880142927">"Show percentage when charging (default)"</item>
+ <item msgid="3327323682209964956">"Don\'t show this icon"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Other"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Split screen divider"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Move down"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 783536f2ee97..cbb1ecf577a1 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organisation."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Can\'t save screenshot due to limited storage space."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Taking screenshots is not allowed by the app or your organisation."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"More time."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Less time."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torch off."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torch unavailable."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torch on."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torch turned off."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torch turned on."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nsilence"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"All\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Enable split-screen swipe-up accelerator"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Show notifications silently"</string>
+ <string name="block" msgid="2734508760962682611">"Block all notifications"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Don\'t silence"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Don\'t silence or block"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Show full importance settings"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Min importance"</string>
<string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
<string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
<string name="high_importance" msgid="1527066195614050263">"High importance"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Silently show at the bottom of the notification list"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Silently show these notifications"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Allow these notifications to make sounds"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Peek on to the screen and allow sound"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Show at the top of the notifications list, peek on to the screen and allow sound"</string>
<string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
<string name="notification_done" msgid="5279426047273930175">"Finished"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
- <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Colour and appearance"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrate display"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"On"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Off"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Turn on automatically"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Switch into Night Mode as appropriate for location and time of day"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"When Night Mode is on"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Use dark theme for Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Adjust tint"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Adjust brightness"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"The dark theme is applied to core areas of Android OS that are normally displayed in a light theme, such as Settings."</string>
<string name="color_apply" msgid="9212602012641034283">"Apply"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Show Do Not Disturb in volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Allow full control of Do Not Disturb in the volume dialogue."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume and Do Not Disturb"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Enter Do Not Disturb on volume down"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Exit Do Not Disturb on volume up"</string>
<string name="battery" msgid="7498329822413202973">"Battery"</string>
<string name="clock" msgid="7416090374234785905">"Clock"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphones connected"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset connected"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Enable or disable icons from being shown in the status bar."</string>
<string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver is on"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver is off"</string>
<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>
@@ -508,7 +519,7 @@
<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">"Savings"</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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
<string name="preview" msgid="9077832302472282938">"Preview"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"(edit)"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Time"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Show hours, minutes and seconds"</item>
+ <item msgid="1427801730816895300">"Show hours and minutes (default)"</item>
+ <item msgid="3830170141562534721">"Don\'t show this icon"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Always show percentage"</item>
+ <item msgid="2139628951880142927">"Show percentage when charging (default)"</item>
+ <item msgid="3327323682209964956">"Don\'t show this icon"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Other"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Split screen divider"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Move down"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 783536f2ee97..cbb1ecf577a1 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organisation."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Can\'t save screenshot due to limited storage space."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Taking screenshots is not allowed by the app or your organisation."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"More time."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Less time."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torch off."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torch unavailable."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torch on."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torch turned off."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torch turned on."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is disabled in safe-mode."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Clear"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"This app does not support multi-window"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App does not support multi-window"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nsilence"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"All\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Enable split-screen swipe-up accelerator"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Show notifications silently"</string>
+ <string name="block" msgid="2734508760962682611">"Block all notifications"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Don\'t silence"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Don\'t silence or block"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Show full importance settings"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Min importance"</string>
<string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
<string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
<string name="high_importance" msgid="1527066195614050263">"High importance"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Silently show at the bottom of the notification list"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Silently show these notifications"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Allow these notifications to make sounds"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Peek on to the screen and allow sound"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Show at the top of the notifications list, peek on to the screen and allow sound"</string>
<string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
<string name="notification_done" msgid="5279426047273930175">"Finished"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
- <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Colour and appearance"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrate display"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"On"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Off"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Turn on automatically"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Switch into Night Mode as appropriate for location and time of day"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"When Night Mode is on"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Use dark theme for Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Adjust tint"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Adjust brightness"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"The dark theme is applied to core areas of Android OS that are normally displayed in a light theme, such as Settings."</string>
<string name="color_apply" msgid="9212602012641034283">"Apply"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduces performance and background data"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Back"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Show Do Not Disturb in volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Allow full control of Do Not Disturb in the volume dialogue."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume and Do Not Disturb"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Enter Do Not Disturb on volume down"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Show with volume controls"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Do not disturb"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Volume buttons shortcut"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Exit Do Not Disturb on volume up"</string>
<string name="battery" msgid="7498329822413202973">"Battery"</string>
<string name="clock" msgid="7416090374234785905">"Clock"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphones connected"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset connected"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Enable or disable icons from being shown in the status bar."</string>
<string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver is on"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver is off"</string>
<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>
@@ -508,7 +519,7 @@
<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">"Savings"</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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Select Keyboard Button"</string>
<string name="preview" msgid="9077832302472282938">"Preview"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Drag to add tiles"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"(edit)"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Time"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Show hours, minutes and seconds"</item>
+ <item msgid="1427801730816895300">"Show hours and minutes (default)"</item>
+ <item msgid="3830170141562534721">"Don\'t show this icon"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Always show percentage"</item>
+ <item msgid="2139628951880142927">"Show percentage when charging (default)"</item>
+ <item msgid="3327323682209964956">"Don\'t show this icon"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Other"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Split screen divider"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Move down"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Move up"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 47b50382b8b5..f3c21df871ae 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Se guardó la captura de pantalla."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver tu captura de pantalla."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"No se pudo guardar la captura de pantalla."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Error de captura por almacenamiento limitado o porque la aplicación u organización no lo permiten."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"No se puede guardar la captura de pantalla debido al almacenamiento limitado."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"La app o tu organización no permiten las capturas de pantalla."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Fijar pantalla"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> está inhabilitada en modo seguro."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta app no es compatible con el modo multiventana"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"La app no es compatible con el modo multiventana"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\nprioridad"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Todo"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todo\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carga rápida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carga lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Deslizar el dedo hacia arriba para dividir la pantalla"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar gesto de dedo hacia arriba para dividir pantalla"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Recientes para acceder al modo de pantalla dividida"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a las notificaciones de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas las notificaciones de esta app"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Poca importancia"</string>
<string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar nunca estas notificaciones"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar en la parte inferior de la lista de notificaciones sin emitir sonido"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de manera silenciosa"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automático"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Colores desconocidos"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificación del color"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar el mosaico de Configuración rápida"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Habilitar la transformación personalizada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Color y apariencia"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Activado"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desactivado"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activar automáticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Cambiar a modo nocturno según corresponda en relación con la ubicación y hora del día"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Cuando el modo nocturno está activado"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Usar tema oscuro para el SO Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tinte"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brillo"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"El tema oscuro se aplica en las áreas principales del SO Android que suelen mostrarse con un tema claro, como Configuración."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar la configuración"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algunas opciones de configuración de color pueden provocar que el dispositivo quede inutilizable. Haz clic en Aceptar para confirmar estos parámetros de color. De lo contrario, la configuración se restablecerá en diez segundos."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batería (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y el uso de datos en segundo plano"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pantalla principal"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar el panel de control de No interrumpir en el volumen"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir el control total del modo No interrumpir en el cuadro de diálogo de volumen."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumen y No interrumpir"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Activar el modo No interrumpir al bajar el volumen"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No interrumpir"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas de botones de volumen"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Desactivar el modo No interrumpir al subir el volumen"</string>
<string name="battery" msgid="7498329822413202973">"Batería"</string>
<string name="clock" msgid="7416090374234785905">"Reloj"</string>
<string name="headset" msgid="4534219457597457353">"Auriculares"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Habilitar o inhabilitar la visualización de los íconos en la barra de estado"</string>
<string name="data_saver" msgid="5037565123367048522">"Reducir datos"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Reducir datos está activada"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Reducir datos está desactivada"</string>
<string name="switch_bar_on" msgid="1142437840752794229">"Activado"</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">"Iniciar"</string>
<string name="center" msgid="4327473927066010960">"Centro"</string>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Selecciona un botón del teclado"</string>
<string name="preview" msgid="9077832302472282938">"Vista previa"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastra los mosaicos para agregarlos"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostrar horas, minutos y segundos"</item>
+ <item msgid="1427801730816895300">"Mostrar horas y minutos (predeterminado)"</item>
+ <item msgid="3830170141562534721">"No mostrar este ícono"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Siempre mostrar el porcentaje"</item>
+ <item msgid="2139628951880142927">"Mostrar el porcentaje durante la carga (predeterminado)"</item>
+ <item msgid="3327323682209964956">"No mostrar este ícono"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover hacia abajo"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ae1c3c8c2f66..bd9cc000e948 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captura guardada"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver la captura de pantalla"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"No se ha podido guardar la captura de pantalla."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Error al hacer captura por límite almacenamiento o porque aplicación u organización no lo permiten."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"No se puede guardar la captura de pantalla porque no hay espacio de almacenamiento suficiente."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"La aplicación o tu organización no permiten que se realicen capturas de pantalla."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Activar como cámara (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada."</string>
@@ -301,8 +304,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fijación de pantalla"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación no admite el modo multiventana."</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"La aplicación no admite el modo multiventana"</string>
<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>
@@ -332,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\ncon prioridad"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Todo"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todo\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
@@ -446,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Habilitar deslizar el dedo hacia arriba para dividir la pantalla"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar deslizar dedo hacia arriba para dividir pantalla"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Visión general para acceder al modo de pantalla dividida"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a las notificaciones de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas las notificaciones de esta aplicación"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Poco importante"</string>
<string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Muy importante"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar estas notificaciones"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automático"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Colores desconocidos"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificación de colores"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar mosaico de Ajustes rápidos"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Habilitar transformación personalizada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Color y aspecto"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Sí"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"No"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activar automáticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Cambiar al modo nocturno cuando proceda según la ubicación y la hora del día"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Cuando el modo nocturno esté activado"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Tema oscuro para sistema operativo Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tono"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brillo"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"El tema oscuro se aplica a las áreas principales del sistema operativo Android que normalmente se muestran con un tema claro, como la aplicación Ajustes."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar configuración"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algunas opciones de configuración de color pueden hacer que el dispositivo no se pueda utilizar. Haz clic en Aceptar para confirmar esta configuración. Si no lo haces, se restablecerá esta configuración cuando transcurran 10 segundos."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batería (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y las conexiones automáticas"</string>
@@ -485,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recientes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atrás"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar el panel de control de No molestar en el volumen"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir un control total del modo No molestar en el cuadro de diálogo de volumen."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumen y No molestar"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Activar No molestar al bajar el volumen"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar con controles de volumen"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"No molestar"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Combinación de teclas para los botones de volumen"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Salir de No molestar al subir el volumen"</string>
<string name="battery" msgid="7498329822413202973">"Batería"</string>
<string name="clock" msgid="7416090374234785905">"Reloj"</string>
<string name="headset" msgid="4534219457597457353">"Auriculares"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Permite mostrar u ocultar iconos en la barra de estado"</string>
<string name="data_saver" msgid="5037565123367048522">"Economizador de datos"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizador de datos activado"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizador de datos desactivado"</string>
<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>
@@ -521,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Selecciona un botón de teclado"</string>
<string name="preview" msgid="9077832302472282938">"Vista previa"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastrar para añadir mosaicos"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Cambiar"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostrar horas, minutos y segundos"</item>
+ <item msgid="1427801730816895300">"Mostrar horas y minutos (predeterminado)"</item>
+ <item msgid="3830170141562534721">"No mostrar este icono"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Mostrar porcentaje siempre"</item>
+ <item msgid="2139628951880142927">"Mostrar porcentaje durante la carga (predeterminado)"</item>
+ <item msgid="3327323682209964956">"No mostrar este icono"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Dividir la pantalla"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Bajar"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index eae5ea7e5869..1279a2c083d3 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Puudutage kuvatõmmise vaatamiseks."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekraanipilti ei saa jäädvustada piiratud talletusruumi tõttu või ei luba seda rakendus/organisatsioon."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Piiratud salvestusruumi tõttu ei saa ekraanipilti salvestada."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-failiedastuse valikud"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Paigalda meediumimängijana (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Paigalda kaamerana (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Pikem aeg."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Lühem aeg."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taskulamp on väljas."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taskulamp pole saadaval."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taskulamp on sees."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Taskulamp on välja lülitatud."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Taskulamp on sisse lülitatud."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekraanikuva kinnitamine"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Rakendus <xliff:g id="APP">%s</xliff:g> on turvarežiimis keelatud."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Ajalugu"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Kustuta"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"See rakendus ei toeta mitut akent"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Rakendus ei toeta mitut akent"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Täielik\nvaikus"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Ainult\nprioriteetsed"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ainult\nalarmid"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Kõik"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Kõik\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Kiirlaadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Aeglane laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
<string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Luba ülespühkimise kiirendi ekraani poolitamiseks"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Luba ülespühkimise liigutus ekraani poolitamiseks"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Lubab žesti, mis poolitab ekraani, kui kasutaja pühib üles nupul Ülevaade."</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Lülita sisse"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Rakenda teema <xliff:g id="TOPIC_NAME">%1$s</xliff:g> märguannete puhul"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Rakenda selle rakenduse kõigi märguannete puhul"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Kuva märguanded vaikselt"</string>
+ <string name="block" msgid="2734508760962682611">"Blokeeri kõik märguanded"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ära vaigista"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ära vaigista ega blokeeri"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Kuva täieliku tähtsuse seaded"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokeeritud"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Minimaalne tähtsus"</string>
<string name="low_importance" msgid="4109929986107147930">"Madal tähtsuse tase"</string>
<string name="default_importance" msgid="8192107689995742653">"Tavaline tähtsuse tase"</string>
<string name="high_importance" msgid="1527066195614050263">"Kõrge tähtsuse tase"</string>
<string name="max_importance" msgid="5089005872719563894">"Kiireloomuline tähtsuse tase"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ära kunagi näita neid märguandeid"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Kuva märguannete loendi allosas vaikselt"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Kuva need märguanded vaikselt"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Kuva märguannete loendi ülaosas koos heliga"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Kuva ekraani servas koos heliga"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Kuva märguannete loendi allosas vaikselt"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Kuva need märguanded vaikselt"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Luba nende märguannete puhul heli"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Kuva ekraani servas ja luba heli"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Kuva märguannete loendi ülaservas, kuva ekraani servas ja luba heli"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Tavalised värvid"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Öised värvid"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Kohandatud värvid"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automaatne"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Värvid on teadmata"</string>
- <string name="color_transform" msgid="6985460408079086090">"Värvi muutmine"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Kuva paan Kiirseaded"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Luba kohandatud teisendamine"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Värv ja ilme"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Öörežiim"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Ekraani kalibreerimine"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Sees"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Väljas"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Lülita automaatselt sisse"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Lülita öörežiimile, kui see on asukoha ja kellaaja suhtes sobilik"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kui öörežiim on sees"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Kasuta Android OS-is tumedat teemat"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Reguleeri tooni"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Reguleeri heledust"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tume teema rakendatakse Android OS-i põhialadele, mis kuvatakse tavaliselt heleda teemaga (nt seaded)."</string>
<string name="color_apply" msgid="9212602012641034283">"Rakenda"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Seadete kinnitamine"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Mõni värviseade ei saa seadet võib-olla kasutada. Nende värviseadete kinnitamiseks klõpsake OK, muidu lähtestatakse need seaded 10 sekundi pärast."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Aku (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vähendab jõudlust ja taustaandmeid"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Avaekraan"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Hiljutised"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tagasi"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Kuva helitugevuse juures funktsioon Mitte segada"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Helitugevuse dialoogis lubatakse funktsiooni Mitte segada täielik juhtimine."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Helitugevus ja funktsioon Mitte segada"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Lülita helitugevuse vähendamisel sisse funkt. Mitte segada"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Kuva koos helitugevuse juhtnuppudega"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mitte segada"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Helitugevuse nuppude otsetee"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Lülita helitugevuse suurendamisel välja funkt. Mitte segada"</string>
<string name="battery" msgid="7498329822413202973">"Aku"</string>
<string name="clock" msgid="7416090374234785905">"Kell"</string>
<string name="headset" msgid="4534219457597457353">"Peakomplekt"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Kõrvaklapid on ühendatud"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Peakomplekt on ühendatud"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Lubatakse või keelatakse ikoonide kuvamine olekuribal."</string>
<string name="data_saver" msgid="5037565123367048522">"Andmemahu säästja"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Andmemahu säästja on sisse lülitatud"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Andmemahu säästja on välja lülitatud"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatuuri nupu valimine"</string>
<string name="preview" msgid="9077832302472282938">"Eelvaade"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Lohistage paanide lisamiseks"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Muuda"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Kellaaeg"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Kuva tunnid, minutid ja sekundid"</item>
+ <item msgid="1427801730816895300">"Kuva tunnid ja minutid (vaikimisi)"</item>
+ <item msgid="3830170141562534721">"Ära kuva seda ikooni"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Kuva alati protsent"</item>
+ <item msgid="2139628951880142927">"Kuva protsent laadimisel (vaikimisi)"</item>
+ <item msgid="3327323682209964956">"Ära kuva seda ikooni"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Muu"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Ekraanijagaja"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Liigu alla"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Liigu üles"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Liigu vasakule"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Liigu paremale"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index f8ac7f2282bb..a245bf7d3b75 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Pantaila-argazkia atera da."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Pantaila-argazkia ikusteko, ukitu ezazu."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Ezin izan da pantaila-argazkia atera."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Ezin da atera pantaila-argazkia tokirik geratzen ez delako edo horrelakorik onartzen ez delako."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ezin da atera pantaila-argazkia ez delako tokirik geratzen."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikazioak edo erakundeak ez du onartzen pantaila-argazkiak ateratzea."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB fitxategiak transferitzeko aukerak"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Muntatu multimedia-erreproduzigailu gisa (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Muntatu kamera gisa (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Denbora gehiago."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Denbora gutxiago."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flasha desaktibatuta dago."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flasha aktibatuta dago."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flasha desaktibatu egin da."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flasha aktibatu egin da."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pantaila-ainguratzea"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> desgaituta dago modu seguruan."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Garbitu"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Isiltasun\nosoa"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Lehentasunezkoak\nsoilik"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmak\nsoilik"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Guztiak"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Guztiak\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
<string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Gaitu hatza gora pasatuta pantaila zatitzeko bizkortzailea"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Gaitu pantaila zatitzeko keinua hatza gora pasatuta"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Sakatu Ikuspegi nagusia botoia eta gaitu hatza gora pasatuta pantaila zatitzeko keinua"</string>
<string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktibatu"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplikatu \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\" gaiari buruzko jakinarazpenei"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplikatu aplikazio honetako jakinarazpen guztiei"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blokeatuta"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Garrantzi txikia"</string>
<string name="default_importance" msgid="8192107689995742653">"Garrantzi normala"</string>
<string name="high_importance" msgid="1527066195614050263">"Garrantzi handia"</string>
<string name="max_importance" msgid="5089005872719563894">"Premiazkoa"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ez erakutsi jakinarazpen hauek inoiz"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Erakutsi jakinarazpen hauek zerrendaren behealdean, baina soinurik egin gabe"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Erakutsi jakinarazpen hauek zerrendaren goialdean eta egin soinua"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
<string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Kolore normalak"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Gaueko koloreak"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Kolore pertsonalizatuak"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatikoa"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Kolore ezezagunak"</string>
- <string name="color_transform" msgid="6985460408079086090">"Kolore-aldaketa"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Erakutsi ezarpen bizkorren lauza"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Gaitu itxuraldaketa pertsonalizatua"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Kolorea eta itxura"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Gau modua"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibratu pantaila"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aktibatuta"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desaktibatuta"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Aktibatu automatikoki"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Aldatu Gau modura, kokapena eta ordua kontuan izanda"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Gau modua aktibatuta dagoenean"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Erabili gai iluna Android sistema eragilean"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Doitu kolorea"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Doitu distira"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Gai iluna Android sistema eragileko eremu nagusietan aplikatzen da. Normalean gai argian bistaratzen dira eremu horiek, adibidez, Ezarpenak atala."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplikatu"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Berretsi ezarpenak"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Baliteke gailua kolore-ezarpen batzuekin ezin erabili izatea. Kolore-ezarpenak berresteko, sakatu Ados. Bestela, hamar segundoren buruan berrezarriko dira ezarpenak."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (%% <xliff:g id="ID_1">%1$d</xliff:g>)"</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Errendimendua eta atzeko planoko datuen erabilera murrizten ditu"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Hasierako pantaila"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Azkenak"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atzera"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Erakutsi \"Ez molestatu\" aukera bolumenaren leihoan"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Baimendu bolumenaren leihoan \"Ez molestatu\" aukera guztiz kontrolatzea."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Bolumena eta \"Ez molestatu\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Sartu \"Ez molestatu\" egoeran bolumena jaistean"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Erakutsi bolumena kontrolatzeko aukerekin"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ez molestatu"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Bolumen-botoietarako lasterbidea"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Irten \"Ez molestatu\" egoeratik bolumena igotzean"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Erlojua"</string>
<string name="headset" msgid="4534219457597457353">"Mikrofonodun entzungailua"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Aurikularrak konektatu dira"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Mikrofonodun entzungailua konektatu da"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Gaitu edo desgaitu ikonoak egoera-barran erakusteko aukera."</string>
<string name="data_saver" msgid="5037565123367048522">"Datu-aurrezlea"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Aktibatuta dago datu-aurrezlea"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Desaktibatuta dago datu-aurrezlea"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Hautatu teklatuko botoia"</string>
<string name="preview" msgid="9077832302472282938">"Aurrebista"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastatu lauzak hemen gehitzeko"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editatu"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Ordua"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Erakutsi orduak, minutuak eta segundoak"</item>
+ <item msgid="1427801730816895300">"Erakutsi orduak eta minutuak (balio lehenetsia)"</item>
+ <item msgid="3830170141562534721">"Ez erakutsi ikonoa"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Erakutsi beti ehunekoa"</item>
+ <item msgid="2139628951880142927">"Erakutsi ehunekoa kargatu bitartean (balio lehenetsia)"</item>
+ <item msgid="3327323682209964956">"Ez erakutsi ikonoa"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Pantaila-zatitzailea"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Eraman behera"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Eraman gora"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Eraman ezkerrera"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Eraman eskuinera"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1950221fb55d..cc3251858151 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"عکس صفحه‌نمایش گرفته شد."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"برای مشاهده عکس صفحه‌نمایشتان، لمس کنید."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"عکس صفحه‌نمایش گرفته نشد."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"به دلیل فضای ذخیره‌سازی کم یا عدم اجازه برنامه یا سازمانتان، نمی‌توان از صفحه عکس گرفت."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"به دلیل محدود بودن فضای ذخیره‌سازی نمی‌توانید عکس صفحه‌نمایش را ذخیره کنید."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"این برنامه یا سازمان شما اجازه نمی‌دهند عکس صفحه‌نمایش بگیرید."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏گزینه‌های انتقال فایل USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏نصب به‌عنوان دستگاه پخش رسانه (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"‏تصب به‌عنوان دوربین (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"زمان بیشتر."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"زمان کمتر."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"چراغ قوه خاموش است."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"چراغ قوه در دسترس نیست."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"چراغ قوه روشن است."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"چراغ قوه خاموش شد."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"چراغ قوه روشن شد."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"پین کردن صفحه"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> شروع نشد."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> در حالت ایمن غیرفعال است."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"سابقه"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"پاک کردن"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"این برنامه از چندپنجره پشتیبانی نمی‌کند"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"برنامه از چندپنجره پشتیبانی نمی‌کند"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"سکوت\nکامل"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"فقط\nاولویت‌دار"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"فقط\nهشدارها"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"همه"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"همه\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"در حال شارژ سریع (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"در حال شارژ آهسته (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
<string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"فعال کردن شتاب‌دهنده تقسیم صفحه با بالا کشیدن"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"فعال کردن تقسیم صفحه با اشاره بالا کشیدن"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"اشاره ورود به تقسیم صفحه با بالا کشیدن صفحه از دکمه نمای کلی را فعال می‌کند"</string>
<string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحه‌کلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"روشن کردن"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"اعمال بر روی اعلان‌های <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"اعمال بر روی تمام اعلان‌های این برنامه"</string>
+ <string name="show_silently" msgid="6841966539811264192">"نمایش بی‌صدای اعلان‌ها"</string>
+ <string name="block" msgid="2734508760962682611">"مسدود کردن همه اعلان‌ها"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ساکت نشود"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ساکت یا مسدود نشود"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"نمایش تنظیمات کامل اهمیت"</string>
<string name="blocked_importance" msgid="5198578988978234161">"مسدود شده"</string>
+ <string name="min_importance" msgid="1901894910809414782">"کمترین اهمیت"</string>
<string name="low_importance" msgid="4109929986107147930">"اهمیت کم"</string>
<string name="default_importance" msgid="8192107689995742653">"اهمیت معمولی"</string>
<string name="high_importance" msgid="1527066195614050263">"اهمیت زیاد"</string>
<string name="max_importance" msgid="5089005872719563894">"اهمیت فوری"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"هرگز این اعلان‌ها نشان داده نشوند"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"این اعلان‌ها بی‌صدا نشان داده شوند"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"در بالای فهرست اعلان‌ها و به همراه صدا نشان داده شود"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"در جلوی صفحه به همراه صدا نشان داده شود"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"این اعلان‌ها بی‌صدا نشان داده شوند"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"به این اعلان‌ها اجازه داده شود صدادار باشند"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"در صفحه نشان داده شوند و صدادار باشند"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"در بالای فهرست اعلان نشان داده شوند، در صفحه نشان داده شوند و صدادار باشند"</string>
<string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
<string name="notification_done" msgid="5279426047273930175">"تمام"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"رنگ‌های عادی"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"رنگ‌های شب"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"رنگ‌های سفارشی"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"خودکار"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"رنگ‌های نامشخص"</string>
- <string name="color_transform" msgid="6985460408079086090">"اصلاح رنگ"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"نمایش کاشی تنظیمات سریع"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"فعال کردن تبدیل سفارشی"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"رنگ و ظاهر"</string>
+ <string name="night_mode" msgid="3540405868248625488">"حالت شب"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"درجه‌بندی نمایشگر"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"روشن"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"خاموش"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"روشن شدن خودکار"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"تغییر به حالت شب وقتی برای مکان و زمان روز مناسب است"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"وقتی حالت شب روشن است"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"‏استفاده از زمینه تیره برای سیستم‌عامل Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"تنظیم سایه‌رنگ"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"تنظیم روشنایی"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"‏زمینه تیره بر قسمت‌های اصلی سیستم‌عامل Android که به‌طور معمول با زمینه روشن نشان داده می‌شوند (مثل «تنظیمات») اعمال می‌شود."</string>
<string name="color_apply" msgid="9212602012641034283">"اعمال‌ کردن"</string>
<string name="color_revert_title" msgid="4746666545480534663">"تأیید تنظیمات"</string>
<string name="color_revert_message" msgid="9116001069397996691">"بعضی از تنظیمات رنگ می‌توانند این دستگاه را غیرقابل استفاده کنند. برای تأیید این تنظیمات رنگ روی «تأیید» کلیک کنید، در غیر این صورت این تغییرات بعد از ۱۰ ثانیه بازنشانی می‌شوند."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"باتری (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"عملکرد و اطلاعات پس‌زمینه را کاهش می‌دهد"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"صفحه اصلی"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"موارد اخیر"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"برگشت"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"نمایش «مزاحم نشوید» در میزان صدا"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"به حالت «مزاحم نشوید» اجازه داده می‌شود در کادر گفتگوی میزان صدا کنترل کامل داشته باشد."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"میزان صدا و «مزاحم نشوید»"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"وارد شدن به حالت «مزاحم نشوید» در میزان صدای پایین"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"نمایش با کنترل‌های صدا"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"مزاحم نشوید"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"میان‌بر دکمه‌های صدا"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"خارج شدن از حالت «مزاحم نشوید» در میزان صدای بالا"</string>
<string name="battery" msgid="7498329822413202973">"باتری"</string>
<string name="clock" msgid="7416090374234785905">"ساعت"</string>
<string name="headset" msgid="4534219457597457353">"هدست"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"هدفون وصل شد"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"هدست وصل شد"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"فعال یا غیرفعال کردن نمایش نمادها در نوار وضعیت."</string>
<string name="data_saver" msgid="5037565123367048522">"صرفه‌جویی در مصرف داده"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"صرفه‌جویی در مصرف داده روشن است"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"صرفه‌جویی در مصرف داده خاموش است"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"کلید صفحه‌کلید را انتخاب کنید"</string>
<string name="preview" msgid="9077832302472282938">"پیش‌نمایش"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"کشیدن برای افزودن کاشی‌ها"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"ویرایش"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"زمان"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ساعت، دقیقه و ثانیه نشان داده شود"</item>
+ <item msgid="1427801730816895300">"ساعت و دقیقه نشان داده شود (پیش‌فرض)"</item>
+ <item msgid="3830170141562534721">"این نماد نشان داده نشود"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"همیشه درصد نشان داده شود"</item>
+ <item msgid="2139628951880142927">"هنگام شارژ شدن درصد نشان داده شود (پیش‌فرض)"</item>
+ <item msgid="3327323682209964956">"این نماد نشان داده نشود"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"موارد دیگر"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"تقسیم‌کننده صفحه"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"انتقال به پایین"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"انتقال به بالا"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"انتقال به چپ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"انتقال به راست"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index b3f5425ac4aa..22431916583b 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvakaappaus tallennettu"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Katso kuvakaappaus koskettamalla."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Kuvakaappausta ei voitu tallentaa"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Kuvakaappaus ei onnistu, koska tila ei riitä tai koska sovellus tai organisaatiosi ei salli sitä."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kuvakaappauksen tallentaminen epäonnistui, sillä tallennustilaa ei ole riittävästi."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Sovellus tai organisaatiosi ei salli kuvakaappauksien tallentamista."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-tiedostonsiirtoasetukset"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Käytä mediasoittimena (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Käytä kamerana (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lisää aikaa."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Vähennä aikaa."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taskulamppu on pois päältä."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taskulamppu on päällä."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Taskulamppu poistettiin käytöstä."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Taskulamppu otettiin käyttöön."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"näytön kiinnitys"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> on poistettu käytöstä vikasietotilassa."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tyhjennä"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Tämä sovellus ei tue usean ikkunan tilaa."</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Sovellus ei tue usean ikkunan tilaa."</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Täydellinen\nhiljaisuus"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vain\ntärkeät"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vain\nherätykset"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Kaikki"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Kaikki\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nopea lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Hidas lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
<string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ota jaetun näytön tilan pyyhkäisyele käyttöön"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Siirry jaetun näytön tilaan pyyhkäisemällä ylöspäin"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Voit siirtyä jaetun näytön tilaan pyyhkäisemällä Viimeisimmät-painikkeesta ylöspäin."</string>
<string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ota käyttöön"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Sovella aiheen <xliff:g id="TOPIC_NAME">%1$s</xliff:g> ilmoituksiin"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Sovella kaikkiin tämän sovelluksen ilmoituksiin"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Estetyt"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Ei kovin tärkeä"</string>
<string name="default_importance" msgid="8192107689995742653">"Tärkeä"</string>
<string name="high_importance" msgid="1527066195614050263">"Hyvin tärkeä"</string>
<string name="max_importance" msgid="5089005872719563894">"Kiireellinen"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Älä koskaan näytä näitä ilmoituksia"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Näytä huomaamattomasti ilmoitusluettelon alaosassa"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Näytä nämä ilmoitukset huomaamattomasti"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Näytä ilmoitukset luettelon kärjessä ja toista merkkiääni"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Näytä ilmoitus näytöllä ja toista äänimerkki"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Tavalliset värit"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Yövärit"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Muokatut värit"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automaattinen"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Tuntemattomat värit"</string>
- <string name="color_transform" msgid="6985460408079086090">"Muokatut värit"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Näytä pika-asetusruutu"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Ota muokatut värit käyttöön"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Väri ja ulkoasu"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Yötila"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibroi näyttö"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Käytössä"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Pois käytöstä"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Ota käyttöön automaattisesti"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Ota yötila käyttöön sijainnin ja kellonajan perusteella."</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kun yötila on käytössä"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Käytä tummaa teemaa käyttöjärjestelmässä"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Säädä sävytystä"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Säädä kirkkautta"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tumma teema tulee käyttöön Android-käyttöjärjestelmän ydinosissa, kuten Asetuksissa, joissa käytetään tavallisesti vaaleaa teemaa."</string>
<string name="color_apply" msgid="9212602012641034283">"Käytä"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Vahvista asetukset"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Jotkin väriasetukset voivat häiritä laitteen käyttöä. Vahvista uudet väriasetukset valitsemalla OK. Muussa tapauksessa aiemmat asetukset palautetaan 10 sekunnin kuluttua."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Akku (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa."</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Aloitusnäyttö"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Viimeaikaiset"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Takaisin"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Näytä Älä häiritse ‑valinnat äänenvoimakkuudessa"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Näytä kaikki Älä häiritse ‑tilan säädöt äänenvoimakkuusvalinnassa."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Äänenvoimakkuus ja Älä häiritse ‑tila"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Siirry Älä häiritse -tilaan, kun äänenvoimakkuutta lasketaan"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Näytä äänenvoimakkuuden säätimien yhteydessä"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Älä häiritse"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Äänenvoimakkuuspainikkeiden pikanäppäin"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Poistu Älä häiritse -tilasta, kun äänenvoimakkuus nousee"</string>
<string name="battery" msgid="7498329822413202973">"Akku"</string>
<string name="clock" msgid="7416090374234785905">"Kello"</string>
<string name="headset" msgid="4534219457597457353">"Kuulokemikrofoni"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Kuulokkeet liitetty"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Kuulokemikrofoni liitetty"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ota tilapalkin kuvakkeet käyttöön tai poista ne käytöstä."</string>
<string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver on käytössä."</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver on pois käytöstä."</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Valitse näppäimistön näppäin"</string>
<string name="preview" msgid="9077832302472282938">"Esikatselu"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Lisää osioita vetämällä."</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Muokkaa"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Aika"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Näytä tunnit, minuutit ja sekunnit"</item>
+ <item msgid="1427801730816895300">"Näytä tunnit ja minuutit (oletus)"</item>
+ <item msgid="3830170141562534721">"Älä näytä tätä kuvaketta"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Näytä prosenttiluku aina"</item>
+ <item msgid="2139628951880142927">"Näytä prosenttiluku latauksen aikana (oletus)"</item>
+ <item msgid="3327323682209964956">"Älä näytä tätä kuvaketta"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Näytön jakaja"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Siirrä alaspäin"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Siirrä ylöspäin"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Siirrä vasemmalle"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Siirrä oikealle"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 9187aa5b4467..b957dbaa694d 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Imposs. prendre saisie d\'écran : espace stock. limité, ou l\'appli ou votre organisation l\'interdit."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossible d\'enregistrer la saisie d\'écran, car l\'espace de stockage est limité."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Installer comme un lecteur multimédia (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Installer comme un appareil photo (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historique"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Effacer"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Cette application ne prend pas en charge le mode multifenêtre"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'application ne prend pas en charge le mode multifenêtre"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Aucune\ninterruption"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorités\nuniquement"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tous"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tous\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
<string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activer l\'accélérateur d\'écr. partagé en balayant vers le haut"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer le geste d\'écran partagé en balayant vers le haut"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton « Aperçu »"</string>
<string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Appliquer à <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Appliquer à toutes les notifications de cette application"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloquée"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
<string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
<string name="max_importance" msgid="5089005872719563894">"Importance urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Afficher en mode silencieux au bas de la liste de notifications"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatique"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Couleurs inconnues"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modifier la couleur"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afficher la tuile de configuration rapide"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Activer la transformation personnalisée"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Mode Nuit"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrer l\'affichage"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Activé"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Désactivé"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activer automatiquement"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Passer en mode Nuit en fonction de la position et de l\'heure de la journée"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Lorsque le mode Nuit est activé"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Utiliser thème foncé pour Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajuster la coloration"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Régler la luminosité"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Le thème foncé est appliqué à des zones essentielles de la plateforme Android qui sont habituellement affichées dans un thème clair, comme les paramètres."</string>
<string name="color_apply" msgid="9212602012641034283">"Appliquer"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmer les paramètres"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Certains paramètres de couleurs peuvent rendre cet appareil inutilisable. Cliquez sur « OK » pour valider ces paramètres, sinon ils seront réinitialisés après 10 secondes."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Pile (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Réduit les performances et les données en arrière-plan"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Fonctionnalité Ne pas déranger dans boîte de dialogue volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Autoriser le contrôle de la fonctionnalité Ne pas déranger dans la boîte de dialogue de modification du volume"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume et fonctionnalité Ne pas déranger"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Activer fonctionnalité Ne pas déranger avec bouton Volume -"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Désactiver fonctionnalité Ne pas déranger avec bouton Volume +"</string>
<string name="battery" msgid="7498329822413202973">"Pile"</string>
<string name="clock" msgid="7416090374234785905">"Horloge"</string>
<string name="headset" msgid="4534219457597457353">"Écouteurs"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Écouteurs connectés"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Écouteurs connectés"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activer ou désactiver l\'affichage des icônes dans la barre d\'état"</string>
<string name="data_saver" msgid="5037565123367048522">"Économiseur de données"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"La fonction Économiseur de données est activée"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"La fonction Économiseur de données est désactivée"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Sélectionnez la touche du clavier"</string>
<string name="preview" msgid="9077832302472282938">"Aperçu"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Faites glisser des tuiles ici pour les ajouter"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Heure"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Afficher les heures, les minutes et les secondes"</item>
+ <item msgid="1427801730816895300">"Afficher les heures et les minutes (par défaut)"</item>
+ <item msgid="3830170141562534721">"Ne pas afficher cette icône"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Toujours afficher le pourcentage"</item>
+ <item msgid="2139628951880142927">"Montrer le pourcentage durant la charge (par défaut)"</item>
+ <item msgid="3327323682209964956">"Ne pas afficher cette icône"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 767ba86ea09d..a7bf20b79dfb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Capture d\'écran imposs., car espace stockage limité, ou appli ou entreprise ne vous y autorise pas."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Les captures d\'écran ne sont pas autorisées par l\'application ou par votre organisation."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Installer en tant que lecteur multimédia (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Installer en tant qu\'appareil photo (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'application <xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historique"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Effacer"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Application incompatible avec le mode multifenêtre."</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Application incompatible avec le mode multifenêtre"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Aucune\ninterruption"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Toujours"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Toutes\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
<string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activer accélérateur écran partagé en balayant vers le haut"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer l\'écran partagé en balayant vers le haut"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton \"Aperçu\""</string>
<string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Appliquer aux notifications relatives au sujet \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
- <string name="apply_to_app" msgid="363016783939815960">"Appliquer à toutes les notifications de cette application"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloquées"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
<string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgent"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Afficher au bas de la liste des notifications en mode silencieux"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatique"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Couleurs inconnues"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modification des couleurs"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afficher la tuile de configuration rapide"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Activer la transformation personnalisée"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Mode Nuit"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrer l\'affichage"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Activé"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Désactivé"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activer automatiquement"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Passer en mode Nuit en fonction de la position et de l\'heure de la journée"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Lorsque le mode Nuit est activé"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Utiliser thème foncé pour plate-forme Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajuster la coloration"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Régler la luminosité"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Le thème foncé est appliqué à des zones essentielles de la plate-forme Android qui sont habituellement affichées dans un thème clair, telles que les paramètres."</string>
<string name="color_apply" msgid="9212602012641034283">"Appliquer"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Vérifier les paramètres"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Certains paramètres de couleurs peuvent rendre cet appareil inutilisable. Cliquez sur \"OK\" pour valider ces paramètres, sans quoi ils seront réinitialisés après 10 secondes."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batterie (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Limite les performances et les données en arrière-plan."</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Accueil"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Récents"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Précédent"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Fonctionnalité Ne pas déranger dans boîte de dialogue volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Autoriser le contrôle de la fonctionnalité Ne pas déranger dans la boîte de dialogue de modification du volume"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume et fonctionnalité Ne pas déranger"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Activer fonctionnalité Ne pas déranger via le bouton Volume -"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afficher avec les commandes de volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne pas déranger"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Raccourci des boutons de volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Désactiver fonctionnalité Ne pas déranger via bouton Volume +"</string>
<string name="battery" msgid="7498329822413202973">"Batterie"</string>
<string name="clock" msgid="7416090374234785905">"Horloge"</string>
<string name="headset" msgid="4534219457597457353">"Casque"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Casque connecté"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Casque connecté"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activer ou désactiver l\'affichage des icônes dans la barre d\'état"</string>
<string name="data_saver" msgid="5037565123367048522">"Économiseur de données"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"L\'économiseur de données est activé."</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"L\'économiseur de données est désactivé."</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Sélectionner la touche du clavier"</string>
<string name="preview" msgid="9077832302472282938">"Aperçu"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Faites glisser des tuiles ici pour les ajouter"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Heure"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Afficher les heures, les minutes et les secondes"</item>
+ <item msgid="1427801730816895300">"Afficher les heures et les minutes (option par défaut)"</item>
+ <item msgid="3830170141562534721">"Ne plus afficher cette icône"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Toujours afficher le pourcentage"</item>
+ <item msgid="2139628951880142927">"Afficher le pourcentage lorsque l\'appareil est en charge (option par défaut)"</item>
+ <item msgid="3327323682209964956">"Ne plus afficher cette icône"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 24af89b89fb3..d24c424e0383 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de pantalla gardada."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toca para ver a captura de pantalla."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Non se puido facer a captura de pantalla."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Non se pode realizar a captura de pantalla porque o espazo de almacenamento está limitado ou porque non o admite a aplicación ou a túa empresa."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Non se pode gardar a captura de pantalla porque o espazo de almacenamento é limitado."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"A aplicación ou a túa organización non permite realizar capturas de pantalla."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcións de transferencia USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Inserir como reprodutor multimedia (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Inserir como cámara (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Máis tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desactivada."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna activada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Desactivouse a lanterna."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Activouse a lanterna."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixación de pantalla"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"A aplicación <xliff:g id="APP">%s</xliff:g> está desactivada no modo seguro"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historial"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Borrar"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicación non é compatible con varias ventás"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"A aplicación non é compatible con varias ventás"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silencio\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Todas"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápido (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lento (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activar acelerador de pant. div. pasando o dedo cara arriba"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activar pantalla dividida pasando o dedo cara arriba"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa o xesto de pasar o dedo cara arriba desde o botón Visión xeral para acceder ao modo de pantalla dividida"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado co tablet, primeiro tes que activar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar ás notificacións de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificacións procedentes desta aplicación"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importancia baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Importancia urxente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrar nunca estas notificacións"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificacións de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificacións e emitir son"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar na pantalla e emitir son"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
<string name="notification_done" msgid="5279426047273930175">"Feito"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Cores nocturnas"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automático"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores descoñecidas"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificación de cor"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar mosaico de configuración rápida"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Activar transformación personalizada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspecto"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modo nocturno"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrar pantalla"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Activado"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desactivado"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activar automaticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Cambia ao modo nocturno segundo proceda para a localización e a hora do día"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Cando o modo nocturno está activado"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Usar tema escuro para SO Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Axustar ton"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Axustar brillo"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro aplícase ás áreas principais do SO Android que se mostran normalmente nun tema claro, como a configuración."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar configuración"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algunhas opcións de configuración de cor poden facer que este dispositivo sexa inutilizable. Fai clic en Aceptar para confirmar esta configuración de cor; en caso contrario, a configuración restablecerase tras 10 segundos."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batería (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce o rendemento e os datos en segundo plano"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Inicio"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Volver"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar o modo Non molestar no cadro de diálogo de volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permite o control completo do modo Non molestar no cadro de diálogo de volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e modo Non molestar"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Activar o modo Non molestar ao baixar o volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar cos controis de volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non molestar"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Atallo dos botóns de volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Desactivar o modo Non molestar ao subir o volume"</string>
<string name="battery" msgid="7498329822413202973">"Batería"</string>
<string name="clock" msgid="7416090374234785905">"Reloxo"</string>
<string name="headset" msgid="4534219457597457353">"Auriculares"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Conectáronse os auriculares"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Conectáronse os auriculares"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activa ou desactiva a visualización das iconas na barra de estado."</string>
<string name="data_saver" msgid="5037565123367048522">"Economizador de datos"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"O economizador de datos está activado"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"O economizador de datos está desactivado"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Selecciona o botón do teclado"</string>
<string name="preview" msgid="9077832302472282938">"Vista previa"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arrastrar para engadir mosaicos"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+ <item msgid="1427801730816895300">"Mostrar horas e minutos (predeterminado)"</item>
+ <item msgid="3830170141562534721">"Non mostrar esta icona"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Mostrar sempre porcentaxe"</item>
+ <item msgid="2139628951880142927">"Mostrar porcentaxe durante a carga (predeterminado)"</item>
+ <item msgid="3327323682209964956">"Non mostrar esta icona"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Baixar"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover á esquerda"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover á dereita"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index bb7a9d6b187e..075f02399eec 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"સ્ક્રીનશોટ કેપ્ચર કર્યો."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"તમારો સ્ક્રીનશોટ જોવા માટે ટચ કરો."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"સ્ક્રીનશોટ કેપ્ચર કરી શકાયો નથી."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"મર્યાદિત સંગ્રહ સ્થાનને કારણે સ્ક્રીનશોટ લઈ શકાતો નથી અથવા એપ્લિકેશન અથવા તમારા સંગઠન દ્વારા તેની મંજૂરી નથી."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"મર્યાદિત સંગ્રહ સ્થાનને કારણે સ્ક્રીનશોટ સાચવી શકાતો નથી."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ઍપ્લિકેશન કે તમારી સંસ્થા દ્વારા સ્ક્રીનશોટ્સ લેવાની મંજૂરી નથી."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ફાઇલ ટ્રાન્સફર વિકલ્પો"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"મીડિયા પ્લેયર તરીકે માઉન્ટ કરો (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"કૅમેરા તરીકે માઉન્ટ કરો (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"વધુ સમય."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ઓછો સમય."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ફ્લેશલાઇટ બંધ."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ફ્લેશલાઇટ અનુપલબ્ધ."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ફ્લેશલાઇટ ચાલુ."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ફ્લેશલાઇટ બંધ કરી."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ફ્લેશલાઇટ ચાલુ કરી."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"સ્ક્રીન પિનિંગ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"શોધ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી શકાયું નથી."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"સુરક્ષિત મોડમાં <xliff:g id="APP">%s</xliff:g> અક્ષમ કરેલ છે."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ઇતિહાસ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"સાફ કરો"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"આ ઍપ્લિકેશન મલ્ટિ-વિંડોનું સમર્થન કરતી નથી"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ઍપ્લિકેશન મલ્ટિ-વિંડોનું સમર્થન કરતી નથી"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"સાવ\nશાંતિ"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ફક્ત\nપ્રાધાન્યતા"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ફક્ત\nએલાર્મ્સ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"તમામ"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"બધી\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ચાર્જ થઈ રહ્યું છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ઝડપથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ધીમેથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
<string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ ઍક્સલરેટર સક્ષમ કરો"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ હાવભાવ સક્ષમ કરો"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"વિહંગાવલોકન બટનમાંથી સ્વાઇપ કરીને સ્પ્લિટ-સ્ક્રીનમાં દાખલ થવા માટે હાવભાવ સક્ષમ કરો"</string>
<string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ચાલુ કરો"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> સૂચનાઓ પર લાગુ કરો"</string>
- <string name="apply_to_app" msgid="363016783939815960">"આ ઍપ્લિકેશનની તમામ સૂચનાઓ પર લાગુ કરો"</string>
+ <string name="show_silently" msgid="6841966539811264192">"સૂચનાઓ ચુપચાપ બતાવો"</string>
+ <string name="block" msgid="2734508760962682611">"તમામ સૂચનાઓને અવરોધિત કરો"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ચુપ કરશો નહીં"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ચુપ કે અવરોધિત કરશો નહીં"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"પૂર્ણ મહત્વ સેટિંગ્સ બતાવો"</string>
<string name="blocked_importance" msgid="5198578988978234161">"અવરોધિત"</string>
+ <string name="min_importance" msgid="1901894910809414782">"ન્યૂનતમ મહત્વ"</string>
<string name="low_importance" msgid="4109929986107147930">"નિમ્ન મહત્વની"</string>
<string name="default_importance" msgid="8192107689995742653">"સામાન્ય મહત્વની"</string>
<string name="high_importance" msgid="1527066195614050263">"ઉચ્ચ મહત્વની"</string>
<string name="max_importance" msgid="5089005872719563894">"તાત્કાલિક મહત્વની"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"આ સૂચનાઓ ક્યારેય બતાવશો નહીં"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"આ સૂચનાઓ ચુપચાપ બતાવો"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"સૂચનાઓની સૂચિની ટોચ પર બતાવો અને અવાજ કરો"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજ કરો"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"આ સૂચનાઓ ચુપચાપ બતાવો"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"આ સૂચનાને અવાજ કરવાની મંજૂરી આપો"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજને મંજૂરી આપો"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"સૂચનાઓની સૂચિની ટોચ પર બતાવો, સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજને મંજૂરી આપો"</string>
<string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
<string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"સામાન્ય રંગો"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"રાત્રિ રંગો"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"કસ્ટમ રંગો"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"સ્વતઃ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"અજાણ્યા રંગો"</string>
- <string name="color_transform" msgid="6985460408079086090">"રંગ સંશોધન"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"ઝડપી સેટિંગ્સ ટાઇલ બતાવો"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"કસ્ટમ રૂપાંતરણને સક્ષમ કરો"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"રંગ અને દેખાવ"</string>
+ <string name="night_mode" msgid="3540405868248625488">"રાત્રિ મોડ"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"પ્રદર્શન કૅલિબ્રેટ કરો"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ચાલુ"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"બંધ"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"આપમેળે ચાલુ કરો"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"સ્થાન અને દિવસના સમય માટે યોગ્ય હોય તે રાત્રિ મોડ પર સ્વિચ કરો"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"જ્યારે રાત્રિ મોડ ચાલુ હોય"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS માટે ઘાટી થીમનો ઉપયોગ કરો"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ટિંટ સમાયોજિત કરો"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"તેજ સમાયોજિત કરો"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ઘાટી થીમને Android OS ના મુખ્ય ક્ષેત્રો પર લાગુ કરે છે જે સામાન્ય રીતે સેટિંગ્સ જેવી લાઇટ થીમમાં પ્રદર્શિત કરવામાં આવે છે."</string>
<string name="color_apply" msgid="9212602012641034283">"લાગુ કરો"</string>
<string name="color_revert_title" msgid="4746666545480534663">"સેટિંગ્સની પુષ્ટિ કરો"</string>
<string name="color_revert_message" msgid="9116001069397996691">"કેટલીક રંગ સેટિંગ્સ આ ઉપકરણને બિનઉપયોગી બનાવી શકે છે. આ રંગ સેટિંગ્સની પુષ્ટિ કરવા માટે ઑકે ક્લિક કરો, અન્યથા 10 સેકંડ પછી આ સેટિંગ્સ ફરીથી સેટ થશે."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"બૅટરી (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"પ્રદર્શન અને પૃષ્ઠભૂમિ ડેટા ઘટાડે છે"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"હોમ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"તાજેતરના"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"પાછળ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"વૉલ્યૂમમાં ખલેલ પાડશો નહીં બતાવો"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"વૉલ્યૂમ સંવાદમાં ખલેલ પાડશો નહીંના સંપૂર્ણ નિયંત્રણની મંજૂરી આપો."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"વૉલ્યૂમ અને ખલેલ પાડશો નહીં"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"વૉલ્યૂમ ઘટાડવા પર ખલેલ પાડશો નહીંમાં દાખલ થાઓ"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"વૉલ્યૂમ નિયંત્રણ સાથે બતાવો"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ખલેલ પાડશો નહીં"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"વૉલ્યૂમ બટન્સ શૉર્ટકટ"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"વૉલ્યૂમ વધારવા પર ખલેલ પાડશો નહીંમાંથી બહાર નિકળો"</string>
<string name="battery" msgid="7498329822413202973">"બૅટરી"</string>
<string name="clock" msgid="7416090374234785905">"ઘડિયાળ"</string>
<string name="headset" msgid="4534219457597457353">"હેડસેટ"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"હેડફોન કનેક્ટ કર્યાં"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"હેડસેટ કનેક્ટ કર્યો"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"સ્થિતિ બારમાં બતાવવામાં આવતા આઇકન્સને સક્ષમ અથવા અક્ષમ કરો."</string>
<string name="data_saver" msgid="5037565123367048522">"ડેટા સેવર"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ડેટા સેવર ચાલુ છે"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ડેટા સેવર બંધ છે"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"કીબોર્ડ બટન પસંદ કરો"</string>
<string name="preview" msgid="9077832302472282938">"પૂર્વાવલોકન કરો"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ટાઇલ્સ ઉમેરવા માટે ખેંચો"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"સંપાદિત કરો"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"સમય"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"કલાક, મિનિટ અને સેકંડ બતાવો"</item>
+ <item msgid="1427801730816895300">"કલાક અને મિનિટ બતાવો (ડિફોલ્ટ)"</item>
+ <item msgid="3830170141562534721">"આ આઇકન બતાવશો નહીં"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"હંમેશાં ટકાવારી બતાવો"</item>
+ <item msgid="2139628951880142927">"ચાર્જ થાય ત્યારે ટકાવારી બતાવો (ડિફોલ્ટ)"</item>
+ <item msgid="3327323682209964956">"આ આઇકન બતાવશો નહીં"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"અન્ય"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"સ્પ્લિટ-સ્ક્રીન વિભાજક"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"નીચે ખસેડો"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ઉપર ખસેડો"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ડાબે ખસેડો"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"જમણે ખસેડો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index d6a277d55549..91a5d69931d7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"स्‍क्रीनशॉट कैप्‍चर किया गया."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"अपना स्‍क्रीनशॉट देखने के लिए स्‍पर्श करें."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रीनशॉट को कैप्चर नहीं किया जा सका."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"सीमित मेमोरी स्थान के कारण स्क्रीनशॉट नहीं ले सकते, या ऐप्स या आपके संगठन द्वारा ऐसा अनुमत नहीं है."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"सीमित मेमोरी स्थान के कारण स्क्रीनशॉट सहेजा नहीं जा सकता."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"आपके ऐप्लिकेशन या आपके संगठन द्वारा स्क्रीनशॉट लेने की अनुमति नहीं है."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB फ़ाइल स्थानांतरण विकल्प"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेयर के रूप में माउंट करें (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"कैमरे के रूप में माउंट करें (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"अधिक समय."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कम समय."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"फ़्लैशलाइट बंद है."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ़्लैशलाइट उपलब्ध नहीं है."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"फ़्लैशलाइट चालू है."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"फ़्लैशलाइट को बंद किया गया."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"फ़्लैशलाइट को चालू किया गया."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रीन पिन करना"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> को सुरक्षित-मोड में अक्षम किया गया."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"साफ़ करें"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यह ऐप्लिकेशन एकाधिक विंडो का समर्थन नहीं करता है"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ऐप्लिकेशन एकाधिक विंडो का समर्थन नहीं करता है"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"पूरी तरह\nशांत"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवल\nप्राथमिकता"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवल\nअलार्म"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"सभी"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"सभी\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूरा होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> बाकी)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"तेज़ी से चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में हो जाएगा)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"धीरे चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में पूरा हो जाएगा)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
<string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ऊपर स्वाइप करके स्क्रीन विभाजन की त्वरित सुविधा सक्षम करें"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ऊपर स्वाइप करके विभाजित स्क्रीन में जाने का जेस्चर सक्षम करें"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"अवलोकन बटन से ऊपर स्वाइप करके स्क्रीन विभाजन में आने का हावभाव सक्षम करें"</string>
<string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करें"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> नोटिफिकेशन पर लागू करें"</string>
- <string name="apply_to_app" msgid="363016783939815960">"इस ऐप के सभी नोटिफिकेशन पर लागू करें"</string>
+ <string name="show_silently" msgid="6841966539811264192">"नोटिफिकेशन मौन रूप से दिखाएं"</string>
+ <string name="block" msgid="2734508760962682611">"सभी नोटिफिकेशन अवरुद्ध करें"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"मौन ना करें"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"मौन या अवरुद्ध ना करें"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्व वाली सेटिंग दिखाएं"</string>
<string name="blocked_importance" msgid="5198578988978234161">"अवरोधित"</string>
+ <string name="min_importance" msgid="1901894910809414782">"न्यूनतम महत्व"</string>
<string name="low_importance" msgid="4109929986107147930">"निम्न महत्व"</string>
<string name="default_importance" msgid="8192107689995742653">"सामान्य महत्व"</string>
<string name="high_importance" msgid="1527066195614050263">"उच्च महत्व"</string>
<string name="max_importance" msgid="5089005872719563894">"तत्काल महत्व"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ये नोटिफिकेशन कभी ना दिखाएं"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"नोटिफिकेशन सूची में सबसे नीचे मौन रूप से दिखाएं"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"नोटिफिकेशन सूची में सबसे ऊपर दिखाएं और ध्वनि चलाएं"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"स्‍क्रीन पर एक झलक दिखाएं और ध्‍वनि चलाएं"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"नोटिफिकेशन सूची में सबसे नीचे मौन रूप से दिखाएं"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"इन नोटिफिकेशन को ध्वनि करने दें"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रीन पर झलक दिखाएं और ध्वनि करें"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"नोटिफिकेशन सूची के शीर्ष पर दिखाएं, स्क्रीन पर झलक दिखाएं और ध्वनि करें"</string>
<string name="notification_more_settings" msgid="816306283396553571">"और सेटिंग"</string>
<string name="notification_done" msgid="5279426047273930175">"हो गया"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"रात्रि के रंग"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"कस्टम रंग"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"स्वतः"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रंग"</string>
- <string name="color_transform" msgid="6985460408079086090">"रंग परिवर्तन"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"त्‍वरित-सेटिंग टाइल दिखाएं"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"कस्टम रूपांतरण सक्षम करें"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"रंग और दिखावट"</string>
+ <string name="night_mode" msgid="3540405868248625488">"रात्रि मोड"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"स्क्रीन को कैलिब्रेट करें"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"चालू"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"बंद"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"अपने आप चालू करें"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"स्थान और दिन के समय के लिए उपयुक्त रात्रि मोड में बदलें"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"रात्रि मोड के चालू होने पर"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS के लिए गहरी थीम का उपयोग करें"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"टिंट समायोजित करें"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"स्क्रीन की रोशनी समायोजित करें"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"गहरी थीम को Android OS के मुख्य क्षेत्रों पर लागू किया जाता है जिन्हें सामान्यतः सेटिंग जैसी हल्की थीम में प्रदर्शित किया जाता है."</string>
<string name="color_apply" msgid="9212602012641034283">"लागू करें"</string>
<string name="color_revert_title" msgid="4746666545480534663">"से‍ेटिंग की पुष्टि करें"</string>
<string name="color_revert_message" msgid="9116001069397996691">"कुछ रंग सेटिंग इस डिवाइस को अनुपयोगी बना सकती हैं. इन रंग सेटिंग की पुष्टि करने के लिए ठीक क्लिक करें, अन्यथा 10 सेकंड के बाद ये सेटिंग रीसेट हो जाएंगी."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"बैटरी (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"निष्‍पादन और पृष्ठभूमि डेटा को कम करता है"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"होम"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हाल ही के"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"वापस जाएं"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"वॉल्यूम में परेशान न करें दिखाएं"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"वॉल्यूम संवाद में परेशान न करें के पूर्ण नियंत्रण की अनुमति दें."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"वॉल्यूम और परेशान न करें"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"वॉल्यूम कम करें पर परेशान न करें डालें"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"वॉल्यूम नियंत्रणों के साथ दिखाएं"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"परेशान न करें"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"वॉल्यूम बटन का शॉर्टकट"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"वॉल्यूम बढ़ाएं पर परेशान न करें से बाहर निकलें"</string>
<string name="battery" msgid="7498329822413202973">"बैटरी"</string>
<string name="clock" msgid="7416090374234785905">"घड़ी"</string>
<string name="headset" msgid="4534219457597457353">"हैडसेट"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"हेडफ़ोन कनेक्‍ट किए गए"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"हैडसेट कनेक्‍ट किया गया"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"आइकन को स्‍थिति बार में दिखाए जाने से सक्षम या अक्षम करें."</string>
<string name="data_saver" msgid="5037565123367048522">"डेटा बचतकर्ता"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा बचतकर्ता चालू है"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा बचतकर्ता बंद है"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटन चुनें"</string>
<string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलों को जोड़ने के लिए खींचें"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"संपादित करें"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"समय"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"घंटे, मिनट और सेकंड दिखाएं"</item>
+ <item msgid="1427801730816895300">"घंटे और मिनट दिखाएं (डिफ़ॉल्ट)"</item>
+ <item msgid="3830170141562534721">"यह आइकन ना दिखाएं"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"हमेशा प्रतिशत दिखाएं"</item>
+ <item msgid="2139628951880142927">"चार्ज होते समय प्रतिशत दिखाएं (डिफ़ॉल्ट)"</item>
+ <item msgid="3327323682209964956">"यह आइकन ना दिखाएं"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"अन्य"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित स्क्रीन विभाजक"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"नीचे ले जाएं"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ऊपर ले जाएं"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाएं ले जाएं"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दाएं ले जाएं"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index c9cdd50a91c1..eaa777ba5894 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -74,7 +74,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Zaslon je snimljen."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimke zaslona."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nije bilo moguće snimiti zaslon."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Zaslon nije snimljen zbog ograničene pohrane ili zato što to ne dopušta aplikacija ili vaša organizacija."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Zaslon nije snimljen zbog ograničenog prostora za pohranu."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Snimanje zaslona ne dopušta aplikacija ili vaša organizacija."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa datoteka"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Učitaj kao media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Učitaj kao fotoaparat (PTP)"</string>
@@ -207,6 +208,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svjetiljka isključena."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svjetiljka nije dostupna."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svjetiljka uključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svjetiljka isključena."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svjetiljka uključena."</string>
@@ -302,8 +304,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"prikvačivanje zaslona"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"Povijest"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podržava više prozora"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podržava više prozora"</string>
<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>
@@ -333,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetno"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Sve"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Svi\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
@@ -447,38 +451,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
<string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogući ubrzanje za podijeljen zaslon povlačenjem prema gore"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret povlačenja prema gore za podijeljen zaslon"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućivanje pokreta za otvaranje podijeljenog zaslona tako da se od gumba Pregled prstom prijeđe prema gore"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Primijeni na obavijesti za temu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Primijeni na sve obavijesti ove aplikacije"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Prikaži obavijesti tiho"</string>
+ <string name="block" msgid="2734508760962682611">"Blokiraj sve obavijesti"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ne utišavaj"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ne utišavaj i ne blokiraj"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži potpune postavke važnosti"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Najmanja važnost"</string>
<string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
<string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
<string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
<string name="max_importance" msgid="5089005872719563894">"Hitno"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nikad ne prikazuj te obavijesti"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Prikaži tiho pri dnu popisa obavijesti"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži te obavijesti tiho"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu popisa obavijesti i emitiraj zvučni signal"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Prikaži na zaslonu i emitiraj zvučni signal"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Prikaži tiho pri dnu popisa obavijesti"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Prikaži te obavijesti tiho"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Dopusti obavijestima da emitiraju zvučne signale"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Prikaži na zaslonu i dopusti zvuk"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži pri vrhu popisa obavijesti, prikaži na zaslonu i dopusti zvuk"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Uobičajene boje"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatski"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
- <string name="color_transform" msgid="6985460408079086090">"Izmjena boja"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži pločicu s brzim postavkama"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Omogući prilagođenu preobrazbu"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Noćni način rada"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibriranje zaslona"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Uključeno"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Isključeno"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Uključi automatski"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Prebacivanje na noćni način rada prema lokaciji i dobu dana"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kada je noćni način rada uključen"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Koristi tamnu temu za OS Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Prilagodi nijansu"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Prilagodi svjetlinu"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tamna se tema primjenjuje na glavna područja OS-a Android, kao što su, primjerice, postavke, koja se inače prikazuju u svijetloj temi."</string>
<string name="color_apply" msgid="9212602012641034283">"Primijeni"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Potvrdite postavke"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Neke postavke boja mogu učiniti uređaj neupotrebljivim. Kliknite U redu da biste potvrdili postavke boja jer će se u suprotnom poništiti za 10 sekundi."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Baterija (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Smanjuje količinu rada i pozadinske podatke"</string>
@@ -486,21 +499,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Početni zaslon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Najnovije"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Natrag"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Prikaži \"Ne uznemiravaj\" u glasnoći"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Dopušta potpunu kontrolu nad načinom \"Ne uznemiravaj\" u dijaloškom okviru glasnoće."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Glasnoća i Ne uznemiravaj"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Pokreni \"Ne uznemiravaj\" kada je zvuk stišan"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolama glasnoće"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne uznemiravaj"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečac tipki za glasnoću"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Zaustavi \"Ne uznemiravaj\" kada je zvuk pojačan"</string>
<string name="battery" msgid="7498329822413202973">"Baterija"</string>
<string name="clock" msgid="7416090374234785905">"Sat"</string>
<string name="headset" msgid="4534219457597457353">"Slušalice"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalice su povezane"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Slušalice su povezane"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Omogućuje ili onemogućuje prikazivanje ikona na traci statusa."</string>
<string name="data_saver" msgid="5037565123367048522">"Ušteda podataka"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ušteda podataka je uključena"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ušteda podataka je isključena"</string>
<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>
@@ -522,4 +534,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Odaberite gumb tipkovnice"</string>
<string name="preview" msgid="9077832302472282938">"Pregled"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali pločice"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Prikaži sate, minute i sekunde"</item>
+ <item msgid="1427801730816895300">"Prikaži sate i minute (zadano)"</item>
+ <item msgid="3830170141562534721">"Ne prikazuj tu ikonu"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Uvijek prikazuj postotak"</item>
+ <item msgid="2139628951880142927">"Prikazuj postotak tijekom punjenja (zadano)"</item>
+ <item msgid="3327323682209964956">"Ne prikazuj tu ikonu"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Ostalo"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik podijeljenog zaslona"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomakni prema dolje"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomakni prema gore"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomakni ulijevo"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomakni udesno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8ff4ec9862af..8e55c78fcb6b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Képernyőkép rögzítve."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Megérintésével megtekintheti a képernyőképet."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nem sikerült rögzíteni a képernyőképet."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Nem készíthet képernyőképet, mert kevés a tárhely, vagy az alkalmazás/szervezet nem engedélyezi azt."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nem menthet képernyőképet, mert kevés a tárhely."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Az alkalmazás vagy szervezete nem engedélyezi képernyőképek készítését."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-fájlátvitel beállításai"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Csatlakoztatás médialejátszóként (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Csatlakoztatás kameraként (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Több idő."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kevesebb idő."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Vaku kikapcsolva."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"A zseblámpa nem áll rendelkezésre"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Vaku bekapcsolva."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Vaku kikapcsolva."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Vaku bekapcsolva."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"képernyő rögzítése"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"A(z) <xliff:g id="APP">%s</xliff:g> csökkentett módban ki van kapcsolva."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Előzmények"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Törlés"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ez az alkalmazás nem támogatja a többablakos nézetet"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Az alkalmazás nem támogatja a többablakos nézetet"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Teljes\nnémítás"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Csak\nprioritás"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Csak\nriasztások"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Összes"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Összes\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Gyors töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lassú töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
<string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Osztott képernyő engedélyezése felfelé söpréssel"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Képernyőfelosztó gyors felfelé csúsztatás engedélyezése"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Kézmozdulat engedélyezése osztott képernyős nézet aktiválásához, ha az Áttekintés gombról felfelé húzza az ujját"</string>
<string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bekapcsolás"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"A következő értesítések esetén: <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Az alkalmazás minden értesítése esetén"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Értesítések megjelenítése hangjelzés nélkül"</string>
+ <string name="block" msgid="2734508760962682611">"Minden értesítés letiltása"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Nincs némítás"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Nincs némítás vagy letiltás"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"A teljes fontossági beállítások megjelenítése"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Letiltva"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Minimális fontosságú"</string>
<string name="low_importance" msgid="4109929986107147930">"Kevésbé fontos"</string>
<string name="default_importance" msgid="8192107689995742653">"Normál"</string>
<string name="high_importance" msgid="1527066195614050263">"Fontos"</string>
<string name="max_importance" msgid="5089005872719563894">"Sürgős"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Soha nem jelennek meg ezek az értesítések"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Hangjelzés nélkül jelennek meg az értesítési lista alján"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Hang nélkül jelennek meg ezek az értesítések"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Az értesítési lista tetején jelennek meg hangjelzéssel"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Az értesítések felugranak a képernyőn hangjelzéssel"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Hangjelzés nélkül jelennek meg az értesítési lista alján"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Ezek az értesítések hangjelzés nélkül jelennek meg"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Hangjelzés engedélyezése ezeknél az értesítéseknél"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Az értesítések felugranak a képernyőn hangjelzéssel"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Az értesítési lista tetején jelennek meg, illetve felugranak a képernyőn hangjelzéssel"</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="color_matrix_none" msgid="2121957926040543148">"Hagyományos színek"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Esti színek"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Egyéni színek"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatikus"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Ismeretlen színek"</string>
- <string name="color_transform" msgid="6985460408079086090">"Színmódosítás"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Gyorsbeállítások mozaikjának megjelenítése"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Egyéni átalakítás engedélyezése"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Szín és megjelenés"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Éjszakai mód"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kijelző kalibrálása"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Bekapcsolva"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Kikapcsolva"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Automatikus bekapcsolás"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Váltás az Éjszakai módra a helynek és napszaknak megfelelően"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Amikor be van kapcsolva az Éjszakai mód"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Sötét téma használata az Android operációs rendszernél"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Színárnyalat módosítása"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Fényerő módosítása"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Sötét téma látható az Android operációs rendszer olyan alapterületeinél, amelyek normál állapotban világosan jelennek meg (például a Beállítások)."</string>
<string name="color_apply" msgid="9212602012641034283">"Alkalmaz"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Beállítások megerősítése"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Bizonyos színbeállítások használhatatlanná tehetik ezt az eszközt. A színbeállítás megerősítéséhez kattintson az OK lehetőségre, máskülönben a rendszer 10 másodpercen belül visszaáll a korábbira."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Akkumulátor (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Otthon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Legutóbbiak"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Vissza"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"A „Ne zavarjanak” funkció megjelenítése a hangvezérlőben"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"A „Ne zavarjanak” funkció teljes körű vezérlésének engedélyezése a hangerővezérlési párbeszédpanelon."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hangvezérlő és „Ne zavarjanak” funkció"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"„Ne zavarjanak” aktiválása hangerőcsökkentéskor"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Megjelenítés hangerőszabályzóval"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne zavarjanak"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"A hangerőgombok gyorsbillentyűk"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"„Ne zavarjanak” deaktiválása hangerőnöveléskor"</string>
<string name="battery" msgid="7498329822413202973">"Akkumulátor"</string>
<string name="clock" msgid="7416090374234785905">"Óra"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fejhallgató csatlakoztatva"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset csatlakoztatva"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ikonok megjelenítése és elrejtése az állapotsoron."</string>
<string name="data_saver" msgid="5037565123367048522">"Adatforgalom-csökkentő"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Az adatforgalom-csökkentő be van kapcsolva"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Az Adatforgalom-csökkentő ki van kapcsolva"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Billentyűgomb kiválasztása"</string>
<string name="preview" msgid="9077832302472282938">"Előnézet"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Húzza csempe hozzáadásához"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Szerkesztés"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Idő"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Óra, perc és másodperc megjelenítése"</item>
+ <item msgid="1427801730816895300">"Óra és perc megjelenítése (alapértelmezett)"</item>
+ <item msgid="3830170141562534721">"Ne jelenjen meg ez az ikon"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Százalékos érték mindig látható"</item>
+ <item msgid="2139628951880142927">"Százalékos érték töltés közben látható (alapértelmezett)"</item>
+ <item msgid="3327323682209964956">"Ne jelenjen meg ez az ikon"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Egyéb"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Elválasztó az osztott nézetben"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mozgatás lefelé"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mozgatás felfelé"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mozgatás balra"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mozgatás jobbra"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 35f2fb68b08b..08dfb23cc08d 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Էկրանի հանույթը լուսանկարվել է:"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Հպեք ձեր էկրանի հանույթը տեսնելու համար:"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Չհաջողվեց լուսանկարել էկրանի հանույթը:"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Չենք կարող պատճենել էկրանը՝ տարածքի սահմանափակման կամ ձեր կազմակերպության կողմից արգելքի պատճառով:"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Չհաջողվեց պահել էկրանի պատկերը սահմանափակ հիշողության պատճառով:"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Այս հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում Էկրանի պատկերի ստացումը:"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Միացնել որպես ֆոտոխցիկ (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ավելացնել ժամանակը:"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Պակասեցնել ժամանակը:"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Լապտերն անջատված է:"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Լապտերը միացված է:"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Լապտերն անջատվեց:"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Լապտերը միացավ:"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"էկրանի ամրակցում"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> հավելվածը անվտանգ ռեժիմում անջատված է:"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Պատմություն"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Մաքրել"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Այս հավելվածը չի աջակցում բազմապատուհան ռեժիմը"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Հավելվածը չի աջակցում բազմապատուհան ռեժիմը"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Ընդհանուր\nլուռ վիճակը"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Բոլորը"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Բոլորը\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Միացնել մատը վերև սահեցնելով էկրանը տրոհելու արագացուցիչը"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ակտիվացնել մատը վերև սահեցնելով էկրանը տրոհելու ժեստը"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Միացնել Համատեսք կոճակից մատը դեպի վերև սահեցնելու միջոցով տրոհված էկրանի ռեժիմ անցնելու ժեստը"</string>
<string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Միացնել"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Կիրառել <xliff:g id="TOPIC_NAME">%1$s</xliff:g>-ի ծանուցումների նկատմամբ"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Կիրառել այս հավելվածի բոլոր ծանուցումների նկատմամբ"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Արգելափակված"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Ցածր կարևորություն"</string>
<string name="default_importance" msgid="8192107689995742653">"Սովորական կարևորություն"</string>
<string name="high_importance" msgid="1527066195614050263">"Բարձր կարևորություն"</string>
<string name="max_importance" msgid="5089005872719563894">"Հրատապ կարևորություն"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Երբեք չցուցադրել այս ծանուցումները"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Ցուցադրել ծանուցումների ցանկի վերևում և հնչեցնել ձայնային ազդանշան"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Ցուցադրել էկրանին և հնչեցնել ձայնային ազդանշան"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
<string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Սովորական գույներ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Գիշերային գույներ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Հատուկ գույներ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Ավտոմատ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Անհայտ գույներ"</string>
- <string name="color_transform" msgid="6985460408079086090">"Գույնի փոփոխում"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ցույց տալ Արագ կարգավորումների սալիկը"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Միացնել հատուկ գունային անցումը"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Գույնը և արտաքին տեսքը"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Գիշերային ռեժիմ"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Չափաբերել էկրանը"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Միացված է"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Անջատված է"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Միացնել ավտոմատ կերպով"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Անցեք Գիշերային ռեժիմի, եթե դա պահանջում է տեղը և օրվա ժամանակը"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Երբ Գիշերային ռեժիմը միացված է"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Օգտագործել մուգ թեման Android OS-ի համար"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Կարգավորել երանգը"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Կարգավորել պայծառությունը"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Մուգ թեման կիրառվում է Android OS-ի հիմնական հատվածների նկատմամբ, որոնք սովորաբար ցուցադրվում են բաց թեմայում (օրինակ՝ Կարգավորումներ):"</string>
<string name="color_apply" msgid="9212602012641034283">"Կիրառել"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Հաստատել կարգավորումները"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Գունային որոշ կարգավորումները կարող են այս սարքը օգտագործման համար ոչ պիտանի դարձնել: Սեղմեք Լավ կոճակը՝ գունային այս կարգավորումները հաստատելու համար: Հակառակ դեպքում այս կարգավորումները կվերակայվեն 10 վայրկյան հետո:"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Մարտկոց (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Գլխավոր էջ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Վերջինները"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Հետ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ցույց տալ Չխանգարել գործառույթը ձայնի կառավարման պատուհանում"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Թույլատրել Չխանգարել գործառույթի ամբողջական վերահսկումը ձայնի կառավարման պատուհանում:"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ձայնի ուժգնություն և Չխանգարել գործառույթ"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Մտնել Չխանգարել գործառույթ ձայնի նվազեցման կոճակը սեղմելիս"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ցույց տալ ձայնի ուժգնության կառավարման տարրերի հետ"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Չընդհատել"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Ձայնի կոճակների դյուրանցում"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Ելնել Չխանգարել գործառույթից ձայնի ավելացման կոճակը սեղմելիս"</string>
<string name="battery" msgid="7498329822413202973">"Մարտկոց"</string>
<string name="clock" msgid="7416090374234785905">"Ժամացույց"</string>
<string name="headset" msgid="4534219457597457353">"Ականջակալ"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Ականջակալը կապակցված է"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Ականջակալը կապակցված է"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Միացնել կամ անջատել պատկերակների ցուցադրումը կարգավիճակի գոտում:"</string>
<string name="data_saver" msgid="5037565123367048522">"Տվյալների խնայում"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Տվյալների խնայումը միացված է"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Տվյալների խնայումն անջատված է"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Ընտրեք ստեղնաշարի կոճակը"</string>
<string name="preview" msgid="9077832302472282938">"Նախադիտում"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Քաշեք՝ սալիկներ ավելացնելու համար"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Փոփոխել"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Ժամ"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Ցույց տալ ժամերը, րոպեները և վայրկյանները"</item>
+ <item msgid="1427801730816895300">"Ցույց տալ ժամերը և րոպեները (կանխադրված է)"</item>
+ <item msgid="3830170141562534721">"Ցույց չտալ այս պատկերակը"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Միշտ ցույց տալ տոկոսը"</item>
+ <item msgid="2139628951880142927">"Ցույց տալ տոկոսը լիցքավորելու ժամանակ (կանխադրված է)"</item>
+ <item msgid="3327323682209964956">"Ցույց չտալ այս պատկերակը"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Տրոհված էկրանի բաժանիչ"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Տեղափոխել ներքև"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Տեղափոխել վերև"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Տեղափոխել ձախ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Տեղափոխել աջ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ad28e80f1c89..3fa41be87cb2 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan layar diambil."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan layar Anda."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat mengambil tangkapan layar."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Tak bisa mengambil tangkapan layar karena ruang penyimpanan terbatas/tak diizinkan aplikasi/organisasi Anda."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan tangkapan layar karena ruang penyimpanan terbatas."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Mengambil tangkapan layar tidak diizinkan oleh aplikasi atau organisasi."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opsi transfer file USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Pasang sebagai pemutar media (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Pasang sebagai kamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lebih lama."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Lebih cepat."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Senter nonaktif."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Senter aktif."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Senter dinonaktifkan."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Senter diaktifkan."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pin ke layar"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulai <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> dinonaktifkan dalam mode aman."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Riwayat"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Hapus"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikasi ini tidak mendukung multijendela"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikasi tidak mendukung multijendela"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Senyap\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Hanya\nprioritas"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Hanya\nalarm"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Semua"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Semua\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengisi daya dengan cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengisi daya dengan lambat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
<string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktifkan akselerator gesek atas untuk layar terpisah"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktifkan isyarat gesek atas untuk layar terpisah"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktifkan isyarat untuk masuk layar terpisah dengan menggesek tombol Ringkasan ke atas"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktifkan"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Terapkan ke notifikasi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Terapkan untuk semua notifikasi dari aplikasi ini"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Diblokir"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Tingkat kepentingan: rendah"</string>
<string name="default_importance" msgid="8192107689995742653">"Tingkat kepentingan: normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Tingkat kepentingan: tinggi"</string>
<string name="max_importance" msgid="5089005872719563894">"Tingkat kepentingan: darurat"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan pernah tunjukkan notifikasi ini"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Tunjukkan di bawah daftar notifikasi tanpa suara"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan notifikasi ini tanpa suara"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan di bagian atas daftar notifikasi dan bunyikan suara"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Muncul di layar dan bunyikan suara"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Warna normal"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Warna khusus"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Otomatis"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Warna tidak diketahui"</string>
- <string name="color_transform" msgid="6985460408079086090">"Perubahan warna"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tampilkan ubin Setelan Cepat"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Aktifkan transformasi khusus"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Warna dan tampilan"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Mode malam"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrasi layar"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aktif"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Nonaktif"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Aktifkan secara otomatis"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Beralih ke Mode Malam yang sesuai untuk lokasi dan waktu"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Saat Mode Malam aktif"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Gunakan tema gelap untuk OS Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Sesuaikan rona"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Sesuaikan kecerahan"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema gelap diterapkan ke area inti OS Android yang biasanya ditampilkan di tema terang, seperti Setelan."</string>
<string name="color_apply" msgid="9212602012641034283">"Terapkan"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Konfirmasi setelan"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Beberapa setelan warna dapat membuat perangkat ini tidak dapat digunakan. Klik OKE untuk mengonfirmasi setelan warna ini. Jika tidak, setelan ini akan disetel ulang setelah 10 detik."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Baterai (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangi performa dan data latar belakang"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Layar Utama"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaru"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Tampilkan mode jangan ganggu di volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Izinkan kontrol penuh dari mode jangan mengganggu di dialog volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume dan mode Jangan ganggu"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Masukkan mode jangan ganggu di tombol kecilkan volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Tampilkan dengan kontrol volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan tombol volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Keluar dari mode jangan ganggu di tombol keraskan volume"</string>
<string name="battery" msgid="7498329822413202973">"Baterai"</string>
<string name="clock" msgid="7416090374234785905">"Jam"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Headphone terhubung"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset terhubung"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Aktifkan atau nonaktifkan ikon yang ditampilkan di bilah status."</string>
<string name="data_saver" msgid="5037565123367048522">"Penghemat Data"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Penghemat Data aktif"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Penghemat Data nonaktif"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Pilih Tombol Keyboard"</string>
<string name="preview" msgid="9077832302472282938">"Pratinjau"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Seret untuk menambahkan ubin"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Waktu"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Tampilkan jam, menit, dan detik"</item>
+ <item msgid="1427801730816895300">"Tampilkan jam dan menit (default)"</item>
+ <item msgid="3830170141562534721">"Jangan tampilkan ikon ini"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Selalu tampilkan persentase"</item>
+ <item msgid="2139628951880142927">"Tampilkan persentase saat mengisi daya (default)"</item>
+ <item msgid="3327323682209964956">"Jangan tampilkan ikon ini"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Pembagi layar terpisah"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Turunkan"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Naikkan"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pindahkan ke kiri"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pindahkan ke kanan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 522a60419758..e3c3aa85fa01 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Skjámynd var tekin."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Snertu til að skoða skjámyndina."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Ekki tókst að taka skjámynd."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekki hægt að taka skjámynd vegna takmarkaðs pláss eða forritið eða notendaskipanin leyfir það ekki."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ekki tókst að vista skjámynd vegna takmarkaðs geymslupláss."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Forritið eða fyrirtækið þitt leyfir ekki að teknar séu skjámyndir."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Valkostir USB-skráaflutnings"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Tengja sem efnisspilara (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Tengja sem myndavél (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meiri tími."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minni tími."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Slökkt á vasaljósi."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Kveikt á vasaljósi."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Slökkt á vasaljósi."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Kveikt á vasaljósi."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skjáfesting"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Slökkt er á <xliff:g id="APP">%s</xliff:g> í öruggri stillingu."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Ferill"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Hreinsa"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Þetta forrit styður ekki marga glugga"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Forritið styður ekki marga glugga"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Algjör\nþögn"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Aðeins\nforgangur"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Aðeins\nvekjarar"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Allar"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Allar\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Í hraðri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Í hægri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
<string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Virkja skjáskiptingu með því að strjúka upp"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Virkja skjáskiptingu með því að strjúka upp"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Virkja skjáskiptingarbendingu með því að strjúka upp frá yfirlitshnappi"</string>
<string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Kveikja"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Láta gilda um tilkynningar varðandi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Láta gilda um allar tilkynningar frá þessu forriti"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Útilokuð"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Ekki svo mikilvægt"</string>
<string name="default_importance" msgid="8192107689995742653">"Venjulegt mikilvægi"</string>
<string name="high_importance" msgid="1527066195614050263">"Mjög mikilvægt"</string>
<string name="max_importance" msgid="5089005872719563894">"Afar áríðandi"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Aldrei sýna þessar tilkynningar"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Sýna neðst á tilkynningalistanum án hljóðs"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Sýna þessar tilkynningar án hljóðs"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Sýna efst á tilkynningalistanum og spila hljóð"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Birta á skjánum og spila hljóð"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
<string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Venjulegir litir"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Næturlitir"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Sérsniðnir litir"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Sjálfvirkt"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Óþekktir litir"</string>
- <string name="color_transform" msgid="6985460408079086090">"Litabreytingar"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Sýna flísar í flýtistillingum"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Kveikja á sérsniðinni umbreytingu"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Litur og útlit"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Næturstilling"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kvarða skjáinn"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Kveikt"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Slökkt"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Kveikja sjálfkrafa"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Skipta í næturstillingu í samræmi við staðsetningu og tíma dags"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Þegar kveikt er á næturstillingu"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Nota dökkt þema fyrir Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Stilla litblæ"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Stilla birtustig"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Dökka þemað er notað á þeim aðalsvæðum Android OS sem venjulega eru ljós, s.s. í stillingum."</string>
<string name="color_apply" msgid="9212602012641034283">"Nota"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Staðfesta stillingar"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Sumar litastillingar kunna að bitna á notagildi tækisins. Veldu „Í lagi“ til að staðfesta þessar litastillingar, að öðrum kosti verða litirnir endurstilltir eftir tíu sekúndur."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Rafhlaða (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Dregur úr afköstum og bakgrunnsgögnum"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Heim"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nýlegt"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Til baka"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Sýna „Ónáðið ekki“ í hljóðstyrksvali"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Leyfa fulla stjórn á stillingunni „Ónáðið ekki“ í hljóðstyrksglugganum."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hljóðstyrkur og „Ónáðið ekki“"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Kveikja á „Ónáðið ekki“ með því að lækka"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Sýna með hljóðstyrksstillingum"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ónáðið ekki"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Flýtihnappar fyrir hljóðstyrk"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Slökkva á „Ónáðið ekki“ með því að hækka"</string>
<string name="battery" msgid="7498329822413202973">"Rafhlaða"</string>
<string name="clock" msgid="7416090374234785905">"Klukka"</string>
<string name="headset" msgid="4534219457597457353">"Höfuðtól"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Heyrnartól tengd"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Höfuðtól tengt"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Birtu eða feldu myndtákn í stöðustikunni."</string>
<string name="data_saver" msgid="5037565123367048522">"Gagnasparnaður"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Kveikt er á gagnasparnaði"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Slökkt er á gagnasparnaði"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Veldu lyklaborðshnapp"</string>
<string name="preview" msgid="9077832302472282938">"Forskoðun"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dragðu til að bæta við reitum"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Breyta"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Tími"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Sýna klukkustundir, mínútur og sekúndur"</item>
+ <item msgid="1427801730816895300">"Sýna klukkustundir og mínútur (sjálfgefið)"</item>
+ <item msgid="3830170141562534721">"Ekki sýna þetta tákn"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Sýna alltaf hlutfall"</item>
+ <item msgid="2139628951880142927">"Sýna hlutfall meðan á hleðslu stendur (sjálfgefið)"</item>
+ <item msgid="3327323682209964956">"Ekki sýna þetta tákn"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Skjáskipting"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Færa niður"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Færa upp"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Færa til vinstri"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Færa til hægri"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 7e6e37338163..5266ba881c69 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot acquisito."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Tocca per visualizzare il tuo screenshot."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Impossibile acquisire lo screenshot."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Imposs. acquisire screenshot per spazio archiviazione limitato o perché vietato da organizzazione o app."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossibile salvare lo screenshot a causa dello spazio di archiviazione limitato."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opzioni trasferimento file USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Monta come lettore multimediale (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Monta come videocamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Più tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Meno tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torcia spenta."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torcia accesa."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torcia disattivata."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torcia attivata."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"blocco su schermo"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'app <xliff:g id="APP">%s</xliff:g> è stata disattivata in modalità provvisoria."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Cronologia"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Cancella"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Questa app non supporta la modalità multi-finestra"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"L\'app non supporta la modalità multi-finestra"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silenzio\ntotale"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo con\npriorità"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nsveglie"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tutte"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tutte\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ricarica veloce (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ricarica lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Consente di attivare la modalità Schermo diviso scorrendo verso l\'alto dal pulsante Panoramica"</string>
<string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Attiva"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Applica a notifiche <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Applica a tutte le notifiche di quest\'app"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloccata"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importanza scarsa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importanza normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Importanza elevata"</string>
<string name="max_importance" msgid="5089005872719563894">"Importanza urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrare mai queste notifiche"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostra silenziosamente nella parte inferiore dell\'elenco delle notifiche"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostra silenziosamente queste notifiche"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostra nella parte superiore dell\'elenco delle notifiche e riproduci suono"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Apri sullo schermo e riproduci suono"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
<string name="notification_done" msgid="5279426047273930175">"Fine"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Colori normali"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Colori per la notte"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Colori personalizzati"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatico"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Colori sconosciuti"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modifica del colore"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostra il riquadro Impostazioni rapide"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Attiva la trasformazione personalizzata"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Colore e aspetto"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modalità notturna"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibra display"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Attiva"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Disattivata"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Attiva automaticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Attiva la modalità notturna in base alla località e all\'ora del giorno"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Quando la modalità notturna è attiva"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Utilizza tema scuro per sistema Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Regola tinta"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Regola luminosità"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Il tema scuro viene applicato agli elementi fondamentali del sistema operativo Android che vengono generalmente visualizzati con un tema chiaro, ad esempio le impostazioni."</string>
<string name="color_apply" msgid="9212602012641034283">"Applica"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Conferma le impostazioni"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Alcune impostazioni relative ai colori potrebbero rendere inutilizzabile il dispositivo. Fai clic su OK per confermare queste impostazioni; in caso contrario, le impostazioni verranno reimpostate dopo 10 secondi."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batteria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Riduce le prestazioni e i dati in background"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recenti"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Indietro"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostra Non disturbare nella finestra del volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Consenti il controllo totale della funzione Non disturbare nella finestra di dialogo del volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e Non disturbare"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Attiva Non disturbare all\'abbassamento del volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostra con controlli volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Non disturbare"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Pulsanti del volume come scorciatoia"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Disattiva Non disturbare all\'aumento del volume"</string>
<string name="battery" msgid="7498329822413202973">"Batteria"</string>
<string name="clock" msgid="7416090374234785905">"Orologio"</string>
<string name="headset" msgid="4534219457597457353">"Auricolare"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Cuffie collegate"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auricolare collegato"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Consente di attivare o disattivare la visualizzazione delle icone nella barra di stato."</string>
<string name="data_saver" msgid="5037565123367048522">"Risparmio dati"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Risparmio dati attivo"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Risparmio dati disattivato"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Seleziona il tasto della tastiera"</string>
<string name="preview" msgid="9077832302472282938">"Anteprima"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Trascina per aggiungere i riquadri"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Modifica"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Ora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostra ore, minuti e secondi"</item>
+ <item msgid="1427801730816895300">"Mostra ore e minuti (opzione predefinita)"</item>
+ <item msgid="3830170141562534721">"Non mostrare questa icona"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Mostra sempre la percentuale"</item>
+ <item msgid="2139628951880142927">"Mostra la percentuale quando in carica (opzione predefinita)"</item>
+ <item msgid="3327323682209964956">"Non mostrare questa icona"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Strumento per schermo diviso"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Sposta giù"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sposta su"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sposta a sinistra"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sposta a destra"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index bdb0429a8253..a13f975f4c34 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"צילום המסך בוצע."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"גע כדי להציג את צילום המסך שלך"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"לא ניתן לבצע צילום מסך."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"לא ניתן לצלם את המסך מפני שנפח האחסון מוגבל או מפני שהאפליקציה או הארגון שלך אינם מתירים זאת."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"לא ניתן לשמור צילום מסך עקב שטח אחסון מוגבל."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"האפליקציה, או הארגון שלך, אינם מתירים לבצע צילומי מסך."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏אפשרויות העברת קבצים ב-USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏טען כנגן מדיה (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"‏טען כמצלמה (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"יותר זמן."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"פחות זמן."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"הפנס כבוי."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"הפנס מופעל."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"הפנס נכבה."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"הפנס הופעל."</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"הצמדת מסך"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"לא ניתן היה להפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> מושבת במצב בטוח."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"היסטוריה"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"נקה"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"אפליקציה זו אינה תומכת בריבוי חלונות"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"האפליקציה אינה תומכת בריבוי חלונות"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"שקט\nמוחלט"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"הכל"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"הכל\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"בטעינה מהירה (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"בטעינה איטית (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
<string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"הפעל מאיץ מסך מפוצל על ידי החלקה כלפי מעלה"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"הפעל מסך מפוצל על ידי תנועת החלקה כלפי מעלה"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"הפעל את התנועה לכניסה למסך מפוצל על ידי החלקה כלפי מעלה מלחצן הסקירה"</string>
<string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"הפעל"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"החל על הודעות של <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"החל על כל ההודעות מאפליקציה זו"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"חסום"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"חשיבות נמוכה"</string>
<string name="default_importance" msgid="8192107689995742653">"חשיבות רגילה"</string>
<string name="high_importance" msgid="1527066195614050263">"חשיבות גבוהה"</string>
<string name="max_importance" msgid="5089005872719563894">"חשיבות דחופה"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"לעולם אל תציג את ההודעות האלה"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"הצג בחלק התחתון של רשימת ההודעות בלי להשמיע צליל"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"הצג בחלק העליון של רשימת ההודעות והשמע צליל"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"הצג לרגע על המסך והשמע צליל"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
<string name="notification_done" msgid="5279426047273930175">"סיום"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"צבעים רגילים"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"צבעי לילה"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"צבעים מותאמים אישית"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"אוטומטי"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"צבעים לא ידועים"</string>
- <string name="color_transform" msgid="6985460408079086090">"שינוי צבע"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"הצגת אריח של הגדרות מהירות"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"הפעל טרנספורמציה מותאמת אישית"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"צבע ומראה"</string>
+ <string name="night_mode" msgid="3540405868248625488">"מצב לילה"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"כיול תצוגה"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"פועל"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"כבוי"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"הפעל אוטומטית"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"החלף למצב לילה בהתאם למיקום ולשעה ביום"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"כאשר מצב לילה מופעל"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"‏השתמש בעיצוב כהה למערכת ההפעלה של Android."</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"התאמת גוון"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"התאמת בהירות"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"‏העיצוב הכהה מוחל על התחומים העיקריים במערכת ההפעלה של Android שמוצגים בדרך כלל בעיצוב בהיר, כמו \'הגדרות\'."</string>
<string name="color_apply" msgid="9212602012641034283">"החל"</string>
<string name="color_revert_title" msgid="4746666545480534663">"אישור הגדרות"</string>
<string name="color_revert_message" msgid="9116001069397996691">"הגדרות צבע מסוימות עלולות להפוך את המכשיר הזה לבלתי שמיש. לחץ על אישור כדי לאשר את הגדרות הצבע האלה, אחרת הגדרות אלה יתאפסו לאחר 10 שניות."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"סוללה (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"מפחית את רמת הביצועים ואת נתוני הרקע"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"דף הבית"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"אחרונים"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"הקודם"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"הצג את החלונית \'נא לא להפריע\' בעוצמת הקול"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"אפשר שליטה מלאה בחלונית \'נא לא להפריע\' בתיבת הדו-שיח של עוצמת הקול."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"עוצמת הקול והאפשרות \'נא לא להפריע\'"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"היכנס לאפשרות \'נא לא להפריע\' בהחלשת עוצמת הקול"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"הצג עם פקדי עוצמת הקול"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"נא לא להפריע"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"מקש קיצור ללחצני עוצמת קול"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"צא מהאפשרות \'נא לא להפריע\' בהגברת עוצמת הקול"</string>
<string name="battery" msgid="7498329822413202973">"סוללה"</string>
<string name="clock" msgid="7416090374234785905">"שעון"</string>
<string name="headset" msgid="4534219457597457353">"אוזניות"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"אוזניות מחוברות"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"אוזניות מחוברות"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"הפעלה או השבתה של סמלים המוצגים בשורת הסטטוס."</string>
<string name="data_saver" msgid="5037565123367048522">"‏חוסך הנתונים (Data Saver)"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"‏חוסך הנתונים (Data Saver) פועל"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"‏חוסך הנתונים (Data Saver) כבוי"</string>
<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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"בחירת לחצן מקלדת"</string>
<string name="preview" msgid="9077832302472282938">"תצוגה מקדימה"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"גרור כדי להוסיף משבצות"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"ערוך"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"שעה"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"הצג שעות, דקות ושניות"</item>
+ <item msgid="1427801730816895300">"הצג שעות ודקות (ברירת מחדל)"</item>
+ <item msgid="3830170141562534721">"אל תציג את הסמל הזה"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"הצג תמיד באחוזים"</item>
+ <item msgid="2139628951880142927">"הצג באחוזים בזמן טעינה (ברירת מחדל)"</item>
+ <item msgid="3327323682209964956">"אל תציג את הסמל הזה"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"מחלק מסך מפוצל"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"הזז למטה"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"הזז למעלה"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"הזז שמאלה"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"הזז ימינה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 55f7eadb725c..d3a8b2ce8839 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"スクリーンショットを取得しました。"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"タップしてスクリーンショットを表示します。"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"スクリーンショットをキャプチャできませんでした。"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"空き容量が足りないか、アプリまたは組織によって許可されていないため、スクリーンショットは撮れません。"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"空き容量が足りないため、スクリーンショットを保存できません。"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"アプリまたは組織によって許可されていないため、スクリーンショットは撮れません。"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USBファイル転送オプション"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"メディアプレーヤー(MTP)としてマウント"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"カメラ(PTP)としてマウント"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"長くします。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"短くします。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ライトがOFFです。"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ライトがONです。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ライトをOFFにしました。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ライトをONにしました。"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"画面固定"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」はセーフモードでは無効になります。"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"履歴"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"消去"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"このアプリはマルチウィンドウに対応していません"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"アプリはマルチウィンドウに対応していません"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"サイレント\n"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"重要な\n通知のみ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"アラーム\nのみ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"すべて"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"すべて\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"急速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"低速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
<string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"スワイプアップ分割画面アクセラレータを有効にする"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"上にスワイプして分割画面に切り替える操作を有効にする"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"[概要] ボタンから上にスワイプして分割画面に切り替える操作を有効にします"</string>
<string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ONにする"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」の通知に適用"</string>
- <string name="apply_to_app" msgid="363016783939815960">"このアプリからのすべての通知に適用"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"ブロック中"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"重要度: 低"</string>
<string name="default_importance" msgid="8192107689995742653">"重要度: 中"</string>
<string name="high_importance" msgid="1527066195614050263">"重要度: 高"</string>
<string name="max_importance" msgid="5089005872719563894">"重要度: 緊急"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"今後はこの通知を表示しない"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"通知リストの末尾にマナーモードで表示する"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"この通知をマナーモードで表示する"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"通知リストの先頭に表示し、音声でも知らせる"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"画面に数秒間表示し、音声でも知らせる"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完了"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"標準の色"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"夜間の色"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"カスタムの色"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"自動"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"不明な色"</string>
- <string name="color_transform" msgid="6985460408079086090">"色の変更"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"[クイック設定] タイルの表示"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"カスタム変換の有効化"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"色と表示"</string>
+ <string name="night_mode" msgid="3540405868248625488">"夜間モード"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"表示の調整"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ON"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"OFF"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"自動的に ON"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"場所や時間に応じて夜間モードに切り替えます"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"夜間モードが ON のとき"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS でダークテーマを使用"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ティントを調整"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"明るさを調整"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"通常ライトテーマで表示される Android OS の主要領域(設定など)にダークテーマが適用されます。"</string>
<string name="color_apply" msgid="9212602012641034283">"適用"</string>
<string name="color_revert_title" msgid="4746666545480534663">"設定の確認"</string>
<string name="color_revert_message" msgid="9116001069397996691">"一部の色設定を適用すると、この端末を使用できなくなることがあります。この色設定を確認するには、[OK] をクリックしてください。確認しない場合、10 秒後に設定はリセットされます。"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"バッテリー(<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"パフォーマンスとバックグラウンド データを制限します"</string>
@@ -485,17 +509,15 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ホーム"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"戻る"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"音量内に [通知を非表示] を表示"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"音量ダイアログでの [通知を非表示] の管理を許可します。"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量と [通知を非表示]"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"音量下げボタンで [通知を非表示] を ON にする"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"音量調節を表示"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"通知の非表示"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"音量ボタンのショートカット"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"音量上げボタンで [通知を非表示] を OFF にする"</string>
<string name="battery" msgid="7498329822413202973">"電池"</string>
<string name="clock" msgid="7416090374234785905">"時計"</string>
<string name="headset" msgid="4534219457597457353">"ヘッドセット"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ヘッドホンを接続しました"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ヘッドセットを接続しました"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ステータスバーでのアイコンの表示を有効または無効にします。"</string>
<!-- no translation found for data_saver (5037565123367048522) -->
<skip />
<!-- no translation found for accessibility_data_saver_on (8454111686783887148) -->
@@ -503,6 +525,7 @@
<!-- no translation found for accessibility_data_saver_off (8841582529453005337) -->
<skip />
<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>
@@ -524,4 +547,23 @@
<string name="select_keycode" msgid="7413765103381924584">"キーボードのボタンの選択"</string>
<string name="preview" msgid="9077832302472282938">"プレビュー"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"タイルを追加するにはドラッグしてください"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"編集"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"時間"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"時間、分、秒を表示"</item>
+ <item msgid="1427801730816895300">"時間、分を表示(デフォルト)"</item>
+ <item msgid="3830170141562534721">"このアイコンを表示しない"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"常に割合を表示"</item>
+ <item msgid="2139628951880142927">"変更時に割合を表示(デフォルト)"</item>
+ <item msgid="3327323682209964956">"このアイコンを表示しない"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"分割画面の分割線"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下に移動"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上に移動"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左に移動"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右に移動"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 6a0ece8bdbc8..d14a3c9fb7d4 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"სკრინშოტი გადაღებულია."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"შეეხეთ ეკრანის სურათის სანახავად."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ვერ მოხერხდა ეკრანის ანაბეჭდის გადაღება."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"ეკრანის ანაბეჭდი ვერ შეიქმნა შეზღუდული სივრცის გამო, ან შეზღუდულია თქვენი ორგანიზაციის აპის მიერ."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა შეზღუდული მეხსიერების გამო."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ფაილის ტრანსფერის პარამეტრები"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"მედია-საკრავად (MTP) ჩართვა"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"მიუერთეთ როგორც კამერა (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"მეტი დრო."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ნაკლები დრო."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ფანარი გამორთულია."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ფანარი ჩართულია."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ფანარი გამოირთო."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ფანარი ჩაირთო."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ეკრანზე ჩამაგრება"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-ის გამოძახება ვერ მოხერხდა."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> გათიშულია უსაფრთხო რეჟიმში."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ისტორია"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"გასუფთავება"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"მრავალი ფანჯრის რეჟიმი არ არის მხარდაჭერილი ამ აპის მიერ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"მრავალი ფანჯრის რეჟიმი არ არის მხარდაჭერილი აპის მიერ"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"სრული\nსიჩუმე"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"მხოლოდ\nპრიორიტეტულები"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"მხოლოდ\nგაფრთხილებები"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ყველა"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ყველა\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"იტენება სწრაფად (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"იტენება ნელა (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
<string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის მაჩქარებლის ჩართვა"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის ჟესტის ჩართვა"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"მიმოხილვის ღილაკიდან ზემოთ გადაფურცვლისას ეკრანის გაყოფის რეჟიმზე გადასვლის ჟესტის ჩართვა"</string>
<string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ჩართვა"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"„<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“ ტიპის შეტყობინებებისთვის მისადაგება"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ამ აპის ყველა შეტყობინებისთვის მისადაგება"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"დაბლოკილი"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"დაბალი პრიორიტეტი"</string>
<string name="default_importance" msgid="8192107689995742653">"ჩვეულებრივი პრიორიტეტი"</string>
<string name="high_importance" msgid="1527066195614050263">"მაღალი პრიორიტეტი"</string>
<string name="max_importance" msgid="5089005872719563894">"გადაუდებელი"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ამ შეტყობინებების ჩვენების შეწყვეტა"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"ამ შეტყობინებების სიის ბოლოში, უხმოდ ჩვენება"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"ამ შეტყობინებების სიის თავში, ხმოვან სიგნალთან ერთად ჩვენება"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"ამ შეტყობინებების პირდაპირ ეკრანზე, ხმოვან სიგნალთან ერთად ჩვენება"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
<string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ჩვეულებრივი ფერები"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ღამის ფერები"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"მორგებული ფერები"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ავტომატური"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"უცნობი ფერები"</string>
- <string name="color_transform" msgid="6985460408079086090">"ფერების შეცვლა"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"სწრაფი პარამეტრების მოზაიკის ჩვენება"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"მორგებული გარდაქმნის ჩართვა"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"ფერი და იერსახე"</string>
+ <string name="night_mode" msgid="3540405868248625488">"ღამის რეჟიმი"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ეკრანის კალიბრაცია"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ჩართული"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"გამორთული"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"ავტომატურად ჩართვა"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ღამის რეჟიმზე გადართვა მდებარეობისა და დღე-ღამის მონაკვეთის შესაბამისად."</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"ღამის რეჟიმის ჩართვისას"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS-ისთვის მუქი თემის გამოყენება"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ელფერის გასწორება"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"სიკაშკაშის გასწორება"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"მუქი თემა მიესადაგება Android OS-ის ძირითად არეებს, რომლებიც, ჩვეულებრივ, ღია თემის მეშვეობით არის ნაჩვენები. მაგალითად, პარამეტრებს."</string>
<string name="color_apply" msgid="9212602012641034283">"გამოყენება"</string>
<string name="color_revert_title" msgid="4746666545480534663">"პარამეტრების დადასტურება"</string>
<string name="color_revert_message" msgid="9116001069397996691">"ფერთა ზოგიერთ პარამეტრს ამ მოწყობილობასთან მუშაობის გართულება შეუძლია. ფერთა ამჟამინდელი პარამეტრების დასადასტურებლად, დააწკაპუნეთ „კარგი“-ზე. წინააღმდეგ შემთხვევაში, პარამეტრები 10 წამის შემდეგ ჩამოიყრება."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ბატარეა (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ამცირებს წარმადობას და ფონურ მონაცემებს"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"მთავარი"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ბოლოს გამოყენებული"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"უკან"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"ხმის დიალოგში „არ შემაწუხოთ“ რეჟიმის ჩვენება"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ხმის დიალოგში „არ შემაწუხოთ“ რეჟიმის სრული კონტროლის დაშვება."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ხმა და „არ შემაწუხოთ“"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ხმის დაწევისას „არ შემაწუხოთ“ რეჟიმზე გადასვლა"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ხმის მართვის საშუალებების ჩვენება"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"არ შემაწუხოთ"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ხმის ღილაკების მალსახმობი"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ხმის აწევისას „არ შემაწუხოთ“ რეჟიმიდან გამოსვლა"</string>
<string name="battery" msgid="7498329822413202973">"ბატარეა"</string>
<string name="clock" msgid="7416090374234785905">"საათი"</string>
<string name="headset" msgid="4534219457597457353">"ყურსაცვამი"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ყურსასმენები დაკავშირებულია"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ყურსაცვამი დაკავშირებულია"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"სტატუსის ზოლში ხატულების ჩვენების ჩართვა ან გათიშვა."</string>
<string name="data_saver" msgid="5037565123367048522">"მონაცემთა დამზოგველი"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"მონაცემთა დამზოგველი ჩართულია"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"მონაცემთა დამზოგველი გამორთულია"</string>
<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>
@@ -520,5 +543,24 @@
<string name="keycode_description" msgid="1403795192716828949">"კლავიშის კოდის ტიპის ღილაკების მეშვეობით ნავიგაციის ზოლში კლავიატურის კლავიშების დამატება არის შესაძლებელი. მათზე დაჭერისას არჩეული კლავიატურის კლავიშის ემულაცია ხდება. პირველ რიგში, ღილაკისთვის უნდა აირჩეს კლავიში, ხოლო შემდეგ სურათი, რომელიც ღილაკზე უნდა იყოს ნაჩვენები."</string>
<string name="select_keycode" msgid="7413765103381924584">"აირჩიეთ კლავიატურის ღილაკი"</string>
<string name="preview" msgid="9077832302472282938">"გადახედვა"</string>
- <string name="drag_to_add_tiles" msgid="7058945779098711293">"მოზაიკების დასამატებლად, გადაიტანეთ ჩავლებით"</string>
+ <string name="drag_to_add_tiles" msgid="7058945779098711293">"ფილების დასამატებლად, გადაიტანეთ ჩავლებით"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"რედაქტირება"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"დრო"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"საათების, წუთებისა და წამების ჩვენება"</item>
+ <item msgid="1427801730816895300">"საათებისა და წუთების ჩვენება (ნაგულისხმევი)"</item>
+ <item msgid="3830170141562534721">"აღარ მაჩვენო ეს ხატულა"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"პროცენტულობის ყოველთვის ჩვენება"</item>
+ <item msgid="2139628951880142927">"პროცენტულობის დატენვისას ჩვენება (ნაგულისხმევი)"</item>
+ <item msgid="3327323682209964956">"აღარ მაჩვენო ეს ხატულა"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ქვემოთ გადატანა"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ზემოთ გადატანა"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"მარცხნივ გადატანა"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"მარჯვნივ გადატანა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 9b50dbc31e7c..a2346b3adb54 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сақталды."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Скриншотты көру үшін түрту."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот жасалмады."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Шектеулі жад кеңістігіне байланысты скриншот түсіру мүмкін емес немесе бұған қолданба немесе ұйым рұқсат етпейді."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Жадтағы шектеулі бос орынға байланысты скриншотты сақтау мүмкін емес."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB файлын жіберу опциялары"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойнатқыш (MTP) ретінде қосыңыз"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Камера ретінде (PTP) қосыңыз"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбірек уақыт."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азырақ уақыт."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Қол шам өшірулі."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Қол шам қосулы."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Қол шам өшірілді."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Қол шам қосылды."</string>
@@ -301,8 +304,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экранды бекіту"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"Тарих"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалау"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бұл қолданба көп терезені қолдамайды"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Қолданба көп терезені қолдамайды"</string>
<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>
@@ -332,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Толық\nтыныштық"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Тек\nбасымдық"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Тек\nдабылдар"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Барлығы"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Барлығы\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Жылдам зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Баяу зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
<string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Бөлінген экранды жоғары қарай жанау жеделдеткішін қосу"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Бөлінген экранда жоғары қарай сырғыту қимылын қосу"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\"Шолу\" түймесінен жоғары қарай жанау арқылы бөлінген экранға кіру қимылын қосу"</string>
<string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Қосу"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> хабарландыруға қолдану"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Осы қолданбаның барлық хабарландыруларына қолдану"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Бөгелген"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Төмен маңыздылық"</string>
<string name="default_importance" msgid="8192107689995742653">"Қалыпты маңыздылық"</string>
<string name="high_importance" msgid="1527066195614050263">"Жоғары маңыздылық"</string>
<string name="max_importance" msgid="5089005872719563894">"Шұғыл маңыздылық"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Осы хабарландыруларды ешқашан көрсетпеу"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Осы хабарландыруларды үнсіз көрсету"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Хабарландыруларды тізімінің жоғарғы жағында көрсету және дыбыс шығару"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Экранға бекіту және дыбыс шығару"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
<string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Қалыпты түстер"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Түнгі түстер"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Арнаулы түстер"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Белгісіз түстер"</string>
- <string name="color_transform" msgid="6985460408079086090">"Түсті өзгерту"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Жылдам параметрлер торын көрсету"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Арнаулы түрлендіруді қосу"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Түс және сыртқы түрі"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Түнгі режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Дисплейді калибрлеу"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Қосулы"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Өшірулі"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматты түрде қосу"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Орынға және күн уақытына тиісті түнгі режимге ауысу"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Түнгі режим қосулы кезде"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android ОЖ үшін күңгірт тақырыпты пайдалану"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Реңкті реттеу"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Жарықтықты реттеу"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Күңгірт тақырып Android операциялық жүйесінің әдетте ашық тақырыпта көрсетілетін негізгі аумақтарына қолданылады, мысалы, \"Параметрлер\" тармағына."</string>
<string name="color_apply" msgid="9212602012641034283">"Қолдану"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Батарея (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Өнімділікті және фондық деректерді азайтады"</string>
@@ -485,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Негізгі бет"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Жақындағылар"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артқа"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Дыбыс деңгейінде \"Мазаламау\" режимін көрсету"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дыбыс деңгейі диалогтық терезесінде \"Мазаламау\" режимін толық басқаруға рұқсат ету."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Дыбыс деңгейі және \"Мазаламау\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Дыбыс деңгейін төмендеткенде \"Мазаламау\" режиміне кіру"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Дыбыс деңгейін басқару элементтерімен бірге көрсету"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Мазаламау"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Дыбыс деңгейі түймелерінің төте жолы"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Дыбыс деңгейін көтергенде \"Мазаламау\" режимінен шығу"</string>
<string name="battery" msgid="7498329822413202973">"Батарея"</string>
<string name="clock" msgid="7416090374234785905">"Сағат"</string>
<string name="headset" msgid="4534219457597457353">"Құлақаспап жинағы"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Құлақаспап қосылды"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Құлақаспап жинағы қосылды"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Белгішелердің күй жолағында көрсетілуін қосу немесе өшіру"</string>
<string name="data_saver" msgid="5037565123367048522">"Дерек сақтағыш"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Дерек сақтағыш қосулы"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Дерек сақтағышы өшірулі"</string>
<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>
@@ -521,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Пернетақта түймесін таңдау"</string>
<string name="preview" msgid="9077832302472282938">"Алдын ала қарау"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Торлар қосу үшін сүйреңіз"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Өңдеу"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Уақыт"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Сағаттарды, минуттарды және секундтарды көрсету"</item>
+ <item msgid="1427801730816895300">"Сағаттарды және минуттарды көрсету (әдепкі)"</item>
+ <item msgid="3830170141562534721">"Бұл белгішені көрсетпеу"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Әрқашан пайызды көрсету"</item>
+ <item msgid="2139628951880142927">"Зарядтау кезінде пайызды көрсету (әдепкі)"</item>
+ <item msgid="3327323682209964956">"Бұл белгішені көрсетпеу"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Бөлінген экран бөлгіші"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмен қарай жылжыту"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жоғары қарай жылжыту"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солға жылжыту"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңға жылжыту"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index a4d6c0636d6c..97772ad9ece8 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"បាន​ចាប់​យក​រូបថត​អេក្រង់។​"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ​ដើម្បី​មើល​រូបថត​អេក្រង់​របស់​អ្នក​។"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"មិន​អាច​ចាប់​យក​រូប​ថត​អេក្រង់​។"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"មិនអាចថតអេក្រង់ដោយសារតែទំហំផ្ទុកមានដែនកំណត់ ឬវាមិនត្រូវបានអនុញ្ញាត​ដោយកម្មវិធី ឬ​ស្ថាប័ន​របស់​អ្នក។"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"មិនអាចរក្សាទុករូបថតអេក្រង់បានទេដោយសារទំហំផ្ទុកមានកម្រិត។"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ការថតរូបអេក្រង់មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធីនេះ ឬស្ថាប័នរបស់អ្នក។"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"ជម្រើស​ផ្ទេរ​ឯកសារ​តាម​យូអេសប៊ី"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ភ្ជាប់​ជា​កម្មវិធី​ចាក់​មេឌៀ (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ភ្ជាប់​ជា​ម៉ាស៊ីន​ថត (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ច្រើនជាង"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"តិច​ជាង"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"បិទ​ពិល។"</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ពិលមិនអាចប្រើបានទេ"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"បើក​ពិល។"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"បាន​បិទ​ពិល។"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"បាន​បើក​ពិល។"</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ការ​ភ្ជាប់​អេក្រង់"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ទេ។"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ត្រូវបានបិទដំណើរការក្នុងរបៀបសុវត្ថិភាព"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ប្រវត្តិ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"សម្អាត"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"កម្មវិធីនេះមិនគាំទ្រផ្ទាំងវិដូច្រើនទេ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"កម្មវិធីមិនគាំទ្រផ្ទាំងវិដូច្រើនទេ"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"ស្ងៀមស្ងាត់\nទាំងស្រុង"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"អាទិភាព\nប៉ុណ្ណោះ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ទាំងអស់"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ទាំងអស់\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ថ្មកំពុងសាកលឿន (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ថ្មកំពុងសាកយឺតៗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
<string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"បើកដំណើរការឧបករណ៍បង្កើនល្បឿនការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"បើកដំណើរការកាយវិការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"បើកដំណើរការកាយវិការដើម្បីបំបែកអេក្រង់ដោយអូសទៅលើចាប់ពីប៊ូតុងទិដ្ឋភាព"</string>
<string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"បើក"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"អនុវត្តចំពោះការជូនដំណឹង <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"អនុវត្តចំពោះការជូនដំណឹងទាំងអស់ពីកម្មវិធីនេះ"</string>
+ <string name="show_silently" msgid="6841966539811264192">"បង្ហាញការជូនដំណឹងស្ងាត់ៗ"</string>
+ <string name="block" msgid="2734508760962682611">"រារាំងការជូនដំណឹងទាំងអស់"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"កុំបិទសំឡេង"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"កុំបិទសំឡេង ឬរារាំង"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"បង្ហាញការកំណត់កម្រិតភាពសំខាន់ពេញលេញ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"បានរារាំង"</string>
+ <string name="min_importance" msgid="1901894910809414782">"កម្រិតសំខាន់អប្បបរមា"</string>
<string name="low_importance" msgid="4109929986107147930">"មិនសូវសំខាន់"</string>
<string name="default_importance" msgid="8192107689995742653">"សំខាន់មធ្យម"</string>
<string name="high_importance" msgid="1527066195614050263">"សំខាន់ខ្លាំង"</string>
<string name="max_importance" msgid="5089005872719563894">"សំខាន់ជាបន្ទាន់"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"កុំបង្ហាញការជូនដំណឹងទាំងនេះ"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង និងបន្លឺសំឡេង"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"លោតបង្ហាញនៅលើអេក្រង់ និងបន្លឺសំឡេង"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"អនុញ្ញាតឲ្យការជូនដំណឹងទាំងនេះបន្លឺសំឡេង"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"លោតបង្ហាញនៅលើអេក្រង់ និងអនុញ្ញាតឲ្យបន្លឺសំឡេង"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង លោតបង្ហាញនៅលើអេក្រង់ និងអនុញ្ញាតឲ្យបន្លឺសំឡេង"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
<string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ពណ៌ធម្មតា"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ពណ៌ពេលយប់"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ពណ៌ផ្ទាល់ខ្លួន"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ស្វ័យប្រវត្តិ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"ពណ៌មិនស្គាល់"</string>
- <string name="color_transform" msgid="6985460408079086090">"ការកែសម្រួលពណ៌"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"បង្ហាញផ្ទាំងប្រអប់ការកំណត់រហ័ស"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"បើកដំណើរការផ្លាស់ប្តូរផ្ទាល់ខ្លួន"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"ពណ៌ និងរូបរាង"</string>
+ <string name="night_mode" msgid="3540405868248625488">"របៀបពេលយប់"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ការបង្ហាញក្រិត"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"បើក"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"បិទ"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"បើក​ដោយ​ស្វ័យ​ប្រវត្តិ"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ប្តូរទៅជារបៀបពេលយប់ដែលសមស្របទៅតាមទីកន្លែង និងពេលវេលា"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"នៅពេលបើករបៀបពេលយប់"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"ប្រើធីមងងឹតសម្រាប់ប្រព័ន្ធប្រតិបត្តិការ Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"កែសម្រួលពណ៌ព្រឿងៗ"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"កែសម្រួលពន្លឺ"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ធីមងងឹតត្រូវបានប្រើសម្រាប់ចំណុចស្នូលនៃប្រព័ន្ធប្រតិបត្តិការ Android ដែលជាទូទៅត្រូវបានបង្ហាញជាធីមភ្លឺ ដូចជាការកំណត់ជាដើម។"</string>
<string name="color_apply" msgid="9212602012641034283">"អនុវត្ត"</string>
<string name="color_revert_title" msgid="4746666545480534663">"បញ្ជាក់ការកំណត់"</string>
<string name="color_revert_message" msgid="9116001069397996691">"ការកំណត់ពណ៌មួយចំនួនអាចធ្វើឲ្យឧបករណ៍នេះមិនអាចប្រើបាន។ សូមចុច យល់ព្រម ដើម្បីបញ្ជាក់ការកំណត់ពណ៌ទាំងនេះ បើមិនដូច្នេះទេការកំណត់ទាំងនេះនឹងកំណត់ឡើងវិញក្នុងរយៈពេល 10 វិនាទីបន្ទាប់។"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ថ្ម (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"កាត់បន្ថយប្រតិបត្តិការ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ដើម"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ថ្មីៗ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ថយក្រោយ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"បង្ហាញមុខងារកុំរំខាននៅក្នុងកម្រិតសំឡេង"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"អនុញ្ញាតឲ្យមានការគ្រប់គ្រងពេញលេញចំពោះមុខងារកុំរំខាននៅក្នុងប្រអប់កម្រិតសំឡេង។"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"កម្រិតសំឡេង និងមុនងារកុំរំខាន"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ចូលមុខងារកុំរំខាននៅពេលបន្ថយសំឡេង"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"បង្ហាញជាមួយការគ្រប់គ្រងកម្រិតសំឡេង"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"កុំ​រំខាន"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ផ្លូវកាត់ប៊ូតុងកម្រិតសំឡេង"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ចាកចេញពីមុខងារកុំរំខាននៅពេលបង្កើនសំឡេង"</string>
<string name="battery" msgid="7498329822413202973">"ថ្ម"</string>
<string name="clock" msgid="7416090374234785905">"នាឡិកា"</string>
<string name="headset" msgid="4534219457597457353">"កាស"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"បានភ្ជាប់កាស"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"បានភ្ជាប់កាស"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"បើក ឬបិទដំណើរការបង្ហាញរូបតំណាងនៅលើរបារស្ថានភាព"</string>
<string name="data_saver" msgid="5037565123367048522">"កម្មវិធីសន្សំសំចៃទិន្នន័យ"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"កម្មវិធីសន្សំសំចៃទិន្នន័យបានបើក"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"កម្មវិធីសន្សំសំចៃទិន្នន័យបានបិទ"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"ជ្រើសប៊ូតុងក្តារចុច"</string>
<string name="preview" msgid="9077832302472282938">"មើលជាមុន"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"អូសដើម្បីបន្ថែមចំណងជើង"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"កែសម្រួល"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"ម៉ោង"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"បង្ហាញម៉ោង នាទី និងវិនាទី"</item>
+ <item msgid="1427801730816895300">"បង្ហាញម៉ោង នាទី (លំនាំដើម)"</item>
+ <item msgid="3830170141562534721">"កុំបង្ហាញរូបតំណាងនេះ"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"បង្ហាញភាគរយជានិច្ច"</item>
+ <item msgid="2139628951880142927">"បង្ហាញភាគរយនៅពេលសាកថ្ម (លំនាំដើម)"</item>
+ <item msgid="3327323682209964956">"កុំបង្ហាញរូបតំណាងនេះ"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"ផ្សេងៗ"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"កម្មវិធីចែកអេក្រង់បំបែក"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ផ្លាស់ទីចុះក្រោម"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ផ្លាស់ទីឡើងលើ"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ផ្លាស់ទីទៅឆ្វេង"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ផ្លាស់ទីទៅស្តាំ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 8c0e42f5553b..481b918c3f14 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ವೀಕ್ಷಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಸೆರೆಹಿಡಿಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"ಪರಿಮಿತ ಸಂಗ್ರಹಣೆ ಸ್ಥಳ, ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಅನುಮತಿಯಿಲ್ಲದಿರುವ ಕಾರಣ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ಪರಿಮಿತ ಸಂಗ್ರಹಣೆ ಸ್ಥಳದ ಕಾರಣದಿಂದಾಗಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳುವುದನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆ ಅನುಮತಿಸುವುದಿಲ್ಲ."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ಫೈಲ್ ವರ್ಗಾವಣೆ ಆಯ್ಕೆಗಳು"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ಮೀಡಿಯಾ ಪ್ಲೇಯರ್ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ಕ್ಯಾಮರಾ ರೂಪದಲ್ಲಿ ಅಳವಡಿಸಿ (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ಹೆಚ್ಚು ಸಮಯ."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ಕಡಿಮೆ ಸಮಯ."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆಫ್ ಆಗಿದೆ."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆನ್ ಆಗಿದೆ."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ಸ್ಕ್ರೀನ್ ಪಿನ್ನಿಂಗ್"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್‌ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ಇತಿಹಾಸ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ತೆರವುಗೊಳಿಸು"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಬಹು-ವಿಂಡೊಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ಅಪ್ಲಿಕೇಶನ್ ಬಹು-ವಿಂಡೊಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"ಸಂಪೂರ್ಣ\nನಿಶ್ಯಬ್ಧ"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ಆದ್ಯತೆ\nಮಾತ್ರ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ಅಲಾರಮ್‌ಗಳು\nಮಾತ್ರ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ಎಲ್ಲ"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ಎಲ್ಲಾ\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ನಿಧಾನ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
<string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ವೇಗವರ್ಧಕವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ಗೆಶ್ಚರ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ಸಮಗ್ರ ನೋಟದ ಬಟನ್‌ನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಸ್ಪ್ಲಿಟ್‌-ಸ್ಕ್ರೀನ್ ನಮೂದಿಸಲು ಗೆಸ್ಚರ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ಆನ್ ಮಾಡು"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿ"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿ"</string>
+ <string name="show_silently" msgid="6841966539811264192">"ಸ್ಥಬ್ಧವಾಗಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string>
+ <string name="block" msgid="2734508760962682611">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ಮೌನವಾಗಿಸಬೇಡಿ"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ಸ್ಥಬ್ದ ಅಥವಾ ನಿರ್ಬಂಧಿಸಬೇಡಿ"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ಪೂರ್ಣ ಪ್ರಾಮುಖ್ಯತೆ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
+ <string name="min_importance" msgid="1901894910809414782">"ಕನಿಷ್ಟ ಪ್ರಾಮುಖ್ಯತೆ"</string>
<string name="low_importance" msgid="4109929986107147930">"ಕಡಿಮೆ ಪ್ರಾಮುಖ್ಯತೆ"</string>
<string name="default_importance" msgid="8192107689995742653">"ಸಾಮಾನ್ಯ ಪ್ರಾಮುಖ್ಯತೆ"</string>
<string name="high_importance" msgid="1527066195614050263">"ಉನ್ನತ ಪ್ರಾಮುಖ್ಯತೆ"</string>
<string name="max_importance" msgid="5089005872719563894">"ತುರ್ತು ಪ್ರಾಮುಖ್ಯತೆ"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಎಂದಿಗೂ ತೋರಿಸಬೇಡ"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ಈ ಅಧಿಸೂಚನೆಯು ಧ್ವನಿಗಳನ್ನು ಮಾಡಲು ಅನುಮತಿಸಿ"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು, ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಅನುಮತಿಸಿ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ಸಾಮಾನ್ಯ ಬಣ್ಣಗಳು"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ರಾತ್ರಿ ಬಣ್ಣಗಳು"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ಕಸ್ಟಮ್ ಬಣ್ಣಗಳು"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ಸ್ವಯಂ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"ಅಪರಿಚಿತ ಬಣ್ಣಗಳು"</string>
- <string name="color_transform" msgid="6985460408079086090">"ಬಣ್ಣ ಬದಲಾವಣೆ"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಟೈಲ್ ತೋರಿಸು"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"ಕಸ್ಟಮ್ ಪರಿವರ್ತನೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"ಬಣ್ಣ ಮತ್ತು ಗೋಚರತೆ"</string>
+ <string name="night_mode" msgid="3540405868248625488">"ರಾತ್ರಿ ಮೋಡ್"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ಅಣಿಗೊಳಿಸುವ ಪ್ರದರ್ಶನ"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ಆನ್"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ಆಫ್"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಮಾಡು"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ಸ್ಥಳ ಮತ್ತು ದಿನದ ಸಮಯಕ್ಕೆ ಸೂಕ್ತವಾಗುವಂತೆ ರಾತ್ರಿ ಮೋಡ್‌ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"ರಾತ್ರಿ ಮೋಡ್‌ ಆನ್‌ ಆಗಿರುವಾಗ"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS ಗೆ ಕಪ್ಪು ಥೀಮ್‌ ಬಳಸಿ"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ಟಿಂಟ್‌ ಸರಿಹೊಂದಿಸು"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ಪ್ರಖರತೆಯನ್ನು ಸರಿಹೊಂದಿಸು"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ಕಪ್ಪು ಥೀಮ್‌ ಅನ್ನು Android OS ನ ಕೋರ್‌ ಪ್ರದೇಶಗಳಿಗೆ ಅನ್ವಯಿಸಲಾಗಿರುತ್ತದೆ. ಇದನ್ನು ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಂತಹ ತಿಳಿಯಾದ ಥೀಮ್‌ನಲ್ಲಿ ಸಾಮಾನ್ಯವಾಗಿ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ."</string>
<string name="color_apply" msgid="9212602012641034283">"ಅನ್ವಯಿಸು"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಖಚಿತಪಡಿಸಿ"</string>
<string name="color_revert_message" msgid="9116001069397996691">"ಕೆಲವು ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಈ ಸಾಧನವನ್ನು ಅನುಪಯುಕ್ತಗೊಳಿಸಬಹುದು. ಈ ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಖಚಿತಪಡಿಸಲು ಸರಿ ಕ್ಲಿಕ್ ಮಾಡಿ, ಇಲ್ಲವಾದರೆ ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು 10 ಸೆಕೆಂಡುಗಳ ನಂತರ ಮರುಹೊಂದಿಸಿ."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ಬ್ಯಾಟರಿ (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ಮುಖಪುಟ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ಇತ್ತೀಚಿನವುಗಳು"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ಹಿಂದೆ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"ವಾಲ್ಯೂಮ್‌ನಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\" ಅನ್ನು ತೋರಿಸಿ"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ವಾಲ್ಯೂಮ್ ಸಂವಾದದಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\"ಯ ಸಂಪೂರ್ಣ ನಿಯಂತ್ರಣವನ್ನು ಅನುಮತಿಸಿ."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ವಾಲ್ಯೂಮ್‌ ಮತ್ತು ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ವಾಲ್ಯೂಮ್ ಕಡಿಮೆಯಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\" ನಮೂದಿಸಿ"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ವಾಲ್ಯೂಮ್ ನಿಯಂತ್ರಣಗಳ ಜೊತೆಗೆ ತೋರಿಸು"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ವಾಲ್ಯೂಮ್ ಬಟನ್‌ಗಳ ಶಾರ್ಟ್‌ಕಟ್‌"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ವಾಲ್ಯೂಮ್ ಹೆಚ್ಚಳದಲ್ಲಿ \"ಅಡಚಣೆ ಮಾಡಬೇಡಿ\"ಯನ್ನು ತೊರೆಯಿರಿ"</string>
<string name="battery" msgid="7498329822413202973">"ಬ್ಯಾಟರಿ"</string>
<string name="clock" msgid="7416090374234785905">"ಗಡಿಯಾರ"</string>
<string name="headset" msgid="4534219457597457353">"ಹೆಡ್‌ಸೆಟ್"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ಹೆಡ್‌ಫೋನ್ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ಹೆಡ್‌ಸೆಟ್ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಐಕಾನ್‌ಗಳು ತೋರಿಸುವುದನ್ನು ಸಕ್ರಿಯ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ."</string>
<string name="data_saver" msgid="5037565123367048522">"ಡೇಟಾ ಉಳಿಸುವಿಕೆ"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ಡೇಟಾ ಉಳಿಸುವಿಕೆ ಆನ್ ಆಗಿದೆ"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ಡೇಟಾ ಉಳಿಸುವಿಕೆ ಆಫ್ ಆಗಿದೆ"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"ಕೀಬೋರ್ಡ್ ಬಟನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="preview" msgid="9077832302472282938">"ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ಟೈಲ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"ಸಂಪಾದಿಸು"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"ಸಮಯ"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ಗಂಟೆಗಳು, ನಿಮಿಷಗಳು, ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು"</item>
+ <item msgid="1427801730816895300">"ಗಂಟೆಗಳು ಮತ್ತು ನಿಮಿಷಗಳನ್ನು ತೋರಿಸು (ಡಿಫಾಲ್ಟ್‌)"</item>
+ <item msgid="3830170141562534721">"ಈ ಐಕಾನ್ ತೋರಿಸಬೇಡ"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ಯಾವಾಗಲೂ ಪ್ರತಿಶತವನ್ನು ತೋರಿಸು"</item>
+ <item msgid="2139628951880142927">"ಚಾರ್ಜ್‌ ಮಾಡುವಾಗ ಪ್ರತಿಶತವನ್ನು ತೋರಿಸು (ಡಿಫಾಲ್ಟ್‌)"</item>
+ <item msgid="3327323682209964956">"ಈ ಐಕಾನ್ ತೋರಿಸಬೇಡ"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"ಇತರ"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ಕೆಳಗೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ಮೇಲೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2e0fc9026ea6..a3f4ff13b54e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"캡쳐화면 저장됨"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"캡쳐화면을 보려면 터치하세요."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"캡쳐화면을 캡쳐하지 못했습니다."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"저장 공간이 부족하거나 앱 또는 소속 조직에서 허용하지 않아 스크린샷을 찍을 수 없습니다."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"저장용량이 부족하여 스크린샷을 저장할 수 없습니다."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"앱이나 조직에서 스크린샷 촬영을 허용하지 않습니다."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 파일 전송 옵션"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"미디어 플레이어로 마운트(MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"카메라로 마운트(PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"시간 늘리기"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"시간 줄이기"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"손전등: 사용 중지"</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"손전등을 사용할 수 없습니다."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"손전등: 사용"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"손전등이 사용 중지되었습니다."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"손전등을 사용합니다."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"화면 고정"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>은(는) 안전 모드에서 사용 중지됩니다."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"기록"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"삭제"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"이 앱은 다중 창을 지원하지 않습니다."</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"앱이 다중 창을 지원하지 않습니다."</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"모두\n차단"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"중요 알림만\n허용"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"알람만\n"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"모두 수신"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"모두\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"고속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"저속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
<string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"위로 스와이프하여 창 분할하기 사용 설정"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"화면 분할 위로 스와이프 동작 사용"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"최근 사용 버튼에서 위로 스와이프하기 동작으로 창 분할 모드를 사용 설정합니다."</string>
<string name="experimental" msgid="6198182315536726162">"베타"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"사용"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> 알림에 적용"</string>
- <string name="apply_to_app" msgid="363016783939815960">"이 앱의 전체 알림에 적용"</string>
+ <string name="show_silently" msgid="6841966539811264192">"무음으로 알림 표시"</string>
+ <string name="block" msgid="2734508760962682611">"모든 알림 차단"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"무음 모드 사용 안함"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"무음 모드 또는 차단 사용 안함"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"전체 중요도 설정 표시"</string>
<string name="blocked_importance" msgid="5198578988978234161">"차단됨"</string>
+ <string name="min_importance" msgid="1901894910809414782">"중요도 최소"</string>
<string name="low_importance" msgid="4109929986107147930">"중요도 낮음"</string>
<string name="default_importance" msgid="8192107689995742653">"중요도 보통"</string>
<string name="high_importance" msgid="1527066195614050263">"중요도 높음"</string>
<string name="max_importance" msgid="5089005872719563894">"중요도 긴급"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"알림 다시 표시 안함"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"알림 목록 하단에 무음으로 표시"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"무음으로 알림 표시"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"알림 목록 상단에 표시하고 소리로 알림"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"화면에 표시하고 소리로 알림"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"알림 목록 맨 아래에 무음으로 표시"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"무음으로 알림 표시"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"알림을 소리로 알리도록 허용"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"화면에 표시하고 소리로 알림"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"알림 목록 맨 위에 표시, 화면에 표시하고 소리로 알림"</string>
<string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
<string name="notification_done" msgid="5279426047273930175">"완료"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"일반 색상"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"야간 색상"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"맞춤 색상"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"자동"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"알 수 없는 색상"</string>
- <string name="color_transform" msgid="6985460408079086090">"색상 수정"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"빠른 설정 타일 표시"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"맞춤 변환 사용"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"색상 및 모양"</string>
+ <string name="night_mode" msgid="3540405868248625488">"야간 모드"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"디스플레이 보정"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"사용"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"사용 안함"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"자동으로 사용 설정"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"위치 및 시간대에 맞게 야간 모드로 전환"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"야간 모드 사용 중일 때"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS용 어두운 테마 사용"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"농담 효과 조정"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"밝기 조정"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"설정 등 밝은 테마에서 일반적으로 표시되는 Android OS의 핵심 영역에 어두운 테마가 적용됩니다."</string>
<string name="color_apply" msgid="9212602012641034283">"적용"</string>
<string name="color_revert_title" msgid="4746666545480534663">"설정 확인"</string>
<string name="color_revert_message" msgid="9116001069397996691">"일부 색상 설정으로 인해 이 기기를 사용하지 못할 수 있습니다. 확인을 클릭하여 이러한 색상 설정을 확인하지 않으면 10초 후에 설정이 초기화됩니다."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"배터리(<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"성능 및 백그라운드 데이터를 줄입니다."</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"홈"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"최근"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"뒤로"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"볼륨에 알림 일시중지 표시"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"볼륨 대화상자에서 알림 일시중지에 대한 전체 컨트롤을 허용합니다."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"볼륨 및 알림 일시중지"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"볼륨 작게 시 알림 일시중지 사용"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"볼륨 컨트롤과 함께 표시"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"알림 일시중지"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"볼륨 버튼 단축키"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"볼륨 크게 시 알림 일시중지 종료"</string>
<string name="battery" msgid="7498329822413202973">"배터리"</string>
<string name="clock" msgid="7416090374234785905">"시계"</string>
<string name="headset" msgid="4534219457597457353">"헤드셋"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"헤드폰 연결됨"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"헤드셋 연결됨"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"아이콘이 상태 표시줄에 표시되도록 사용 설정 또는 중지합니다."</string>
<string name="data_saver" msgid="5037565123367048522">"데이터 세이버"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"데이터 세이버 사용"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"데이터 세이버 사용 안함"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"키보드 버튼 선택"</string>
<string name="preview" msgid="9077832302472282938">"미리보기"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"드래그하여 타일 추가"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"수정"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"시간"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"시간, 분, 초 표시"</item>
+ <item msgid="1427801730816895300">"시간, 분 표시(기본값)"</item>
+ <item msgid="3830170141562534721">"이 아이콘 표시 안함"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"항상 퍼센트 표시"</item>
+ <item msgid="2139628951880142927">"충전할 때 퍼센트 표시(기본값)"</item>
+ <item msgid="3327323682209964956">"이 아이콘 표시 안함"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"기타"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"화면 분할기"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"아래로 이동"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"위로 이동"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"왼쪽으로 이동"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"오른쪽으로 이동"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 29efca3c004f..d5ac252389f7 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот тартылды."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Тийип, скриншотту көрүңүз."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот кылынбай жатат."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Сактагыч орду чектелүү болгондуктан скриншот тарта албайт, же буга колдонмо же ишканаңыз тарабынан уруксат жок."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Эстутумда бош орун чектелүү болгондуктан скриншот сакталбай жатат."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Скриншот тартууга колдонмо же ишканаңыз уруксат бербейт."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB менен файл өткөрүү мүмкүнчүлүктөрү"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойноткуч катары кошуу (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Камера катары кошуу (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбүрөөк убакыт."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азыраак убакыт."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Колчырак өчүк."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Колчырак күйүк."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Колчырак өчүрүлдү."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Колчырак күйгүзүлдү."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экран кадоо"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> коопсуз режиминде өчүрүлдү."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Таржымал"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалоо"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмо мульти-терезени колдоого албайт"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмо мульти-терезени колдоого албайт"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Тым-\nтырс"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Бардыгы"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Бардык\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Тез кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Жай кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Өйдө серпип экранды бөлүүчү ылдамдаткычты иштетүү"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Өйдө серпип экранды бөлүү жаңсоосун иштетүү"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Сереп баскычынан өйдө серпип, экранды бөлүү режимин киргизүү үчүн жаңсоону иштетиңиз"</string>
<string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Күйгүзүү"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> эскертмелерине колдонулсун"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Ушул колдонмодон алынган бардык эскертмелерге колдонулсун"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Бөгөттөлгөн"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Маанилүүлүгү төмөн"</string>
<string name="default_importance" msgid="8192107689995742653">"Маанилүүлүгү орточо"</string>
<string name="high_importance" msgid="1527066195614050263">"Маанилүүлүгү жогору"</string>
<string name="max_importance" msgid="5089005872719563894">"Маанилүүлүгү шашылыш"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Эскертмелер тизмесинин эң ылдыйында үнсүз көрсөтүлсүн"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Үн менен коштолуп, экранга чыгарылсын"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
<string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Кадимки түстөр"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Түнкү түстөр"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Ыңгайлаштырылган түстөр"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Белгисиз түстөр"</string>
- <string name="color_transform" msgid="6985460408079086090">"Түсүн өзгөртүү"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ыкчам жөндөөлөр тактасын көрсөтүү"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Ыңгайлаштырылган өзгөртүүнү иштетүү"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Түсү жана көрүнүшү"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Түнкү режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Дисплейди калибрлөө"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Күйүк"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Өчүк"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматтык түрдө күйгүзүү"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Жайгашкан жерге жана убакытка жараша түнкү режимге которулуңуз"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Түнкү режим күйүп турганда"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS үчүн караңгы тема колдонуу"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Кошумча түсүн тууралоо"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Жарыктыгын тууралоо"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Адатта жарык темада көрсөтүлгөн Android OS\'тин, Жөндөөлөр сыяктуу негизги аймактарына караңгы тема колдонулат."</string>
<string name="color_apply" msgid="9212602012641034283">"Колдонуу"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Батарея (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Башкы бет"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Акыркылар"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Артка"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"\"Тынчымды алба\" режимин үн көзөмөлдөгүчүндө көрсөтүү"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Үндү катуулатып/акырындатуу диалогунда \"Тынчымды алба\" режимин толук көзөмөлдөөгө уруксат берүү."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Үн көзөмөлдөгүчү жана \"Тынчымды алба\" режими"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Үн акырындатылганда \"Тынчымды алба\" режимине кирүү"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Үн көзөмөлдөгүчтөрү менен көрсөтүлсүн"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Тынчымды алба"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Үндү көзөмөлдөөчү баскычтардын кыска жолдору"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Үн катуулатылганда \"Тынчымды алба\" режиминен чыгуу"</string>
<string name="battery" msgid="7498329822413202973">"Батарея"</string>
<string name="clock" msgid="7416090374234785905">"Саат"</string>
<string name="headset" msgid="4534219457597457353">"Гарнитура"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Гарнитуралар туташкан"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнитура туташты"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Абал тилкесиндеги сүрөтчөнү иштетүү же өчүрүү."</string>
<string name="data_saver" msgid="5037565123367048522">"Дайындарды үнөмдөгүч"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Дайындарды үнөмдөгүч күйүк"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Дайындарды үнөмдөгүч өчүрүлгөн"</string>
<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>
@@ -520,5 +543,24 @@
<string name="keycode_description" msgid="1403795192716828949">"Бул баскычтын жардамы менен баскычтоптогу баскычтарды чабыттоо тилкесине кошууга болот. Ал үчүн баскычты жана тийиштүү баскычтын көрүнүшүн тандаңыз."</string>
<string name="select_keycode" msgid="7413765103381924584">"Баскычтоптогу баскычты тандоо"</string>
<string name="preview" msgid="9077832302472282938">"Алдын ала көрүү"</string>
- <string name="drag_to_add_tiles" msgid="7058945779098711293">"Тайлдарды кошуу үчүн сүйрөңүз"</string>
+ <string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Убакыт"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Сааттар, мүнөттөр жана секунддар көрсөтүлсүн"</item>
+ <item msgid="1427801730816895300">"Сааттар жана мүнөттөр көрсөтүлсүн (демейки)"</item>
+ <item msgid="3830170141562534721">"Бул сөлөкөт көрсөтүлбөсүн"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Ар дайым пайызы көрсөтүлсүн"</item>
+ <item msgid="2139628951880142927">"Кубаттоо учурунда пайызы көрсөтүлсүн (демейки)"</item>
+ <item msgid="3327323682209964956">"Бул сөлөкөт көрсөтүлбөсүн"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Экранды бөлгүч"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмөн жылдыруу"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солго жылдыруу"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңго жылдыруу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 564adffe2456..8000621f7cd3 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ຖ່າຍຮູບໜ້າຈໍແລ້ວ"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"ແຕະເພື່ອເບິ່ງພາບໜ້າຈໍຂອງທ່ານ."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"ບໍ່​ສາມາດ​ຖ່າຍ​ຮູບ​ໜ້າ​ຈໍ​ໄດ້​ເນື່ອງ​ຈາກ​ບ່ອນ​ຈັດ​ເກັບ​ຂໍ້ມູນ​ທີ່​ຈຳກັດ ຫຼື​ແອັບຯ ຫຼື​ອົງກອນ​ຂອງ​ທ່ານ​ບໍ່​ອະນຸຍາດ​ໃຫ້​ເຮັດ​ໄດ້."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້ເນື່ອງຈາກພື້ນທີ່ຈັດເກັບຂໍ້ມູນມີຈຳກັດ."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ມີການຖ່າຍຮູບໜ້າຈໍ."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ໂຕເລືອກການຍ້າຍໄຟລ໌"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ເຊື່ອມຕໍ່ເປັນ media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ເຊື່ອມຕໍ່ເປັນກ້ອງຖ່າຍຮູບ (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"​ເພີ່ມ​ເວ​ລາ."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ຫຼຸດ​ເວ​ລາ."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ໄຟ​ສາຍ​ປິດ."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ບໍ່ສາມາດໃຊ້ໄຟສາຍໄດ້"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ໄຟ​ສາຍ​ເປີດ."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ປິດ​ໄຟ​ສາຍ​ແລ້ວ."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"​ເປີດ​ໄຟ​ສາຍ​ແລ້ວ."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່​ສາ​ມາດ​ເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ຖືກປິດໃຊ້ໃນໂໝດຄວາມມປອດໄພ."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ປະຫວັດ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ລຶບ"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ແອັບນີ້ບໍ່ຮອງຮັບຫຼາຍໜ້າຈໍ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ແອັບບໍ່ຮອງຮັບຫຼາຍໜ້າຈໍ"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"ຄວາມ​ງຽບ\nທັງ​ໝົດ"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ທັງໝົດ"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ທັງໝົດ\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
<string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ເປີດໃຊ້ຕົວເລັ່ງຄວາມໄວການປັດຂຶ້ນຂອງໜ້າຈໍແບບແຍກກັນ"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບລວມ"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ເປີດໃຊ້ທ່າທາງການປັດຂຶ້ນເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບຮວມ"</string>
<string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດ​ໃຊ້ Bluetooth ບໍ່?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອ​ເຊື່ອມ​ຕໍ່​ແປ້ນ​ພິມ​ຂອງ​ທ່ານ​ກັບ​ແທັບ​ເລັດ​ຂອງ​ທ່ານ, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ເປີດ Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ເປີດ​"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"ນຳໃຊ້ກັບການແຈ້ງເຕືອນ <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ນຳໃຊ້ກັບທຸກການແຈ້ງເຕືອນຈາກແອັບນີ້"</string>
+ <string name="show_silently" msgid="6841966539811264192">"ສະແດງການແຈ້ງເຕືອນແບບບໍ່ມີສຽງ"</string>
+ <string name="block" msgid="2734508760962682611">"ບລັອກການແຈ້ງເຕືອນທັງໝົດ"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ຢ່າງຽບ"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ຢ່າງຽບ ຫຼື ບລັອກ"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ສະແດງການຕັ້ງຄ່າຄວາມສຳຄັນແບບເຕັມ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"ບລັອກໄວ້​ແລ້ວ"</string>
+ <string name="min_importance" msgid="1901894910809414782">"ຄວາມສຳຄັນໜ້ອຍສຸດ"</string>
<string name="low_importance" msgid="4109929986107147930">"ຄວາມ​ສໍາ​ຄັນ​ຕໍ່າ"</string>
<string name="default_importance" msgid="8192107689995742653">"ຄວາມສຳຄັນປົກກະຕິ"</string>
<string name="high_importance" msgid="1527066195614050263">"ຄວາມ​ສໍາ​ຄັນ​ສູງ"</string>
<string name="max_importance" msgid="5089005872719563894">"ຄວາມ​ສໍາ​ຄັນ​ຮີບ​ດ່ວນ"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ຢ່າ​ສະ​ແດງ​ການ​ແຈ້ງ​ເຕືອນ​ເຫຼົ່າ​ນີ້"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"ສະແດງຢູ່ສ່ວນລຸ່ມຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"ສະແດງຢູ່ສ່ວນເທິງຂອງລາຍການແຈ້ງເຕືອນ ແລະສົ່ງສຽງດັງ"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"ເດັ້ງຂຶ້ນເທິງຫນ້າຈໍ ແລະສົ່ງສຽງດັງ"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ອະນຸຍາດໃຫ້ການແຈ້ງເຕືອນເຫຼົ່ານີ້ໃຊ້ສຽງໄດ້"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"ແຈ້ງໄປໜ້າຈໍ ແລະ ອະນຸຍາດໃຫ້ໃຊ້ສຽງໄດ້"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ, ແຈ້ງໄປໜ້າຈໍ ແລະ ອະນຸຍາດໃຫ້ໃຊ້ສຽງໄດ້"</string>
<string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
<string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ສີ​ປົກ​ກະ​ຕິ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ສີ​ຕອນ​ກາງ​ຄືນ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ສີແບບກຳນົດເອງ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ອັດຕະໂນມັດ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"ສີທີ່ບໍ່ຮູ້ຈັກ"</string>
- <string name="color_transform" msgid="6985460408079086090">"ການ​ດັດ​ແປງສີ"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"ສະແດງໄທລ໌ການຕັ້ງຄ່າດ່ວນ"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"ເປີດໃຊ້ການປ່ຽນສີແບບກຳນົດເອງ"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"ສີ ແລະ ລັກສະນະ"</string>
+ <string name="night_mode" msgid="3540405868248625488">"ໂໝດກາງຄືນ"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ປັບໜ້າຈໍ"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ເປີດ"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ປິດ"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"ເປີດ​ໃຊ້​ອັດ​ຕະ​ໂນ​ມັດ"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ສະລັບໄປໃຊ້ໂໝດກາງຄືນຕາມຄວາມເໝາະສົມກັບສະຖານທີ່ ແລະ ເວລາໃນແຕ່ລະມື້"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"ເມື່ອເປີດໂໝດກາງຄືນ"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"ໃຊ້ຮູບແບບສີສັນແບບມືດສຳລັບ Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ປັບແຕ່ງໂທນສີ"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ປັບແຕ່ງຄວາມສະຫວ່າງ"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ຮູບແບບສີສັນມືດແມ່ນນຳໃຊ້ກັບພື້ນທີ່ຫຼັກຂອງ Android OS ທີ່ປົກກະຕິຈະສະແດງເປັນຮູບແບບສີສັນແຈ້ງ ເຊັ່ນ: ການຕັ້ງຄ່າ."</string>
<string name="color_apply" msgid="9212602012641034283">"ນຳໃຊ້"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ຢືນ​ຢັນ​ການ​ຕັ້ງ​ຄ່າ"</string>
<string name="color_revert_message" msgid="9116001069397996691">"ບາງການຕັ້ງຄ່າສີສາມາດເຮັດໃຫ້ອຸປະກອນນີ້ບໍ່ສາມາດໃຊ້ໄດ້. ຄລິກ ຕົກລົງ ເພື່ອຢືນຢັນການຕັ້ງຄ່າສີເຫຼົ່ານີ້, ຖ້າບໍ່ດັ່ງນັ້ນ ການຕັ້ງຄ່າເຫຼົ່ານີ້ຈະຕັ້ງຄືນໃໝ່ ຫຼັງຈາກ 10 ວິນາທີ."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ແບັດເຕີຣີ (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ຫຼຸດ​ປະ​ສິ​ທິ​ພາບ​ການໃຊ້ງານ ແລະ ​ຂໍ້​ມູນ​ພື້ນຫຼັງ"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"​ໜ້າຫຼັກ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ຫາ​ກໍ​ໃຊ້"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ກັບຄືນ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"ສະແດງ ຫ້າມລົບກວນ ໃນລະດັບສຽງ"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ອະນຸຍາດການຄວບຄຸມເຕັມສ່ວນຂອງ ຫ້າມລົບກວນ ໃນກ່ອງປັບລະດັບສຽງ."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ລະດັບສຽງ ແລະ ຫ້າມລົບກວນ"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ເປີດໃຊ້ໂໝດ ຫ້າມລົບກວນ ເມື່ອປັບສຽງໃຫ້ຄ່ອຍລົງ"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ສະແດງສ່ວນຄວບຄຸມສຽງ"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ຫ້າມ​ລົບ​ກວນ"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ທາງລັດປຸ່ມສຽງ"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ອອກຈາກໂໝດ ຫ້າມລົບກວນ ເມື່ອປັບສຽງໃຫ້ດັງຂຶ້ນ"</string>
<string name="battery" msgid="7498329822413202973">"ແບັດເຕີຣີ"</string>
<string name="clock" msgid="7416090374234785905">"ໂມງ"</string>
<string name="headset" msgid="4534219457597457353">"​ຊຸດ​ຫູ​ຟັງ"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ເຊື່ອມຕໍ່ຊຸດຫູຟັງແລ້ວ"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ເຊື່ອມ​ຕໍ່ຊຸດ​ຫູ​ຟັງແລ້ວ"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ເປີດ ຫຼື ປິດໄອຄອນຕ່າງໆຈາກການສະແດງໃນແຖບສະຖານະ."</string>
<string name="data_saver" msgid="5037565123367048522">"ຕົວປະຢັດຂໍ້ມູນ"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ຕົວປະຢັດຂໍ້ມູນເປີດຢູ່"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ຕົວປະຢັດຂໍ້ມູນປິດຢູ່"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"ເລືອກປຸ່ມແປ້ນພິມ"</string>
<string name="preview" msgid="9077832302472282938">"ສະແດງຕົວຢ່າງ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ລາກເພື່ອເພີ່ມໄທລ໌"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"ແກ້ໄຂ"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"ເວລາ"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ສະແດງຊົ່ວໂມງ, ນາທີ ແລະ ວິນາທີ"</item>
+ <item msgid="1427801730816895300">"ສະແດງຊົ່ວໂມງ ແລະ ນາທີ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+ <item msgid="3830170141562534721">"ຢ່າສະແດງໄອຄອນນີ້"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ສະແດງເປີເຊັນຕະຫຼອດເວລາ"</item>
+ <item msgid="2139628951880142927">"ສະແດງເປີເຊັນເມື່ອກຳລັງສາກໄຟ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+ <item msgid="3327323682209964956">"ຢ່າສະແດງໄອຄອນນີ້"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"ອື່ນໆ"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ເລື່ອນລົງ"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ເລື່ອນຂຶ້ນ"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ເລື່ອນຊ້າຍ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ເລື່ອນຂວາ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 085bfdd1bd5d..a33c76f2a1e0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrano kopija užfiksuota."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Palieskite, kad peržiūrėtumėte ekrano kopiją."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Neg. daryti ekr. kopijų dėl ribotos saugyklos vietos arba to atlikti neleidžia progr. ar organiz."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Negalima išsaugoti ekrano kopijos dėl ribotos saugyklos vietos."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Jūsų organizacijoje arba naudojant šią programą neleidžiama daryti ekrano kopijų"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB failo perdavimo parinktys"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos leistuvę (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daugiau laiko."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mažiau laiko."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Blykstė išjungta."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Blykstė įjungta."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Blykstė išjungta."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Blykstė įjungta."</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekrano prisegimas"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Programa „<xliff:g id="APP">%s</xliff:g>“ išjungta saugos režimu."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Istorija"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Išvalyti"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ši programa nepalaiko kelių langų režimo"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Programa nepalaiko kelių langų režimo"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Visiška\ntyla"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tik\nprioritetiniai"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tik\nsignalai"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Visi"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Visi\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Greitai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lėtai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
<string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Įgalinti skaidyto ekrano perbrauk. aukštyn spartinimo įrankį"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Įgalinti ekrano skaidymo perbraukimo aukštyn gestą"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Įgalinti gestą, kuriuo galima įjungti skaidytą ekraną, perbraukiant aukštyn nuo apžvalgos mygtuko"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Įjungti"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Taikyti „<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“ pranešimams"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Taikyti visiems pranešimams iš šios programos"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Užblokuota"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Maža svarba"</string>
<string name="default_importance" msgid="8192107689995742653">"Įprasta svarba"</string>
<string name="high_importance" msgid="1527066195614050263">"Didelė svarba"</string>
<string name="max_importance" msgid="5089005872719563894">"Skubi svarba"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Niekada nerodyti šių pranešimų"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Tyliai rodyti pranešimų sąrašo apačioje"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Tyliai rodyti šiuos pranešimus"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Rodyti pranešimų sąrašo viršuje ir skambėti"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Rodyti ekrane ir skambėti"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
<string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Įprastos spalvos"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nakties spalvos"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Tinkintos spalvos"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatinis"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Nežinomos spalvos"</string>
- <string name="color_transform" msgid="6985460408079086090">"Spalvų keitimas"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Rodyti Sparčiųjų nustatymų išklotinės elementą"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Įgalinti tinkintą transformavimą"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Spalva ir išvaizda"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Naktinis režimas"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibruoti ekraną"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Įjungta"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Išjungta"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Įjungti automatiškai"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Perjungti į naktinį režimą pagal vietovę ir dienos laiką"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kai įjungtas naktinis režimas"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Naudoti tamsią „Android“ OS temą"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Koreguoti atspalvį"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Koreguoti šviesumą"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Pagrindinėms „Android“ OS dalims, kurioms paprastai taikoma šviesi tema, pvz., skilčiai „Nustatymai“, bus pritaikyta tamsi tema."</string>
<string name="color_apply" msgid="9212602012641034283">"Taikyti"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Nustatymų patvirtinimas"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Dėl kai kurių spalvų nustatymų įrenginys gali būti netinkamas naudoti. Spustelėkite „Gerai“, kad patvirtintumėte šiuos spalvų nustatymus. Kitaip šie nustatymai bus nustatyti iš naujo po 10 sekundžių."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Akumuliatorius (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Pagrindinis ekranas"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Naujausios veiklos ekranas"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atgal"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Rodyti netrukdymo režimą garsumo dialogo lange"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Leisti visiškai valdyti netrukdymo režimą garsumo dialogo lange."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Garsumas ir netrukdymo režimas"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Įjungti netrukdymo režimą mažinant garsumą"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Rodyti su garsumo valdikliais"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netrukdymo režimas"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Garsumo mygtukų spartusis klavišas"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Išjungti netrukdymo režimą didinant garsumą"</string>
<string name="battery" msgid="7498329822413202973">"Akumuliatorius"</string>
<string name="clock" msgid="7416090374234785905">"Laikrodis"</string>
<string name="headset" msgid="4534219457597457353">"Ausinės"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Ausinės prijungtos"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Ausinės prijungtos"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Įgalinti arba išjungti piktogramų rodymą būsenos juostoje."</string>
<string name="data_saver" msgid="5037565123367048522">"Duomenų taupymo priemonė"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Duomenų taupymo priemonė įjungta"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Duomenų taupymo priemonė išjungta"</string>
<string name="switch_bar_on" msgid="1142437840752794229">"Įjungti"</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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatūros mygtuko pasirinkimas"</string>
<string name="preview" msgid="9077832302472282938">"Peržiūrėti"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Nuvilkite, kad pridėtumėte išklotinės elementų"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Redaguoti"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Laikas"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Rodyti valandas, minutes ir sekundes"</item>
+ <item msgid="1427801730816895300">"Rodyti valandas ir minutes (numatytasis nustatymas)"</item>
+ <item msgid="3830170141562534721">"Nerodyti šios piktogramos"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Visada rodyti procentus"</item>
+ <item msgid="2139628951880142927">"Rodyti procentus kraunant (numatytasis nustatymas)"</item>
+ <item msgid="3327323682209964956">"Nerodyti šios piktogramos"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Skaidyto ekrano daliklis"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Perkelti žemyn"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Perkelti aukštyn"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Perkelti kairėn"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Perkelti dešinėn"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2420b1ac8d76..683e00a03eb6 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -74,7 +74,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrānuzņēmums ir uzņemts."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Pieskarieties, lai skatītu ekrānuzņēmumu."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nevarēja uzņemt ekrānuzņēmumu."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Nevar veikt ekrānuzņēmumu (krātuvē nepietiek vietas, vai to neļauj lietotne vai jūsu organizācija)."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nevar saglabāt ekrānuzņēmumu, jo krātuvē nepietiek vietas."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB failu pārsūtīšanas opcijas"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Pievienot kā multivides atskaņotāju (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Pievienot kā kameru (PTP)"</string>
@@ -207,6 +208,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Vairāk laika."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mazāk laika."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Apgaismojums ir izslēgts."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Apgaismojums ir ieslēgts."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Apgaismojums ir izslēgts."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Apgaismojums ir ieslēgts."</string>
@@ -302,8 +305,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Piespraust ekrānu"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Lietotne <xliff:g id="APP">%s</xliff:g> ir atspējota drošajā režīmā."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Vēsture"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Notīrīt"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Šajā lietotnē netiek atbalstīts vairāku logu režīms."</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Lietotnē netiek atbalstīts vairāku logu režīms"</string>
<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>
@@ -333,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Pilnīgs\nklusums"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tikai\nprioritārie"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tikai\nsignāli"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Visi"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Visi\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ātra uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lēna uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
@@ -447,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
<string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Iespējot ekrāna sadalīšanu, izmantojot vilkšanu augšup"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Iespējot vilkšanu augšup, lai sadalītu ekrānu"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Iespējot žestu ekrāna sadalīšanai, velkot augšup no pogas Pārskats"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ieslēgt"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Lietot paziņojumiem “<xliff:g id="TOPIC_NAME">%1$s</xliff:g>”"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Lietot visiem šīs lietotnes paziņojumiem"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloķēts"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Nav svarīgs"</string>
<string name="default_importance" msgid="8192107689995742653">"Parasts"</string>
<string name="high_importance" msgid="1527066195614050263">"Ļoti svarīgs"</string>
<string name="max_importance" msgid="5089005872719563894">"Steidzams"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nekad nerādīt šos paziņojumus"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Rādīt šos paziņojumus bez skaņas signāla"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Rādīt paziņojumu saraksta augšdaļā un ar skaņas signālu"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Rādīt ekrānā ar skaņas signālu"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
<string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Parastas krāsas"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nakts krāsas"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Pielāgotas krāsas"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automātiski"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Nezināmas krāsas"</string>
- <string name="color_transform" msgid="6985460408079086090">"Krāsu pārveidošana"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ātro iestatījumu elementa rādīšana"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Pielāgotās pārveidošanas iespējošana"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Krāsas un izskats"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nakts režīms"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Ekrāna kalibrēšana"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Ieslēgts"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Izslēgts"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Ieslēgt automātiski"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Pārslēgt uz nakts režīmu atbilstoši atrašanās vietai un diennakts laikam"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Ja ir ieslēgts nakts režīms"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Izmantot tumšo motīvu operētājsistēmai Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Regulēt toni"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Regulēt spilgtumu"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tumšais motīvs tiek lietots galvenajos operētājsistēmas Android elementos, kas parasti tiek rādīti ar gaišu motīvu, piemēram, lietotnē Iestatījumi."</string>
<string name="color_apply" msgid="9212602012641034283">"Lietot"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Iestatījumu apstiprināšana"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Noteiktu krāsu iestatījumu dēļ šī ierīce var kļūt nelietojama. Lai apstiprinātu šos krāsu iestatījumus, noklikšķiniet uz Labi. Ja to neizdarīsiet, pēc 10 sekundēm šie iestatījumi tiks atiestatīti."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Akumulators (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Samazina veiktspēju un fona datus."</string>
@@ -486,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Sākums"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Pēdējie"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Atpakaļ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Rādīt režīmu “Netraucēt” skaļuma regulēšanas dialoglodziņā"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Atļaujiet pilnu režīma “Netraucēt” kontroli skaļuma regulēšanas dialoglodziņā."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Skaļums un režīms “Netraucēt”"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Ieslēgt režīmu “Netraucēt”, samazinot skaļumu"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Rādīt ar skaļuma vadīklām"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Netraucēt"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Skaļuma pogu saīsne"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Izslēgt režīmu “Netraucēt”, palielinot skaļumu"</string>
<string name="battery" msgid="7498329822413202973">"Akumulators"</string>
<string name="clock" msgid="7416090374234785905">"Pulkstenis"</string>
<string name="headset" msgid="4534219457597457353">"Austiņas"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Austiņas ir pievienotas"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Austiņas ar mikrofonu ir pievienotas"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Iespējojiet vai atspējojiet ikonu rādīšanu statusa joslā."</string>
<string name="data_saver" msgid="5037565123367048522">"Datu lietojuma samazinātājs"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datu lietojuma samazinātājs ieslēgts"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datu lietojuma samazinātājs ir izslēgts."</string>
<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>
@@ -522,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Tastatūras pogas atlase"</string>
<string name="preview" msgid="9077832302472282938">"Priekšskatījums"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Velciet elementus, lai tos pievienotu"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Rediģēt"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Laiks"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Rādīt stundas, minūtes un sekundes"</item>
+ <item msgid="1427801730816895300">"Rādīt stundas un minūtes (noklusējums)"</item>
+ <item msgid="3830170141562534721">"Nerādīt šo ikonu"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Vienmēr rādīt procentuālo vērtību"</item>
+ <item msgid="2139628951880142927">"Rādīt procentuālo vērtību uzlādes laikā (noklusējums)"</item>
+ <item msgid="3327323682209964956">"Nerādīt šo ikonu"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Ekrāna sadalītājs"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pārvietot uz leju"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pārvietot uz augšu"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pārvietot pa kreisi"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pārvietot pa labi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 276ae6bc4f6c..58b7b751736e 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Сликата на екранот е снимена."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Допрете за да ја видите сликата на екранот."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Сликата на екранот не можеше да се сними."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Не може да направи слика на екран поради огран. простор или не дозволува аплика. или организацијата."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Сликата од екранот не може да се зачува поради ограничена меморија."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Апликацијата или вашата организација не дозволува создавање слики од екранот."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Пренос на датотека со УСБ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Монтирај како мултимедијален плеер (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Монтирај како фотоапарат (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повеќе време."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Помалку време."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Блицот е исклучен."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Светилката е недостапна."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Блицот е вклучен."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Блицот е исклучен."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Блицот е вклучен."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"прикачување екран"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> е оневозможен во безбеден режим."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Историја"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Исчисти"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Апликацијава не поддржува повеќе прозорци"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апликацијата не поддржува повеќе прозорци"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Целосна\nтишина"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприоритетни"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Сѐ"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Сите\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Бавно полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
<string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Овозможете забрзувач за повлекување нагоре поделен екран"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Овозможи го гестот повлекување нагоре за поделен екран"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Овозможете гест за отворање поделен екран со повлекување нагоре од копчето Краток преглед"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Вклучи"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Важи за известувањата за <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Важи за сите известувања од оваа апликација"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Тивко прикажувај ги известувањата"</string>
+ <string name="block" msgid="2734508760962682611">"Блокирај ги сите известувања"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Не стишувај"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Не стишувај или блокирај"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Прикажи ги поставките со целосна важност"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Минимална важност"</string>
<string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
<string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
<string name="high_importance" msgid="1527066195614050263">"Голема важност"</string>
<string name="max_importance" msgid="5089005872719563894">"Итна важност"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Никогаш не ги прикажувај известувањава"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Тивко прикажувај ги на дното на списокот со известувања"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Тивко прикажувај ги известувањава"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Прикажувај ги на врвот на списокот со известувања и дај звучен сигнал"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Појави се на екранот и дај звучен сигнал"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Тивко прикажувај ги на дното на списокот со известувања"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Тивко прикажувај ги известувањава"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Овозможи им на известувањава да прават звуци"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Ѕиркање на екранот и овозможен звук и овозможен звук"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Прикажувај ги на врвот на списокот со известувања, ѕиркање на екранот и овозможи звук"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Нормални бои"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Ноќни бои"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Приспособени бои"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Автоматски"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Непознати бои"</string>
- <string name="color_transform" msgid="6985460408079086090">"Промена на бојата"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Прикажи плочка Брзи поставки"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Овозможи приспособено трансформирање"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Ноќен режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Калибрирај го екранот"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Вклучено"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Исклучено"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Вклучи автоматски"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Префрли во Ноќен режим како што е соодветно за локацијата и времето во денот"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Кога Ноќниот режим е вклучен"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Користете ја темната тема за ОС Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Приспособи ја бојата"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Приспособи ја осветленоста"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Темната тема се применува на основните области на Android OS што обично се прикажуваат во светла тема, како Поставки."</string>
<string name="color_apply" msgid="9212602012641034283">"Примени"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Потврдете ги поставките"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Некои поставки на боите може да го направат уредот неупотреблив. Кликнете на Во ред за да ги потврдите овие поставки на боите, инаку тие поставки ќе се ресетираат по 10 секунди."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Батерија (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ја намалува изведбата и податоците во заднина"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетна страница"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Неодамнешни"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Прикажи „Не вознемирувај“ во јачината на звукот"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дозволете целосна контрола на „Не вознемирувај“ во дијалогот за јачина на звукот."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Јачина на звук и „Не вознемирувај“"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Премини во „Не вознемирувај“ при намалена јачина на звукот"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи со контроли за јачина на звук"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не вознемирувај"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Кратенка за копчињата за јачина на звук"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Излези од „Не вознемирувај“ при зголемена јачина на звукот"</string>
<string name="battery" msgid="7498329822413202973">"Батерија"</string>
<string name="clock" msgid="7416090374234785905">"Часовник"</string>
<string name="headset" msgid="4534219457597457353">"Слушалки"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Слушалките се поврзани"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Слушалките се поврзани"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Овозможете или оневозможете прикажување на иконите во статусната лента."</string>
<string name="data_saver" msgid="5037565123367048522">"Штедач на интернет"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Штедачот на интернет е вклучен"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Штедачот на интернет е исклучен"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Изберете копче за тастатура"</string>
<string name="preview" msgid="9077832302472282938">"Преглед"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Повлечете за додавање плочки"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Уреди"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Време"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Прикажи часови, минути и секунди"</item>
+ <item msgid="1427801730816895300">"Прикажи часови и минути (стандардно)"</item>
+ <item msgid="3830170141562534721">"Не прикажувај ја иконава"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Секогаш прикажувај процент"</item>
+ <item msgid="2139628951880142927">"Прикажи процент кога се полни (стандардно)"</item>
+ <item msgid="3327323682209964956">"Не прикажувај ја иконава"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Друго"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Разделник на поделен екран"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Преместете надолу"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместете нагоре"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместете налево"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместете надесно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index af2576a2854d..6627645f8503 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"സ്‌ക്രീൻഷോട്ട് എടുത്തു."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"നിങ്ങളുടെ സ്‌ക്രീൻഷോട്ട് കാണാനായി സ്‌പർശിക്കുക."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"സ്‌ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"സംഭരണ ഇടം പരിമിതമായതിനാൽ സ്‌ക്രീൻഷോട്ട് എടുക്കാനാകില്ല, അല്ലെങ്കിൽ ഇത് അപ്ലിക്കേഷനോ നിങ്ങളുടെ ഓർഗനൈസേഷനോ അനുവദിക്കുന്നില്ല."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"സ്റ്റോറേജ് ഇടം പരിമിതമായതിനാൽ സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കാൻ കഴിയില്ല."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"സ്ക്രീൻഷോട്ടുകൾ എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ഫയൽ കൈമാറൽ ഓപ്‌ഷനുകൾ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ഒരു മീഡിയ പ്ലേയറായി (MTP) മൗണ്ടുചെയ്യുക"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ഒരു ക്യാമറയായി (PTP) മൗണ്ടുചെയ്യുക"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"കൂടുതൽ സമയം."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"സമയം കുറയ്‌ക്കുക."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ടോർച്ച് ഓഫാണ്."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ടോർച്ച് ലഭ്യമല്ല."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ടോർച്ച് ഓണാണ്."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ടോർച്ച് ഓഫാക്കി."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ടോർച്ച് ഓണാക്കി."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"സ്ക്രീൻ പിൻ ചെയ്യൽ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"സുരക്ഷിത മോഡിൽ <xliff:g id="APP">%s</xliff:g> പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ചരിത്രം"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"മായ്‌ക്കുക"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ഒന്നിലധികം വിൻഡോകളെ ഈ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ഒന്നിലധികം വിൻഡോകളെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"പൂർണ്ണ\nനിശബ്‌ദത"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"മുൻഗണന\nമാത്രം"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"അലാറങ്ങൾ\nമാത്രം"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"എല്ലാം"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"എല്ലാം\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"പതുക്കെ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
<string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ആക്‌സിലറേറ്റർ പ്രവർത്തനക്ഷമമാക്കൂ"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ജെസ്റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ചുരുക്കവിവരണ ബട്ടണിൽ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്തുകൊണ്ട് സ്പ്ലിറ്റ്-സ്ക്രീനിലേക്ക് പ്രവേശിക്കാൻ ജെസ്‌റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്‌ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ഓണാക്കുക"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> അറിയിപ്പുകളിലേക്ക് പ്രയോഗിക്കുക"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ഈ ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളിലേക്കും പ്രയോഗിക്കുക"</string>
+ <string name="show_silently" msgid="6841966539811264192">"അറിയിപ്പുകൾ നിശ്ശബ്ദമായി കാണിക്കുക"</string>
+ <string name="block" msgid="2734508760962682611">"എല്ലാ അറിയിപ്പുകളും ബ്ലോക്കുചെയ്യുക"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"നിശബ്ദമാക്കരുത്"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"നിശബ്ദമാക്കുകയോ ബ്ലോക്കുചെയ്യുകയോ അരുത്"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"പൂർണ്ണ പ്രാധാന്യ ക്രമീകരണം കാണിക്കുക"</string>
<string name="blocked_importance" msgid="5198578988978234161">"ബ്ലോക്കുചെയ്തു"</string>
+ <string name="min_importance" msgid="1901894910809414782">"കുറഞ്ഞ പ്രാധാന്യം"</string>
<string name="low_importance" msgid="4109929986107147930">"താഴ്ന്ന പ്രാധാന്യം"</string>
<string name="default_importance" msgid="8192107689995742653">"സാധാരണ പ്രാധാന്യം"</string>
<string name="high_importance" msgid="1527066195614050263">"ഉയർന്ന പ്രാധാന്യം"</string>
<string name="max_importance" msgid="5089005872719563894">"അടിയന്തര പ്രാധാന്യം"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ഈ അറിയിപ്പുകൾ ഒരിക്കലും കാണിക്കരുത്"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ശബ്ദമുണ്ടാക്കാൻ ഈ അറിയിപ്പുകളെ അനുവദിക്കുക"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
<string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
<string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"സാധാരണ വര്‍ണ്ണങ്ങൾ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"രാത്രി വര്‍ണ്ണങ്ങൾ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ഇഷ്ടാനുസൃത വര്‍ണ്ണങ്ങൾ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"യാന്ത്രികം"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"തിരിച്ചറിയാനാകാത്ത വർണ്ണങ്ങൾ"</string>
- <string name="color_transform" msgid="6985460408079086090">"വർണ്ണ പരിഷ്കരണം"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"ദ്രുത ക്രമീകരണ ടൈൽ കാണിക്കുക"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"ഇഷ്ടാനുസൃത പരിവർത്തനം പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"വർണ്ണവും രൂപഭാവവും"</string>
+ <string name="night_mode" msgid="3540405868248625488">"നൈറ്റ് മോഡ്"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ഡിസ്പ്ലേ കാലിബ്രേറ്റുചെയ്യുക"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ഓൺ"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ഓഫ്"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"സ്വയമേവ ഓണാക്കുക"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ലൊക്കേഷനും ദിവസത്തിലെ സമയത്തിനും അനുയോജ്യമായ തരത്തിൽ നൈറ്റ് മോഡിലേക്ക് സ്വിച്ചുചെയ്യുക"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"നൈറ്റ് മോഡ് ഓണായിരിക്കുമ്പോൾ"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS-നുള്ള ഇരുണ്ട തീം ഉപയോഗിക്കുക"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ടിന്റ് ക്രമപ്പെടുത്തുക"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"തെളിച്ചം ക്രമപ്പെടുത്തുക"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ക്രമീകരണം പോലെയുള്ള, ഒരു ലൈറ്റ് തീമിൽ സാധാരണ ഗതിയിൽ പ്രദർശിപ്പിക്കപ്പെടുന്ന Android OS-ന്റെ അടിസ്ഥാന ഇടങ്ങളിലേക്ക്, ഇരുണ്ട തീം പ്രയോഗിക്കുന്നു."</string>
<string name="color_apply" msgid="9212602012641034283">"ബാധകമാക്കുക"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ക്രമീകരണം സ്ഥിരീകരിക്കുക"</string>
<string name="color_revert_message" msgid="9116001069397996691">"ചില വർണ്ണ ക്രമീകരണത്തിന് ഈ ഉപകരണത്തെ ഉപയോഗരഹിതമാക്കാനാകും. ഈ വർണ്ണ ക്രമീകരണം സ്ഥിരീകരിക്കുന്നതിന് ശരി എന്നതിൽ ക്ലിക്കുചെയ്യുക, അല്ലെങ്കിൽ 10 സെക്കൻഡിന് ശേഷം ഈ ക്രമീകരണം പുനഃക്രമീകരിക്കപ്പെടും."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ബാറ്ററി (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്‌ക്കുന്നു"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"വീട്"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"പുതിയവ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"മടങ്ങുക"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"വോളിയത്തിൽ \'ശല്യപ്പെടുത്തരുത്\' കാണിക്കുക"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"വോളിയം ഡയലോഗിൽ \'ശല്യപ്പെടുത്തരുത്\' എന്നത് പൂർണ്ണമായി നിയന്ത്രിക്കാൻ അനുവദിക്കുക."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"വോളിയവും \'ശല്യപ്പെടുത്തരുത്\' എന്നതും"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"വോളിയം താഴുമ്പോൾ \'ശല്യപ്പെടുത്തരുത്\' പ്രവർത്തിപ്പിക്കുക"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"വോളിയം നിയന്ത്രണങ്ങളോടൊപ്പം കാണിക്കുക"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ശല്യപ്പെടുത്തരുത്"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"വോളിയം ഉയരുമ്പോൾ \'ശല്യപ്പെടുത്തരുത്\' നിർത്തുക"</string>
<string name="battery" msgid="7498329822413202973">"ബാറ്ററി"</string>
<string name="clock" msgid="7416090374234785905">"ക്ലോക്ക്"</string>
<string name="headset" msgid="4534219457597457353">"ഹെഡ്‌സെറ്റ്"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ഹെഡ്ഫോണുകൾ കണക്റ്റുചെയ്തു"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ഹെഡ്‌സെറ്റ് കണക്‌റ്റുചെയ്‌തു"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"സ്റ്റാറ്റസ് ബാറിൽ കാണിക്കുന്നതിൽ നിന്ന് ഐക്കണുകളെ പ്രവർത്തനക്ഷമമാക്കുകയോ പ്രവർത്തനരഹിതമാക്കുകയോ ചെയ്യുക"</string>
<string name="data_saver" msgid="5037565123367048522">"ഡാറ്റ സേവർ"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ഡാറ്റാ സേവർ ഓണാണ്"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ഡാറ്റാ സേവർ ഓഫാണ്"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"കീബോർഡ് ബട്ടൺ തിരഞ്ഞെടുക്കൂ"</string>
<string name="preview" msgid="9077832302472282938">"പ്രിവ്യു നടത്തുക"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ടൈലുകൾ ചേർക്കുന്നതിന് വലിച്ചിടുക"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"സമയം"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"മണിക്കൂറും മിനിറ്റും സെക്കൻഡും കാണിക്കുക"</item>
+ <item msgid="1427801730816895300">"മണിക്കൂറും മിനിറ്റും കാണിക്കുക (ഡിഫോൾട്ട്)"</item>
+ <item msgid="3830170141562534721">"ഈ ഐക്കൺ കാണിക്കരുത്"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"എല്ലായ്പ്പോഴും ശതമാനം കാണിക്കുക"</item>
+ <item msgid="2139628951880142927">"ചാർജ്ജുചെയ്യുമ്പോൾ ശതമാനം കാണിക്കുക (ഡിഫോൾട്ട്)"</item>
+ <item msgid="3327323682209964956">"ഈ ഐക്കൺ കാണിക്കരുത്"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"മറ്റുള്ളവ"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"താഴേക്ക് നീക്കുക"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"മുകളിലേക്ക് നീക്കുക"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ഇടത്തേക്ക് നീക്കുക"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"വലത്തേക്ക് നീക്കുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 2a056fcc45ca..fea38a9ee754 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -71,7 +71,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Дэлгэцийн агшинг авсан."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Дэлгэцийн агшныг харах бол хүрнэ үү."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Дэлгэцийн агшинг авч чадсангүй."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Хадгалах сан хязгаартай эсхүл таны байгууллага буюу апп-с зөвшөөрөөгүй учир дэлгэцийн зургийг авах боломжгүй."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Хадгалах сангийн багтаамж бага байгаа тул дэлгэцийн авсан зургийг хадгалах боломжгүй байна."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Дэлгэцийн зураг авахыг апп эсвэл танай байгууллагаас зөвшөөрөөгүй байна."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB файл шилжүүлэх сонголт"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа тоглуулагч(MTP) болгон залгах"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Камер болгон(PTP) залгах"</string>
@@ -204,6 +205,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Хугацаа нэмэх."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Хугацаа хасах."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Флаш гэрэл унтарсан."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Флаш гэрэл ассан."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Флаш гэрлийг унтраасан."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Флаш гэрлийг асаасан."</string>
@@ -299,8 +302,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"дэлгэц тогтоох"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж чадсангүй."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>-г аюулгүй горимд идэвхгүй болгосон."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Түүх"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Устгах"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Энэ апп олон цонхыг дэмждэггүй"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апп олон цонхыг дэмждэггүй"</string>
<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>
@@ -330,8 +336,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Дуугүй\nболгох"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Зөвхөн\nхамгийн чухлыг"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Зөвхөн\nсэрүүлэг"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Бүгд"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Бүх\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
@@ -444,38 +448,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
<string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Дэлгэц хуваах дээш шудрах хурдасгуурыг идэвхжүүлэх"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Дэлгэц хуваах дээш шудрах дохиог идэвхжүүлэх"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Тойм товчлуурыг дээш шударч, хуваагдсан дэлгэцэд зангаагаар орох тохиргоог идэвхжүүлэх"</string>
<string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Асаах"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> мэдэгдэлд хэрэгжүүлэх"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Энэ апп-н бүх мэдэгдэлд хэрэгжүүлэх"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Блоклосон"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Бага ач холбогдолтой"</string>
<string name="default_importance" msgid="8192107689995742653">"Энгийн ач холбогдолтой"</string>
<string name="high_importance" msgid="1527066195614050263">"Өндөр ач холбогдолтой"</string>
<string name="max_importance" msgid="5089005872719563894">"Яаралтай ач холбогдолтой"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Дэлгэцэнд яаралтайгаар дуутай гаргах"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
<string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Хэвийн өнгө"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Шөнийн өнгө"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Өгөгдмөл өнгө"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Автомат"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Үл мэдэгдэх өнгө"</string>
- <string name="color_transform" msgid="6985460408079086090">"Өнгөний өөрчлөлт"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Түргэн тохиргооны хэсгийг харуулах"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Өгөгдмөл өөрчлөлтийг идэвхжүүлэх"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Өнгө, харагдах байдал"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Шөнийн горим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Дэлгэцийг тохируулах"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Идэвхтэй"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Идэвхгүй"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Автоматаар асаах"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Тухайн өдрийн байршил, цагийн тохиромжтой үед Шөнийн горимд шилжүүлэх"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Шөнийн горим идэвхтэй үед"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android-н үйлдлийн системд бараан загварыг ашиглах"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Өнгөний нягтаршилыг тохируулах"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Гэрэлтүүлгийг тохируулах"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Тохиргоо зэрэг тогтмол цайвар загварт харуулдаг Android үйлдлийн системийн гол хэсгийг бараан загварт харуулна."</string>
<string name="color_apply" msgid="9212602012641034283">"Хэрэгжүүлэх"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Тохиргоог баталгаажуулах"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Зарим өнгөний тохиргоо энэ төхөөрөмжийг ашиглах боломжгүй болгож болзошгүй. OK товчлуурыг дарж эдгээр өнгөний тохиргоог зөвшөөрөхгүй бол энэ тохиргоо нь 10 секундын дараа шинэчлэгдэх болно."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Тэжээл (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Гүйцэтгэл болон дэвсгэрийн датаг багасгадаг"</string>
@@ -483,21 +507,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Нүүр хуудас"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Саяхны"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Буцах"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Бүү саад бол тохиргоог дууны түвшинд харуулах"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Бүү саад бол тохиргооны бүрэн хяналтыг дууны түвшний харилцах цонхонд зөвшөөрнө үү."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Дууны түвшин болон бүү саад бол тохиргоо"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Бүү саад бол тохиргоог оруулахын тулд дууны түвшинг бууруулах"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Түвшний хяналттай харуулах"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Бүү саад бол"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Түвшний товчлуурын товчлол"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Бүү саад бол тохиргооноос гарахын тулд дууны түвшинг нэмэх"</string>
<string name="battery" msgid="7498329822413202973">"Зай"</string>
<string name="clock" msgid="7416090374234785905">"Цаг"</string>
<string name="headset" msgid="4534219457597457353">"Чихэвч"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Чихэвч холбогдсон"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Чихэвч холбогдсон"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Статусын самбарт харагдах дүрс тэмдгийг идэвхжүүлэх эсвэл идэвхгүй болгоно уу."</string>
<string name="data_saver" msgid="5037565123367048522">"Өгөгдөл хамгаалагч"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Өгөгдөл хамгаалагчийг асаасан байна"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Өгөгдөл хамгаалагчийг унтраасан байна"</string>
<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>
@@ -519,4 +542,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Гарын товчлуур сонгох"</string>
<string name="preview" msgid="9077832302472282938">"Урьдчилж харах"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Дөрвөлж нэмэхийн тулд чирнэ үү"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Засах"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Цаг"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Цаг, минут, секундийг харуулах"</item>
+ <item msgid="1427801730816895300">"Цаг, минутыг харуулах (өгөгдмөл)"</item>
+ <item msgid="3830170141562534721">"Энэ дүрс тэмдгийг бүү үзүүл"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Хувийг тогтмол харуулах"</item>
+ <item msgid="2139628951880142927">"Цэнэглэх үед хувийг тогтмол харуулах (өгөгдмөл)"</item>
+ <item msgid="3327323682209964956">"Энэ дүрс тэмдгийг бүү үзүүл"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"\"Дэлгэц хуваах\" хуваагч"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Доош зөөх"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Дээш зөөх"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Зүүн тийш зөөх"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Баруун тийш зөөх"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 4009cc3d84d4..acd9d4e833c9 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रीनशॉट कॅप्चर केला."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"आपला स्क्रीनशॉट पाहण्यासाठी स्पर्श करा."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रीनशॉट कॅप्चर करू शकलो नाही."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"मर्यादित संचयन स्‍थानामुळे किंवा अ‍ॅपद्वारे किंवा आपल्‍या संस्‍थेद्वारे त्याची अनुमती नसल्‍यामुळे स्‍क्रीनशॉट घेऊ शकत नाही."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"मर्यादित संचय जागेमुळे स्क्रीनशॉट जतन करू शकत नाही."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"अॅप किंवा आपल्या संस्थेद्वारे स्क्रीनशॉट घेण्यास अनुमती नाही."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB फाईल स्थानांतरण पर्याय"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेअर म्हणून माउंट करा (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"कॅमेरा म्हणून माउंट करा (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"अधिक वेळ."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कमी वेळ."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"फ्लॅशलाइट बंद."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"फ्लॅशलाइट चालू."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"फ्लॅशलाइट बंद केला."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"फ्लॅशलाइट चालू केला."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्‍क्रीन पिन करणे"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"शोधा"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करणे शक्य झाले नाही."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> सुरक्षित-मोडमध्ये अक्षम केला आहे."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"साफ करा"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"हा अॅप एकाधिक-विंडोला समर्थन देत नाही"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"अॅप एकाधिक-विंडोला समर्थन देत नाही"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"संपूर्ण\nशांतता"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवळ\nप्राधान्य"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवळ\nअलार्म"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"सर्व"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"सर्व\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) वेगाने चार्ज होत आहे"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) हळूहळू चार्ज होत आहे"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
<string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"विभाजित-स्क्रीन स्वाइप-अप त्वरक सक्षम करा"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रीन स्वाइप-अप जेश्चर सक्षम करा"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"विहंगावलोकन बटणावरून वर स्वाइप करून विभाजित-स्क्रीन प्रविष्ट करण्यासाठी जेश्चर सक्षम करा"</string>
<string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> सूचनांवर लागू करा"</string>
- <string name="apply_to_app" msgid="363016783939815960">"या अॅपमधील सर्व सूचनांवर लागू करा"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"अवरोधित केले"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"कमी महत्त्व"</string>
<string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
<string name="high_importance" msgid="1527066195614050263">"सर्वाधिक महत्व"</string>
<string name="max_importance" msgid="5089005872719563894">"त्वरित महत्त्व"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"या सूचना कधीही दर्शवू नका"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"सूचना सूचीच्या तळाशी शांतपणे दर्शवा"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"या सूचना शांतपणे दर्शवा"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीच्या शीर्षस्थानी दर्शवा आणि ध्वनी चालू करा"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रीनवर डोकावून पहा आणि ध्वनी चालू करा"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
<string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"रात्रीचे रंग"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"सानुकूल रंग"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"स्वयं"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रंग"</string>
- <string name="color_transform" msgid="6985460408079086090">"रंग सुधारणा"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"द्रुत सेटिंग्ज टाइल दर्शवा"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"सानुकूल रूपांतरण सक्षम करा"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"रंग आणि स्वरूप"</string>
+ <string name="night_mode" msgid="3540405868248625488">"रात्र मोड"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"प्रदर्शनाचे मापन करा"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"चालू"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"बंद"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"स्वयंचलितपणे चालू करा"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"स्थान आणि दिवसाच्या वेळेसाठी योग्य असल्यानुसार रात्र मोड मध्ये स्विच करा"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"रात्र मोड चालू असताना"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS साठी गडद थीमचा वापर करा"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"रंगाची छटा समायोजित करा"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"चकाकी समायोजित करा"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"सेटिंग्ज सारख्या प्रकाश थीममध्ये प्रदर्शित केल्या जाणाऱ्या Android OS च्या मुख्य क्षेत्रांवर गडद थीम लागू केली जाते."</string>
<string name="color_apply" msgid="9212602012641034283">"लागू करा"</string>
<string name="color_revert_title" msgid="4746666545480534663">"सेटिंग्जची पुष्टी करा"</string>
<string name="color_revert_message" msgid="9116001069397996691">"काही रंग सेटिंग्ज या डिव्हाइसला निरुपयोगी करू शकतात. या रंग सेटिंग्जची पुष्टी करण्‍यासाठी ठीक आहे दाबा अन्यथा या सेटिंग्ज 10 सेकंदांनंतर रीसेट होतील."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"बॅटरी (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यप्रदर्शन आणि पार्श्वभूमी डेटा कमी करते"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"मुख्यपृष्ठ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"अलीकडील"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"परत"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"आवाजामध्‍ये व्यत्यय आणू नका दर्शवा"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"आवाज संवादामधील व्यत्यय आणू नका च्या पूर्ण नियंत्रणास अनुमती द्या."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"आवाज आणि व्यत्यय आणू नका"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"आवाज कमी केल्यावर व्यत्यय आणू नका प्रविष्‍ट करा"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"आवाज नियंत्रणांसह दर्शवा"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"व्यत्यय आणू नका"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"आवाजाच्या बटणांचा शार्टकट"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"आवाज वाढविल्यावर व्यत्यय आणू नका मधून बाहेर पडा"</string>
<string name="battery" msgid="7498329822413202973">"बॅटरी"</string>
<string name="clock" msgid="7416090374234785905">"घड्याळ"</string>
<string name="headset" msgid="4534219457597457353">"हेडसेट"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"हेडफोन कनेक्ट केले"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"हेडसेट कनेक्ट केला"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"चिन्हे स्टेटस बारमध्ये दर्शविले जाण्‍यापासून प्रतिबंधित करण्‍यासाठी ती सक्षम किंवा अक्षम करा."</string>
<string name="data_saver" msgid="5037565123367048522">"डेटा बचतकर्ता"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा बचतकर्ता चालू आहे"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा बचतकर्ता बंद आहे"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटण निवडा"</string>
<string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइल जोडण्यासाठी ड्रॅग करा"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"वेळ"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"तास, मिनिटे आणि सेकंद दर्शवा"</item>
+ <item msgid="1427801730816895300">"तास आणि मिनिटे दर्शवा (डीफॉल्ट)"</item>
+ <item msgid="3830170141562534721">"हे चिन्ह दर्शवू नका"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"नेहमी टक्केवारी दर्शवा"</item>
+ <item msgid="2139628951880142927">"चार्ज करताना टक्केवारी दर्शवा (डीफॉल्ट)"</item>
+ <item msgid="3327323682209964956">"हे चिन्ह दर्शवू नका"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रीन विभाजक"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"खाली हलवा"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"वर हलवा"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"डावीकडे हलवा"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"उजवीकडे हलवा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 0982186c444f..d2048300be52 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan skrin ditangkap."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Sentuh untuk melihat tangkapan skrin anda."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat menangkap tangkapan skrin."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Tdk dpt mngmbil tgkapn skrin krn ruang storan trhad atau tdk dibenarkn olh apl atau organisasi anda."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan tangkapan skrin kerana ruang storan terhad."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Apl atau organisasi anda tidak membenarkan pengambilan tangkapan skrin."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Pilihan pemindahan fail USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Lekapkan sebagai pemain media (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Lekapkan sebagai kamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lagi masa."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kurang masa."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampu suluh dimatikan."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampu suluh dihidupkan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampu suluh dimatikan."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampu suluh dihidupkan."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"penyematan skrin"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> dilumpuhkan dalam mod selamat."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Sejarah"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Kosongkan"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Apl ini tidak menyokong berbilang tetingkap"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Apl tidak menyokong berbilang tetingkap"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Senyap\nsepenuhnya"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Keutamaan\nsahaja"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Penggera\nsahaja"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Semua"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Semua\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengecas cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengecas perlahan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
<string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Dayakan pemecut leret ke atas untuk memasuki skrin terpisah"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Dayakan gerak isyarat leret ke atas utk masuk skrin terpisah"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Dayakan gerak isyarat untuk memasuki skrin terpisah dengan meleret ke atas daripada butang Ikhtisar"</string>
<string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Hidupkan"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Gunakan untuk pemberitahuan <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Gunakan untuk semua pemberitahuan daripada apl ini"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Disekat"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Kepentingan rendah"</string>
<string name="default_importance" msgid="8192107689995742653">"Kepentingan biasa"</string>
<string name="high_importance" msgid="1527066195614050263">"Kepentingan tinggi"</string>
<string name="max_importance" msgid="5089005872719563894">"Kepentingan segera"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan pemberitahuan ini secara senyap"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan pada bahagian atas senarai pemberitahuan dan bunyikan"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Intai pada skrin dan bunyikan"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Warna biasa"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Warna tersuai"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Warna tidak diketahui"</string>
- <string name="color_transform" msgid="6985460408079086090">"Pengubahsuaian warna"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tunjukkan jubin Tetapan Pantas"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Dayakan jelmaan tersuai"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Warna dan penampilan"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Mod malam"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Tentukur paparan"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Hidup"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Mati"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Hidupkan secara automatik"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Beralih ke Mod Malam sebagaimana sesuai untuk lokasi dan masa"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Apabila Mod Malam dihidupkan"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Gunakan tema gelap untuk OS Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Laraskan seri warna"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Laraskan kecerahan"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema gelap digunakan pada bahagian teras OS Android yang biasanya dipaparkan dalam tema cerah, seperti Tetapan."</string>
<string name="color_apply" msgid="9212602012641034283">"Gunakan"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Sahkan tetapan"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Sesetengah tetapan warna boleh menjadikan peranti ini tidak dapat digunakan. Klik OK untuk mengesahkan tetapan warna ini, jika tidak, tetapan ini akan ditetapkan semula selepas 10 saat."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateri (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Mengurangkan prestasi dan data latar belakang"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Skrin Utama"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Terbaharu"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Kembali"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Tunjukkan jangan ganggu dalam kelantangan"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Benarkan kawalan penuh jangan ganggu dalam dialog kelantangan."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Kelantangan dan Jangan Ganggu"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Masuki mod jangan ganggu apabila kelantangan direndahkan"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Tunjukkan dengan kawalan kelantangan"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Jangan ganggu"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Pintasan butang kelantangan"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Keluar drp mod jangan ganggu apabila kelantangan ditinggikan"</string>
<string name="battery" msgid="7498329822413202973">"Bateri"</string>
<string name="clock" msgid="7416090374234785905">"Jam"</string>
<string name="headset" msgid="4534219457597457353">"Set Kepala"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fon kepala disambungkan"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Set kepala disambungkan"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Dayakan atau lumpuhkan ikon daripada dipaparkan dalam bar status."</string>
<string name="data_saver" msgid="5037565123367048522">"Penjimat Data"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Penjimat Data dihidupkan"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Penjimat Data dimatikan"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Pilih Butang Papan Kekunci"</string>
<string name="preview" msgid="9077832302472282938">"Pratonton"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Seret untuk menambahkan jubin"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Masa"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Tunjukkan jam, minit dan saat"</item>
+ <item msgid="1427801730816895300">"Tunjukkan jam dan minit (lalai)"</item>
+ <item msgid="3830170141562534721">"Jangan tunjukkan ikon ini"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Sentiasa tunjukkan peratusan"</item>
+ <item msgid="2139628951880142927">"Tunjukkan peratusan semasa mengecas (lalai)"</item>
+ <item msgid="3327323682209964956">"Jangan tunjukkan ikon ini"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Pembahagi skrin terpisah"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Alih ke bawah"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Alih ke atas"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Alih ke kiri"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Alih ke kanan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index bfc2070d2a94..c88eda2521fd 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား ဖမ်းယူပြီး"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"သင့်ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား ကြည့်ရှုရန် ထိပါ"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား မဖမ်းစီးနိုင်ပါ"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"မျက်နှာပြင်လျှပ်တပြက်ပုံကို မရုက်နိုင်ခဲ့ပါ၊ သိုလှောင်မှု နေရာ အကန့်အသတ် ရှိနေ၍ သို့မဟုတ် app သို့မဟုတ် သင်၏ အဖွဲ့အစည်းက ခွင့်မပြု၍ ဖြစ်နိုင်သည်။"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"သိုလှောင်ခန်းနေရာ အကန့်အသတ်ရှိသောကြောင့် ဖန်သားပြင်ဓာတ်ပုံကို သိမ်းဆည်း၍မရပါ။"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ဖန်သားပြင်ဓာတ်ပုံရိုက်ကူးခြင်းကို အက်ပ်မှ သို့မဟုတ် သင့်အဖွဲ့အစည်းမှ ခွင့်မပြုပါ။"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ဖိုင်ပြောင်း ရွေးမှုများ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"မီဒီယာပလေရာအနေဖြင့် တပ်ဆင်ရန် (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ကင်မရာအနေဖြင့် တပ်ဆင်ရန် (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"အချိန် တိုး"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"အချိန် လျှော့"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ဖလက်ရှမီး ပိတ်ထား"</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ဓာတ်မီးမရသေးပါ။"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ဖလက်ရှမီး ဖွင့်ထား။"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ဖလက်ရှမီး ပိတ်ထားသည်။"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ဖလက်ရှမီး ဖွင့်ထားသည်။"</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"မျက်နှာပြင် ပင်ထိုးမှု"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ရှာဖွေရန်"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ကို မစနိုင်ပါ။"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ကို ဘေးကင်းလုံခြုံသည့်မုဒ်တွင် ပိတ်ထားပါသည်။"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"မှတ်တမ်း"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ရှင်းလင်းပါ"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ဤအက်ပ်သည် ဝင်းဒိုးများစွာတွင်ဖွင့်ရန် မပံ့ပိုးထားပါ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"အက်ပ်သည် ဝင်းဒိုးများစွာတွင်ဖွင့်ရန် မပံ့ပိုးထားပါ"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"လုံးဝ\nတိတ်ဆိတ်ခြင်း"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ဦးစားပေးမှု\nသာ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"နှိုးစက်များ\nသာ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"အားလုံး"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"အားလုံး\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"လျှင်မြန်စွာအားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"နှေးကွေးစွာ အားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
<string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း လုပ်ဆောင်ချက်ကိုဖွင့်ပါ"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်အမူအယာကိုဖွင့်ပါ"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း အမူအရာကိုဖွင့်ပါ"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်ဟန်ကိုဖွင့်ပါ"</string>
<string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ဖွင့်ပါ"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"သတိပေးချက် <xliff:g id="TOPIC_NAME">%1$s</xliff:g> ခုသို့သက်ရောက်စေပါ"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ဤအက်ပ်မှ သတိပေးချက်များအားလုံးသို့ သက်ရောက်စေပါ"</string>
+ <string name="show_silently" msgid="6841966539811264192">"သတိပေးချက်များကို တိတ်ဆိတ်စွာပြပါ"</string>
+ <string name="block" msgid="2734508760962682611">"သတိပေးချက်များအားလုံးကို ပိတ်ဆို့ပါ"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"အသံ မတိတ်ပါနှင့်"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"အသံ မတိတ်ပါနှင့် သို့မဟုတ် မပိတ်ဆို့ပါနှင့်"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"အပြည့်အဝအရေးပါသည့် ဆက်တင်များကိုပြပါ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"ပိတ်ဆို့ထားသည်"</string>
+ <string name="min_importance" msgid="1901894910809414782">"အနည်းဆုံး အရေးပါမှု"</string>
<string name="low_importance" msgid="4109929986107147930">"အနည်းငယ်သာ အရေးပါသည်"</string>
<string name="default_importance" msgid="8192107689995742653">"သာမန်သာ အရေးပါသည်"</string>
<string name="high_importance" msgid="1527066195614050263">"အလွန်အရေးပါသည်"</string>
<string name="max_importance" msgid="5089005872719563894">"အရေးတကြီး အရေးပါသည်"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ဤသတိပေးချက်များကို ဘယ်တော့မှမပြပါနှင့်"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"သတိပေးချက်စာရင်း၏ အောက်ဆုံးတွင် တိတ်တဆိတ်ပြပါ"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ဤသတိပေးချက်များကို တိတ်တဆိတ်ပြပါ"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"သတိပေးချက်စာရင်းများ၏ ထိပ်တွင်ပြကာ အသံဖွင့်ပါ"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"မျက်နှာပြင်ပေါ်သို့ ဖော်ပြကာ အသံဖွင့်ပါ"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"သတိပေးချက်စာရင်း၏ အောက်ဆုံးတွင် တိတ်ဆိတ်စွာပြပါ"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ဤသတိပေးချက်များကို တိတ်ဆိတ်စွာပြပါ"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ဤသတိပေးချက်များကို အသံထွက်ခွင့်ပြုပါ"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"ဖန်သားပြင်ပေါ်တွင် ပေါ်စေပြီး အသံထွက်ခွင့်ပြုပါ"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"သတိပေးချက်စာရင်း၏ ထိပ်ဆုံးတွင်ပြပြီး ဖန်သားပြင်ပေါ်တွင် ပေါ်စေကာ အသံထွက်ခွင့်ပြုပါ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
<string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ပုံမှန် အရောင်များ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ည အရောင်များ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"စိတ်ကြိုက် အရောင်များ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"အလိုအလျောက်"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"မသိသည့် အရောင်များ"</string>
- <string name="color_transform" msgid="6985460408079086090">"အရောင် မွမ်းမံမှု"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"အမြန် ဆက်တင် လေးထောင့်ကွက်ကို ပြပါ"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"စိတ်ကြိုက် ပြောင်းလဲမှုကို ဖွင့်ပါ"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"အရောင်နှင့် အပြင်အဆင်"</string>
+ <string name="night_mode" msgid="3540405868248625488">"ညသုံးမုဒ်"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ပြသမှုအချိန်အဆကို ညှိပါ"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ဖွင့်ပါ"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ပိတ်ပါ"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"အလိုအလျောက် ဖွင့်ပါ"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"တည်နေရာနှင့် တစ်ရက်တာအချိန်နှင့် သင့်လျော်သလို ညသုံးမုဒ်သို့ ပြောင်းပါ"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"ညသုံမုဒ်ဖွင့်ထားစဉ်"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS အတွက်အရောင်ရင့်အပြင်အဆင်ကို သုံးပါ"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"အရောင်မွဲမှုကို ချိန်ပါ"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"အလင်းအမှောင်ချိန်ပါ"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"အရောင်ရင့်အပြင်အဆင်သည် ဆက်တင်များကဲ့သို့ ပုံမှန်အားဖြင့် အရောင်ဖျော့အပြင်အဆင်အဖြစ်ရှိသည့် Android OS ၏အဓိကနေရာများကို ပြောင်းလဲပေးပါသည်။"</string>
<string name="color_apply" msgid="9212602012641034283">"အသုံးပြုပါ"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ဆက်တင်များကို အတည်ပြုပါ"</string>
<string name="color_revert_message" msgid="9116001069397996691">"အချို့သော အရောင်ဆက်တက်များက ဤကိရိယာကို သုံးမရအောင် လုပ်ပစ်နိုင်ပါသည်။ ဤအရောင် ဆက်တင်များကို အတည်ပြုရန် အိုကေကို နှိပ်ပါ၊ သို့မဟုတ် ဤဆက်တင်များကို ၁၀ စက္ကန့် အကြာတွင် ပြန်ညှိလိုက်ပါမည်။"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ဘက်ထရီ ( <xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"လုပ်ဆောင်မှု နှင့် နောက်ခံ ​ဒေတာကို လျော့နည်းစေပါသည်"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"အသံအတိုးအလျှော့တွင် မနှောက်ယှက်ရကို ပြပါ"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"အသံအတိုးအလျှော့အကွက်ထဲတွင် မနှောက်ယှက်ရကို အပြည့်အဝထိန်းချုပ်ခွင့် ပြုပါ။"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"အသံအတိုးအလျှော့နှင့် မနှောက်ယှက်ရ"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"အသံလျှော့သည်နှင့် မနှောက်ယှက်ရသို့ ပြောင်းလဲပါ"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"အသံထိန်းချုပ်သည့်ခလုတ်များဖြင့် ပြပါ"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"မနှောက်ယှက်ပါနှင့်"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"အသံထိန်းချုပ်သည့်ခလုတ် ဖြတ်လမ်း"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"အသံချဲ့သည်နှင့် မနှောက်ယှက်ရမှ ထွက်ပါ"</string>
<string name="battery" msgid="7498329822413202973">"ဘတ်ထရီ"</string>
<string name="clock" msgid="7416090374234785905">"နာရီ"</string>
<string name="headset" msgid="4534219457597457353">"မိုက်ခွက်ပါနားကြပ်"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"နားကြပ်တပ်ဆင်ပြီးပါပြီ"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"မိုက်ခွက်ပါနားကြပ်တပ်ဆင်ပြီးပါပြီ"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"အခြေအနေဘားတန်းတွင် သင်္ကေတပုံပြခြင်းကို ဖွင့်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
<string name="data_saver" msgid="5037565123367048522">"ဒေတာချွေတာမှု"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ဒေတာချွေတာမှု ဖွင့်ထားသည်"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ဒေတာချွေတာမှု ပိတ်ထားသည်"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"ကီးဘုတ်ခလုတ်ကို ရွေးချယ်ပါ"</string>
<string name="preview" msgid="9077832302472282938">"အစမ်းကြည့်ပါ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"အချပ်များကိုထည့်ရန် ဖိဆွဲပါ"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"တည်းဖြတ်ပါ"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"အချိန်"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"နာရီ၊ မိနစ်နှင့် စက္ကန့်ကိုပြပါ"</item>
+ <item msgid="1427801730816895300">"နာရီနှင့် မိနစ်ကိုပြပါ (ပုံသေ)"</item>
+ <item msgid="3830170141562534721">"ဤသင်္ကေတပုံကို မပြပါနှင့်"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ရာခိုင်နှုန်းကို အမြဲတမ်းပြပါ"</item>
+ <item msgid="2139628951880142927">"အားသွင်းနေစဉ်တွင် ရာခိုင်နှုန်းကိုပြပါ (ပုံသေ)"</item>
+ <item msgid="3327323682209964956">"ဤသင်္ကေတပုံကို မပြပါနှင့်"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"အခြား"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"မျက်နှာပြင်ခွဲခြမ်းခြင်း ပိုင်းခြားပေးသည့်စနစ်"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"အောက်သို့ရွှေ့ပါ"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"အပေါ်သို့ရွှေ့ပါ"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ဘယ်ဘက်သို့ရွှေ့ပါ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ညာဘက်သို့ရွှေ့ပါ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3adb0f4aaf6e..ac8cc8ddf3c4 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Skjermdumpen er lagret."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Trykk for å se skjermdumpen."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Kan ikke lagre skjermdumpen."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan ikke ta skjermdump grunnet plassbegrensning, app- eller organisasjonstillatelser."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan ikke lagre skjermdumpen på grunn av begrenset lagringsplass."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Appen eller organisasjonen din tillater ikke at du tar skjermdumper."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Altern. for USB-filoverføring"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Sett inn som mediespiller (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Sett inn som kamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mer tid."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelykten er av."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelykten er på."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelykten er slått av."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelykten er slått på."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"én-appsmodus"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er slått av i sikker modus."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Logg"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tøm"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Denne appen har ikke støtte for flervindusmodus"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen har ikke støtte for flervindusmodus"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nstillhet"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Bare\nPrioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Bare\nalarmer"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Lader raskt (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lader sakte (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
<string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Slå på delt skjerm ved å sveipe opp med akseleratoren"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Slå på delt skjerm ved å sveipe opp"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Slå på bevegelsen for å åpne delt skjerm ved å sveipe opp fra Oversikt-knappen"</string>
<string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå på"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Bruk for varsler for <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Bruk for alle varslene fra denne appen"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blokkert"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Lav viktighet"</string>
<string name="default_importance" msgid="8192107689995742653">"Vanlig viktighet"</string>
<string name="high_importance" msgid="1527066195614050263">"Høy viktighet"</string>
<string name="max_importance" msgid="5089005872719563894">"Svært høy viktighet"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Aldri vis disse varslene"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Vis nederst på varsellisten uten lyd"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse varslene uten lyd"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på varsellisten med lyd"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Vis fort på skjermen med lyd"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
<string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normale farger"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nattfarger"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Spesialtilpassede farger"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisk"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Ukjente farger"</string>
- <string name="color_transform" msgid="6985460408079086090">"Fargemodifisering"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Vis ruten for hurtiginnstillinger"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Slå på spesialtilpasset forvandling"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Farge og utseende"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nattmodus"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrer skjermen"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"På"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Av"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Slå på automatisk"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Bytt til nattmodus avhengig av tid og sted"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Når nattmodus er på"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Bruk et mørkt tema for Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Juster fargen"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Juster lysstyrken"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Det mørke temaet brukes på kjerneområdene i Android OS som vanligvis vises i et lyst tema, for eksempel Innstillinger."</string>
<string name="color_apply" msgid="9212602012641034283">"Bruk"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Bekreft innstillingene"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Noen fargeinnstillinger kan gjøre denne enheten ubrukelig. Klikk på OK for å bekrefte disse fargeinnstillingene, ellers blir de tilbakestilt etter ti sekunder."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batteri (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startside"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nylige"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbake"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Vis «Ikke forstyrr» i volumkontrollene"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Tillat full kontroll over «Ikke forstyrr» i volumdialogen."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volum og «Ikke forstyrr»"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Åpne «Ikke forstyrr» med volum ned-knappen"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Vis med volumkontrollene"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ikke forstyrr"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Hurtigtast for volumknappene"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Lukk «Ikke forstyrr» med volum opp-knappen"</string>
<string name="battery" msgid="7498329822413202973">"Batteri"</string>
<string name="clock" msgid="7416090374234785905">"Klokke"</string>
<string name="headset" msgid="4534219457597457353">"Hodetelefoner"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Øretelefoner er tilkoblet"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Hodetelefoner er tilkoblet"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Vis eller skjul ikoner i statusfeltet."</string>
<string name="data_saver" msgid="5037565123367048522">"Datasparing"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Datasparing er på"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Datasparing er av"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Velg tastaturtast"</string>
<string name="preview" msgid="9077832302472282938">"Forhåndsvisning"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dra for å legge til fliser"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Endre"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Tid"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Vis timer, minutter og sekunder"</item>
+ <item msgid="1427801730816895300">"Vis timer og minutter (standard)"</item>
+ <item msgid="3830170141562534721">"Ikke vis dette ikonet"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Vis alltid prosentandel"</item>
+ <item msgid="2139628951880142927">"Vis prosentandel under lading (standard)"</item>
+ <item msgid="3327323682209964956">"Ikke vis dette ikonet"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Skilleelement for delt skjerm"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytt ned"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytt opp"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytt mot venstre"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytt mot høyre"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index b26ed6b56ef8..4b785528d847 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रिनसट क्याप्चर गरियो।"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"तपाईँको स्क्रिनसट हेर्न छुनुहोस्।"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रिनसट क्याप्चर गर्न सकिएन।"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"सीमित भण्डारण ठाउँको कारणले स्क्रिनसट लिन सकिएन, वा यो अनुप्रयोग वा आफ्नो संगठन द्वारा अनुमति छैन।"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"सीमित भण्डारण स्थान उपलब्ध रहेको हुनाले स्क्रिनसटलाई सुरक्षित गर्न सकिँदैन।"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"अनुप्रयोग वा तपाईँको संगठनले स्क्रिनसट लिन अनुमति दॅिंदैन।"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB फाइल सार्ने विकल्पहरू"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"मिडिया प्लेयर(MTP)को रूपमा माउन्ट गर्नुहोस्"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"क्यामेराको रूपमा माउन्ट गर्नुहोस् (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"थप समय।"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कम समय।"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"टर्च बन्द छ।"</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ्ल्यासलाइट उपलब्ध छैन।"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"टर्च खुला छ।"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"टर्च बन्द गरियो।"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"टर्च खुला गरियो।"</string>
@@ -301,8 +303,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रिन पिन गर्दै"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"इतिहास"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"मेटाउनुहोस्"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"यस अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"अनुप्रयोगले बहु-विन्डोलाई समर्थन गर्दैन"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"पूरै\nशान्त"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"प्राथमिकता \nमात्र"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"अलार्महरू \nमात्र"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"सबै"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"सबै\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"छिटो चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"बिस्तारै चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
@@ -446,38 +450,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
<string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"विभाजित-स्क्रिनको स्वाइप-अप एक्सेलेटर सक्रिय गर्नुहोस्"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न गेस्चरलाई सक्रिय गर्नुहोस्"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रिन स्वाइप-अप इशारा सक्षम गर्नुहोस्"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न इसारालाई सक्रिय गर्नुहोस्"</string>
<string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"सक्रिय पार्नुहोस्"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> सूचनाहरूमा लागू गर्नुहोस्"</string>
- <string name="apply_to_app" msgid="363016783939815960">"यो अनुप्रयोगका सबै सूचनाहरूमा लागू गर्नुहोस्"</string>
+ <string name="show_silently" msgid="6841966539811264192">"सूचनाहरूलाई बिना आवाज देखाउनुहोस्"</string>
+ <string name="block" msgid="2734508760962682611">"सबै सूचनाहरूलाई रोक्नुहोस्"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"मौन नगर्नुहोस्"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"मौन नगर्नुहोस् वा नरोक्नुहोस्"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिङहरू देखाउनुहोस्"</string>
<string name="blocked_importance" msgid="5198578988978234161">"रोकियो"</string>
+ <string name="min_importance" msgid="1901894910809414782">"न्यूनतम महत्त्व"</string>
<string name="low_importance" msgid="4109929986107147930">"न्यून महत्त्व"</string>
<string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
<string name="high_importance" msgid="1527066195614050263">"उच्च महत्त्व"</string>
<string name="max_importance" msgid="5089005872719563894">"जरूरी महत्त्व"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"सूचीको फेदमा बिना आवाज देखाउनुहोस्"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"यी सूचनाहरू बिना आवाज देखाउनुहोस्"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रिनमा हेर्नुहोस् र आवाज निकाल्नुहोस्"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"सूचना सूचीको फेदमा बिना आवाज देखाउने"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"यी सूचनाहरूलाई बिना आवाज देखाउने"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"यी सूचनाहरूलाई ध्वनि निकाल्न अनुमति दिने"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रिनमा चियाउने र ध्वनि निकाल्न अनुमति दिने"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"सूचना सूचीको शीर्षमा देखाउने, स्क्रिनमा चियाउने र ध्वनि निकाल्न अनुमति दिने"</string>
<string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
<string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रङहरू"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"रात्री रङहरू"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"अनुकूलन रङहरू"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"स्वतः"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रङहरू"</string>
- <string name="color_transform" msgid="6985460408079086090">"रङ परिमार्जन"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"द्रुत सेटिङ टाइल देखाउनुहोस्"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"अनुकूलन रूपान्तरण सक्रिय गर्नुहोस्"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"रंग र रूप"</string>
+ <string name="night_mode" msgid="3540405868248625488">"रात्री मोड"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"प्रदर्शनको स्तर मिलाउनुहोस्"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"सक्रिय"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"निष्क्रिय"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"स्वतः सक्रिय पार्नुहोस्"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"स्थान र दिनको समयको लागि उपयुक्त रात्री मोडमा स्विच गर्नुहोस्"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"रात्री मोड सक्रिय हुँदा"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS का लागि गाढा रंगको विषयवस्तु प्रयोग गर्नुहोस्"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"रङ्गलाई समायोजन गर्नुहोस्"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"चमकलाई समायोजन गर्नुहोस्"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"गहिरो रंगको विषयवस्तुलाई Android OS का त्यस्ता मुख्य क्षेत्रहरूमा लागू गरिन्छ जसलाई सामान्यतया हल्का रंगमा देखाइन्छ, जस्तै सेटिङहरू।"</string>
<string name="color_apply" msgid="9212602012641034283">"लागू गर्नुहोस्"</string>
<string name="color_revert_title" msgid="4746666545480534663">"सेटिङहरूको पुष्टि गर्नुहोस्"</string>
<string name="color_revert_message" msgid="9116001069397996691">"केही रङ सेटिङहरूले यस यन्त्रलाई अनुपयोगी बनाउन सक्छन्। यी रङ सेटिङहरू पुष्टि गर्न ठीक छ मा क्लिक गर्नुहोस्, अन्यथा यी सेटिङहरू १० सेकेण्डपछि रिसेट हुनेछन्।"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ब्याट्री (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"कार्यसम्पादन र पृष्ठभूमि डेटा घटाउँछ"</string>
@@ -485,21 +498,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"गृह"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"हालैका"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"पछाडि"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"भोल्युममा बाधा नपुर्याउनुहोस् देखाउनुहोस्"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"भोल्युमको संवादमा बाधा नपुर्याउनुहोस् को पूर्ण नियन्त्रणलाई अनुमति दिनुहोस्"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"भोल्युम र बाधा नपुर्याउनुहोस्"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"भोल्युम कम गर्नेमा बाधा नपुर्याउनुहोस् प्रविष्ट गर्नुहोस्"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"भोल्युम नियन्त्रणसहित देखाउनुहोस्"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"बाधा नपुर्याउनुहोस्"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"भोल्युम बटनका सर्टकट"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"भोल्युम बढाउनेमा बाधा नपुर्याउनुहोस् प्रविष्ट गर्नुहोस्"</string>
<string name="battery" msgid="7498329822413202973">"ब्याट्री"</string>
<string name="clock" msgid="7416090374234785905">"घडी"</string>
<string name="headset" msgid="4534219457597457353">"हेडसेट"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"हेडफोनहरू जडान गरियो"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"हेडसेट जडान गरियो"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"वस्तुस्थिति पट्टीमा देखाइनको लागि आइकनहरू सक्रिय वा निष्क्रिय गर्नुहोस्।"</string>
<string name="data_saver" msgid="5037565123367048522">"डेटा सेभर"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"डेटा सेभर अन छ"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"डेटा सेभर बन्द छ"</string>
<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>
@@ -521,4 +533,22 @@
<string name="select_keycode" msgid="7413765103381924584">"किबोर्ड बटन चयन गर्नुहोस्"</string>
<string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलहरू थप्न तान्नुहोस्"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"समय"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"घण्टा, मिनेट, र सेकेन्ड देखाउनुहोस्"</item>
+ <item msgid="1427801730816895300">"घण्टा र मिनेट (पूर्वनिर्धारित) देखाउनुहोस्"</item>
+ <item msgid="3830170141562534721">"यो आइकन नदेखाउनुहोस्"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"सधैं प्रतिशत देखाउनुहोस्"</item>
+ <item msgid="2139628951880142927">"चार्ज गर्दा प्रतिशत देखाउनुहोस् (पूर्वनिर्धारित)"</item>
+ <item msgid="3327323682209964956">"यो आइकन नदेखाउनुहोस्"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"अन्य"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रिन छुट्याउने"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"तल सार्नुहोस्"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"माथि सार्नुहोस्"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाँया सार्नुहोस्"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दायाँ सार्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 947bc0ccf100..9698cdff6eca 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om je screenshot te bekijken."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan geen screenshot maken wegens beperkte opslagruimte of omdat de app of je organisatie dit niet toestaat."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan screenshot niet opslaan vanwege beperkte opslagruimte."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tijd."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tijd."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Zaklamp uit."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Zaklamp niet beschikbaar."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Zaklamp aan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Zaklamp uitgeschakeld."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Zaklamp ingeschakeld."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"scherm vastzetten"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is uitgeschakeld in de veilige modus"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Geschiedenis"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Wissen"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Deze app ondersteunt de modus voor meerdere vensters niet"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"App ondersteunt meerdere vensters niet"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Totale\nstilte"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alle\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Snel opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langzaam opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
<string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Gebaar inschakelen om gesplitst scherm te openen door vanaf de knop Overzicht omhoog te vegen"</string>
<string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Inschakelen"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Toepassen op meldingen voor <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Toepassen op alle meldingen van deze app"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Meldingen zonder geluid weergeven"</string>
+ <string name="block" msgid="2734508760962682611">"Alle meldingen blokkeren"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Niet zonder geluid weergeven"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Niet zonder geluid weergeven of blokkeren"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Volledige instellingen voor belang weergeven"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Geblokkeerd"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Minimaal belang"</string>
<string name="low_importance" msgid="4109929986107147930">"Klein belang"</string>
<string name="default_importance" msgid="8192107689995742653">"Normaal belang"</string>
<string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgent belang"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Deze meldingen nooit weergeven"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Onder aan de lijst met meldingen weergeven zonder geluid"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Deze meldingen zonder geluid weergeven"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Boven aan de lijst met meldingen weergeven en geluid laten horen"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Op het scherm weergeven en geluid laten horen"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Onder aan de lijst met meldingen weergeven zonder geluid"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Deze meldingen zonder geluid weergeven"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Toestaan dat deze meldingen geluid laten horen"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Op het scherm weergeven en geluid toestaan"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Boven aan de lijst met meldingen weergeven, op het scherm weergeven en geluid toestaan"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
<string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleuren"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nachtkleuren"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Aangepaste kleuren"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatisch"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Onbekende kleuren"</string>
- <string name="color_transform" msgid="6985460408079086090">"Kleuraanpassing"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tegel voor \'Snelle instellingen\' weergeven"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Aangepast transformeren inschakelen"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Kleur en uiterlijk"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nachtmodus"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Display kalibreren"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aan"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Uit"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Automatisch inschakelen"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Overschakelen naar nachtmodus indien van toepassing voor locatie en tijd van de dag"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Als nachtmodus is ingeschakeld"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Donker thema gebruiken voor Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Tint aanpassen"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Helderheid aanpassen"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Het donkere thema wordt toegepast op kerngedeelten van het Android-besturingssysteem die normaal gesproken worden weergegeven met een licht thema, zoals Instellingen."</string>
<string name="color_apply" msgid="9212602012641034283">"Toepassen"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Instellingen bevestigen"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Bij sommige kleurinstellingen kan het apparaat onbruikbaar worden. Klik op OK om deze kleurinstellingen te bevestigen, anders worden deze instellingen na tien seconden gereset."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Accu (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Vermindert de prestaties en achtergrondgegevens"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startpagina"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recent"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Terug"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"\'Niet storen\' weergeven in volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Volledig beheer van \'Niet storen\' in het volumedialoogvenster toestaan."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume en \'Niet storen\'"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"\'Niet storen\' activeren bij volume omlaag"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Weergeven met volumeknoppen"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Niet storen"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Volumeknoppen als sneltoets"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"\'Niet storen\' afsluiten bij volume omhoog"</string>
<string name="battery" msgid="7498329822413202973">"Accu"</string>
<string name="clock" msgid="7416090374234785905">"Klok"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Hoofdtelefoon aangesloten"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset aangesloten"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"De weergave van pictogrammen in de statusbalk in- of uitschakelen."</string>
<string name="data_saver" msgid="5037565123367048522">"Databesparing"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Databesparing is ingeschakeld"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Databesparing is uitgeschakeld"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Toetsenbordknop selecteren"</string>
<string name="preview" msgid="9077832302472282938">"Voorbeeld"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om tegels toe te voegen"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Bewerken"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Tijd"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Uren, minuten en seconden weergeven"</item>
+ <item msgid="1427801730816895300">"Uren en minuten weergeven (standaard)"</item>
+ <item msgid="3830170141562534721">"Dit pictogram niet weergeven"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Percentage altijd weergeven"</item>
+ <item msgid="2139628951880142927">"Percentage weergeven tijdens opladen (standaard)"</item>
+ <item msgid="3327323682209964956">"Dit pictogram niet weergeven"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Overig"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Scheiding voor gesplitst scherm"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Omlaag"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Omhoog"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Naar links"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Naar rechts"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 45bf5b9ba559..6fb2c703ecb6 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਕੈਪਚਰ ਕੀਤਾ।"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"ਆਪਣਾ ਸਕ੍ਰੀਨਸ਼ੌਟ ਦੇਖਣ ਲਈ ਛੋਹਵੋ।"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ਸਕ੍ਰੀਨਸ਼ੌਟ ਕੈਪਚਰ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"ਸੀਮਿਤ ਸਟੋਰੇਜ ਸਪੇਸ ਦੇ ਕਾਰਨ ਸਕ੍ਰੀਨਸ਼ੌਟ ਨਹੀਂ ਲੈ ਸਕਦਾ ਜਾਂ ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਕੰਪਨੀ ਵੱਲੋਂ ਇਸਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ।"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ਸੀਮਿਤ ਸਟੋਰੇਜ ਥਾਂ ਦੇ ਕਾਰਨ ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਸਕਦਾ।"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਦੁਆਰਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਮਨਜ਼ੂਰੀ ਨਹੀਂ ਹੈ।"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਚੋਣਾਂ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ਇੱਕ ਮੀਡੀਆ ਪਲੇਅਰ (MTP) ਦੇ ਤੌਰ ਤੇ ਮਾਊਂਟ ਕਰੋ"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ਇੱਕ ਕੈਮਰੇ (PTP) ਦੇ ਤੌਰ ਤੇ ਮਾਊਂਟ ਕਰੋ"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ਹੋਰ ਸਮਾਂ।"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ਘੱਟ ਸਮਾਂ।"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ਫਲੈਸ਼ਲਾਈਟ ਬੰਦ।"</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ਫਲੈਸ਼ਲਾਈਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ਫਲੈਸ਼ਲਾਈਟ ਚਾਲੂ।"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ਫਲੈਸ਼ਲਾਈਟ ਬੰਦ ਕੀਤਾ।"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ਫਲੈਸ਼ਲਾਈਟ ਚਾਲੂ ਕੀਤੀ।"</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ਸਕ੍ਰੀਨ ਪਿਨਿੰਗ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ਖੋਜੋ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਚਾਲੂ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਸੁਰੱਖਿਅਤ-ਮੋਡ ਵਿੱਚ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ।"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ਇਤਿਹਾਸ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ਸਾਫ਼ ਕਰੋ"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ਇਹ ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"ਕੁਲ \n ਚੁੱਪੀ"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ਕੇਵਲ\nਤਰਜੀਹੀ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ਕੇਵਲ\nਅਲਾਰਮ"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ਸਭ"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ਸਾਰੀਆਂ\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ਚਾਰਜਿੰਗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰਾ ਹੋਣ ਤੱਕ)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
<string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਐਕਸੇਲਰੇਟਰ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ਰੂਪ-ਰੇਖਾ ਬਟਨ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਨ ਦੁਆਰਾ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਣ ਲਈ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
<string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ਚਾਲੂ ਕਰੋ"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ਸੂਚਨਾਵਾਂ \'ਤੇ ਲਾਗੂ ਕਰੋ"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ਇਸ ਐਪ ਦੀਆਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ \'ਤੇ ਲਾਗੂ ਕਰੋ"</string>
+ <string name="show_silently" msgid="6841966539811264192">"ਸੂਚਨਾਵਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+ <string name="block" msgid="2734508760962682611">"ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬਲੌਕ ਕਰੋ"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ਚੁੱਪ ਨਾ ਕਰਵਾਓ"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ਚੁੱਪ ਨਾ ਕਰਵਾਓ ਜਾਂ ਬਲੌਕ ਨਾ ਕਰੋ"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ਪੂਰੀ ਮਹੱਤਤਾ ਵਾਲੀਆਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵਿਖਾਓ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"ਬਲੌਕ ਕੀਤਾ"</string>
+ <string name="min_importance" msgid="1901894910809414782">"ਨਿਊਨਤਮ ਮਹੱਤਤਾ"</string>
<string name="low_importance" msgid="4109929986107147930">"ਘੱਟ ਮਹੱਤਤਾ"</string>
<string name="default_importance" msgid="8192107689995742653">"ਸਧਾਰਨ ਮਹੱਤਤਾ"</string>
<string name="high_importance" msgid="1527066195614050263">"ਵੱਧ ਮਹੱਤਤਾ"</string>
<string name="max_importance" msgid="5089005872719563894">"ਜ਼ਰੂਰੀ ਮਹੱਤਤਾ"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਕਦੇ ਨਾ ਵਿਖਾਓ"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"ਸਕਰੀਨ \'ਤੇ ਝਾਤੀ ਮਾਰੋ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਧੁਨੀ ਪੈਦਾ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"ਸਕ੍ਰੀਨ \'ਤੇ ਝਲਕ ਵਿਖਾਉਣ ਅਤੇ ਧੁਨੀ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ, ਸਕ੍ਰੀਨ \'ਤੇ ਝਲਕ ਵਿਖਾਉਣ ਅਤੇ ਧੁਨੀ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"ਸਧਾਰਨ ਰੰਗ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"ਰਾਤ ਦੇ ਰੰਗ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"ਕਸਟਮ ਰੰਗ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ਸਵੈ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"ਅਗਿਆਤ ਰੰਗ"</string>
- <string name="color_transform" msgid="6985460408079086090">"ਰੰਗ ਸੋਧ"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਟਾਇਲ ਵਿਖਾਓ"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"ਕਸਟਮ ਤਬਦੀਲੀ ਯੋਗ ਬਣਾਓ"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"ਰੰਗ ਅਤੇ ਵਿਖਾਲਾ"</string>
+ <string name="night_mode" msgid="3540405868248625488">"ਰਾਤ ਮੋਡ"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ਡਿਸਪਲੇ ਨੂੰ ਕੈਲੀਬ੍ਰੇਟ ਕਰੋ"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ਚਾਲੂ"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ਬੰਦ"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"ਸਵੈਚਾਲਿਤ ਤੌਰ \'ਤੇ ਚਾਲੂ ਕਰੋ"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ਟਿਕਾਣੇ ਅਤੇ ਦਿਨ ਦੇ ਸਮੇਂ ਲਈ ਢੁਕਵੇਂ ਰਾਤ ਮੋਡ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"ਜਦੋਂ ਰਾਤ ਮੋਡ ਚਾਲੂ ਹੋਵੇ"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS ਲਈ ਗੂੜ੍ਹੇ ਥੀਮ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ਟਿੰਟ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ਚਮਕ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ Android OS ਦੇ ਉਹਨਾਂ ਮੁੱਖ ਖੇਤਰਾਂ \'ਤੇ ਲਾਗੂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਜੋ ਆਮ ਤੌਰ \'ਤੇ ਇੱਕ ਹਲਕੇ ਥੀਮ ਵਿੱਚ ਵਿਖਾਏ ਜਾਂਦੇ ਹਨ, ਜਿਵੇਂ ਕਿ ਸੈਟਿੰਗਾਂ।"</string>
<string name="color_apply" msgid="9212602012641034283">"ਲਾਗੂ ਕਰੋ"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
<string name="color_revert_message" msgid="9116001069397996691">"ਕੁਝ ਰੰਗ ਸੈਟਿੰਗਾਂ ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬੇਕਾਰ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਇਹਨਾਂ ਰੰਗ ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਠੀਕ \'ਤੇ ਕਲਿੱਕ ਕਰੋ, ਨਹੀਂ ਤਾਂ ਇਹ ਸੈਟਿੰਗਾਂ 10 ਸਕਿੰਟ ਬਾਅਦ ਮੁੜ-ਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ।"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"ਬੈਟਰੀ (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ਕਾਰਗੁਜ਼ਾਰੀ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਡੈਟੇ ਨੂੰ ਘਟਾਉਂਦਾ ਹੈ"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ਮੁੱਖ ਸਕ੍ਰੀਨ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ਹਾਲੀਆ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ਪਿੱਛੇ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"ਵੌਲਯੂਮ ਵਿੱਚ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਵਿਖਾਓ"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ਵੌਲਯੂਮ ਡਾਇਲੌਗ ਵਿੱਚ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਦੇ ਪੂਰੇ ਨਿਯੰਤ੍ਰਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ਵੌਲਯੂਮ ਅਤੇ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ਵੌਲਯੂਮ ਘੱਟ ਹੋਣ \'ਤੇ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ਵੌਲਯੂਮ ਕੰਟਰੋਲਾਂ ਨਾਲ ਵਿਖਾਓ"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ਵੌਲਯੂਮ ਬਟਨ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ਵੌਲਯੂਮ ਉੱਚੀ ਹੋਣ \'ਤੇ ਮੈਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
<string name="battery" msgid="7498329822413202973">"ਬੈਟਰੀ"</string>
<string name="clock" msgid="7416090374234785905">"ਘੜੀ"</string>
<string name="headset" msgid="4534219457597457353">"ਹੈੱਡਸੈੱਟ"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ਹੈੱਡਫੋਨਾਂ ਨੂੰ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ਹੈੱਡਸੈੱਟ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"ਚਿੰਨ੍ਹਾਂ ਦੇ ਸਥਿਤੀ ਪੱਟੀ ਵਿੱਚ ਵਿਖਾਏ ਜਾਣ ਨੂੰ ਯੋਗ ਜਾਂ ਅਯੋਗ ਬਣਾਓ।"</string>
<string name="data_saver" msgid="5037565123367048522">"ਡੈਟਾ ਸੇਵਰ"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ਡੈਟਾ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ਡੈਟਾ ਸੇਵਰ ਬੰਦ ਹੈ"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"ਕੀ-ਬੋਰਡ ਬਟਨ ਚੁਣੋ"</string>
<string name="preview" msgid="9077832302472282938">"ਝਲਕ"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ਟਾਇਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘਸੀਟੋ"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"ਸਮਾਂ"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"ਘੰਟੇ, ਮਿੰਟ, ਅਤੇ ਸਕਿੰਟ ਵਿਖਾਓ"</item>
+ <item msgid="1427801730816895300">"ਘੰਟੇ ਅਤੇ ਮਿੰਟ ਵਿਖਾਓ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="3830170141562534721">"ਇਸ ਚਿੰਨ੍ਹ ਨੂੰ ਨਾ ਵਿਖਾਓ"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ਹਮੇਸ਼ਾਂ ਪ੍ਰਤੀਸ਼ਤਤਾ ਵਿਖਾਓ"</item>
+ <item msgid="2139628951880142927">"ਚਾਰਜਿੰਗ ਦੌਰਾਨ ਪ੍ਰਤੀਸ਼ਤਤਾ ਵਿਖਾਓ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
+ <item msgid="3327323682209964956">"ਇਸ ਚਿੰਨ੍ਹ ਨੂੰ ਨਾ ਵਿਖਾਓ"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"ਹੋਰ"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਡਿਵਾਈਡਰ"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ਹੇਠਾਂ ਲੈ ਜਾਓ"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ਉੱਪਰ ਲੈ ਜਾਓ"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ਖੱਬੇ ਲੈ ਜਾਓ"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ਸੱਜੇ ਲੈ ਜਾਓ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a709ed552d05..c9821eea5ed9 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Wykonano zrzut ekranu."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Dotknij, aby wyświetlić zrzut ekranu."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nie udało się wykonać zrzutu ekranu."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Nie można wykonać zrzutu ekranu, bo brak miejsca albo nie zezwala na to aplikacja lub Twoja organizacja."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nie można zapisać zrzutu ekranu, bo brakuje miejsca w pamięci."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Nie możesz wykonać zrzutu ekranu, bo nie zezwala na to aplikacja lub Twoja organizacja."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB – opcje przesyłania plików"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Podłącz jako odtwarzacz multimedialny (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Podłącz jako aparat (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Więcej czasu."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mniej czasu."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Latarka wyłączona."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Latarka włączona."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Latarka została wyłączona."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Latarka została włączona."</string>
@@ -276,7 +279,7 @@
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Przesyłanie"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Przesyłam"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Urządzenie bez nazwy"</string>
- <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Wszystko gotowe do przesyłania"</string>
+ <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gotowy do działania"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Brak dostępnych urządzeń"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"przypinanie ekranu"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacja <xliff:g id="APP">%s</xliff:g> została wyłączona w trybie bezpiecznym."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Wyczyść"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacja nie obsługuje trybu wielu okien"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacja nie obsługuje trybu wielu okien"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Całkowita\ncisza"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tylko\npriorytetowe"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tylko\nalarmy"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Wszystkie"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Wszystkie\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Szybkie ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wolne ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
<string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Włącz przyspieszenie dzielenia ekranu przesunięciem w górę"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Włącz dzielenie ekranu gestem przesunięcia w górę"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Włącz dzielenie ekranu po wykonaniu gestu przesunięcia palcem w górę od przycisku Przegląd"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Włącz"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Zastosuj do powiadomień typu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Zastosuj do wszystkich powiadomień z tej aplikacji"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Zablokowane"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Mało ważne"</string>
<string name="default_importance" msgid="8192107689995742653">"Ważne"</string>
<string name="high_importance" msgid="1527066195614050263">"Bardzo ważne"</string>
<string name="max_importance" msgid="5089005872719563894">"Pilne"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nigdy nie pokazuj tych powiadomień"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Pokazuj na dole listy powiadomień bez sygnału dźwiękowego"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Pokazuj na górze listy powiadomień i sygnalizuj dźwiękiem"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Wyświetlaj na ekranie i odtwarzaj dźwięk"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Kolory standardowe"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Kolory nocne"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Kolory niestandardowe"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatycznie"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Nieznane kolory"</string>
- <string name="color_transform" msgid="6985460408079086090">"Zmiana koloru"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Pokazuj kafelek szybkich ustawień"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Włącz przekształcenie niestandardowe"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Kolor i wygląd"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Tryb nocny"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibracja wyświetlacza"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Wł."</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Wył."</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Włącz automatycznie"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Przełączaj na tryb nocny odpowiednio do lokalizacji i pory dnia"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Gdy jest włączony tryb nocny"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Użyj motywu ciemnego dla Androida"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Dostosuj odcień"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Dostosuj jasność"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Motyw ciemny zostanie zastosowany do głównych obszarów Androida, które normalnie są jasne, takich jak Ustawienia."</string>
<string name="color_apply" msgid="9212602012641034283">"Zastosuj"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Potwierdź ustawienia"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Niektóre ustawienia kolorów mogą utrudniać korzystanie z urządzenia. Kliknij OK, by potwierdzić te ustawienia kolorów. Jeśli tego nie zrobisz, zostaną one zresetowane po 10 sekundach."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Zmniejsza wydajność i ogranicza dane w tle"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekran główny"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Ostatnie"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Wstecz"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Pokaż panel Nie przeszkadzać w oknie sterowania głośnością"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Pokaż cały panel Nie przeszkadzać w oknie sterowania głośnością."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Głośność i tryb Nie przeszkadzać"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Włącz tryb Nie przeszkadzać przy zmniejszaniu głośności"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Pokazuj z regulacją głośności"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nie przeszkadzać"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Wł./wył. przyciskami głośności"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Wyłącz tryb Nie przeszkadzać przy zwiększaniu głośności"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Zegar"</string>
<string name="headset" msgid="4534219457597457353">"Zestaw słuchawkowy"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Słuchawki są podłączone"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Zestaw słuchawkowy jest podłączony"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Włącz lub wyłącz wyświetlanie ikon na pasku stanu."</string>
<string name="data_saver" msgid="5037565123367048522">"Oszczędzanie danych"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Oszczędzanie danych jest włączone"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Oszczędzanie danych jest wyłączone"</string>
<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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Wybierz przycisk klawiatury"</string>
<string name="preview" msgid="9077832302472282938">"Podgląd"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Przeciągnij, aby dodać kafelki"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Edytuj"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Godzina"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Pokazuj godziny, minuty i sekundy"</item>
+ <item msgid="1427801730816895300">"Pokazuj godziny i minuty (domyślnie)"</item>
+ <item msgid="3830170141562534721">"Nie pokazuj tej ikony"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Zawsze pokazuj procent"</item>
+ <item msgid="2139628951880142927">"Pokazuj procent podczas ładowania (domyślnie)"</item>
+ <item msgid="3327323682209964956">"Nie pokazuj tej ikony"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Linia dzielenia ekranu"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Przesuń w dół"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Przesuń w górę"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Przesuń w lewo"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Przesuń w prawo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 796524224568..a15a789cc00f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter a captura de tela."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Não é possível capturar a tela porque não há espaço suficiente ou o app ou organização não permite."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Não é possível salvar a captura de tela, porque não há espaço suficiente."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Capturas de tela não são permitidas pelo app ou por sua organização."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Conectar como media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como uma câmera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
@@ -301,8 +304,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"O app não é compatível com o modo de várias janelas"</string>
<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>
@@ -332,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silêncio\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
@@ -446,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ativar acelerador para dividir a tela ao deslizar para cima"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
<string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações deste app"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
<string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automáticas"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar bloco de configurações rápidas"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrar tela"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Ativado"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desativado"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Ativar automaticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Alternar para o modo noturno conforme apropriado para o local e hora do dia"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Quando o modo noturno está ativado"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como asconfigurações."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
@@ -485,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar \"Não perturbe\" nas opções de volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir controle total do recurso \"Não perturbe\" na caixa de diálogo de volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e \"Não perturbe\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Entre no modo \"Não perturbe\" abaixando o volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Saia do modo \"Não perturbe\" aumentando o volume"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Relógio"</string>
<string name="headset" msgid="4534219457597457353">"Fone de ouvido"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fones de ouvido conectados"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Fone de ouvido conectado"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ativar ou desativar a exibição de ícones na barra de status."</string>
<string name="data_saver" msgid="5037565123367048522">"Economia de dados"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economia de dados ativada"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"A Economia de dados está desativada"</string>
<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>
@@ -521,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Escolha um botão do teclado"</string>
<string name="preview" msgid="9077832302472282938">"Visualização"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar blocos"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Horas"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+ <item msgid="1427801730816895300">"Mostrar horas e minutos (padrão)"</item>
+ <item msgid="3830170141562534721">"Não mostrar este ícone"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Sempre mostrar porcentagem"</item>
+ <item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
+ <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 617e05c5e728..85d4c7953398 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de ecrã efetuada"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para ver a captura de ecrã"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter captura de ecrã."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Imp. tirar capt. ecrã devido ao espaço de armaz. limit. ou isso não é permitido pela aplic. da sua ent."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Não é possível guardar a captura de ecrã devido a espaço de armazenamento limitado."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"A aplicação ou a sua entidade não tem autorização para tirar capturas de ecrã."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opções de transm. de fich. USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Montar como leitor de multimédia (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como câmara (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desligada."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ligada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna desligada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna ligada."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação no ecrã"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Esta aplicação não é compatível com várias janelas"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"A aplicação não é compatível com várias janelas"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silêncio\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Apenas\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Apenas\nalarmes"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"A carregar rapid. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"A carregar lentam. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ativar acelerador de deslize ráp. para cima do ecrã dividido"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto de deslize rápido para cima do ecrã dividido"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativar o gesto para aceder ao ecrã dividido ao deslizar rapidamente para cima a partir do botão Vista geral"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações desta aplicação"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importância alta"</string>
<string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar estas notificações"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações sem som"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificações sem som"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar no ecrã e emitir som"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automáticas"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar o mosaico de Definições rápidas"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspeto"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrar ecrã"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Ativado"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desativado"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Ligar automaticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Alternar para o Modo noturno consoante a localização e a hora do dia"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Quando o Modo noturno está ativado"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Utilizar o tema escuro para o SO Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas essenciais do SO Android que são normalmente apresentadas num tema claro, como as Definições."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar as definições"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algumas definições de cor podem tornar este dispositivo instável. Clique em OK para confirmar estas definições de cor. Caso contrário, estas definições serão repostas após 10 segundos."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados de segundo plano"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Página inicial"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Anterior"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar Não incomodar no volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir o controlo total de Não incomodar na caixa de diálogo do volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e Não incomodar"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Ativar Não incomodar ao diminuir o volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controlos de volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não incomodar"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho dos botões de volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Desativar Não incomodar ao aumentar o volume"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Relógio"</string>
<string name="headset" msgid="4534219457597457353">"Ausc. com microfone integrado"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auscultadores ligados"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auscultadores com microfone integrado ligados"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ativar ou desativar a apresentação de ícones na barra de estado."</string>
<string name="data_saver" msgid="5037565123367048522">"Poupança de dados"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Poupança de dados ativada"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Poupança de dados desativada"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Selecionar o botão do teclado"</string>
<string name="preview" msgid="9077832302472282938">"Pré-visualizar"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar mosaicos"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Hora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+ <item msgid="1427801730816895300">"Mostrar horas e minutos (predefinição)"</item>
+ <item msgid="3830170141562534721">"Não mostrar este ícone"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Mostrar sempre a percentagem"</item>
+ <item msgid="2139628951880142927">"Mostrar a percentagem durante o carregamento (predefinição)"</item>
+ <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divisor do ecrã dividido"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 796524224568..a15a789cc00f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de tela obtida."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Toque para visualizar a captura de tela."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Não foi possível obter a captura de tela."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Não é possível capturar a tela porque não há espaço suficiente ou o app ou organização não permite."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Não é possível salvar a captura de tela, porque não há espaço suficiente."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Capturas de tela não são permitidas pelo app ou por sua organização."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opções transf. arq. por USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Conectar como media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Montar como uma câmera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
@@ -301,8 +304,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"O app não é compatível com o modo de várias janelas"</string>
<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>
@@ -332,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silêncio\ntotal"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Todas\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
@@ -446,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ativar acelerador para dividir a tela ao deslizar para cima"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
<string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações deste app"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
<string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
<string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
<string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automáticas"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar bloco de configurações rápidas"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modo noturno"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrar tela"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Ativado"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Desativado"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Ativar automaticamente"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Alternar para o modo noturno conforme apropriado para o local e hora do dia"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Quando o modo noturno está ativado"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como asconfigurações."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduz o desempenho e os dados em segundo plano"</string>
@@ -485,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Início"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recentes"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Voltar"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Mostrar \"Não perturbe\" nas opções de volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permitir controle total do recurso \"Não perturbe\" na caixa de diálogo de volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume e \"Não perturbe\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Entre no modo \"Não perturbe\" abaixando o volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Mostrar com controles de volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Não perturbe"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Atalho de botões de volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Saia do modo \"Não perturbe\" aumentando o volume"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Relógio"</string>
<string name="headset" msgid="4534219457597457353">"Fone de ouvido"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Fones de ouvido conectados"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Fone de ouvido conectado"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Ativar ou desativar a exibição de ícones na barra de status."</string>
<string name="data_saver" msgid="5037565123367048522">"Economia de dados"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economia de dados ativada"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"A Economia de dados está desativada"</string>
<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>
@@ -521,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Escolha um botão do teclado"</string>
<string name="preview" msgid="9077832302472282938">"Visualização"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Arraste para adicionar blocos"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Horas"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Mostrar horas, minutos e segundos"</item>
+ <item msgid="1427801730816895300">"Mostrar horas e minutos (padrão)"</item>
+ <item msgid="3830170141562534721">"Não mostrar este ícone"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Sempre mostrar porcentagem"</item>
+ <item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
+ <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 26ab25b3c80b..fc1ed2f67ffc 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -21,22 +21,22 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7164937344850004466">"UI sistem"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ștergeți"</string>
- <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminaţi din listă"</string>
+ <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminați din listă"</string>
<string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informații despre aplicație"</string>
<string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ecranele dvs. recente apar aici"</string>
- <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Renunţaţi la aplicațiile recente"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Renunțați la aplicațiile recente"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
<item quantity="few">%d ecrane în Recente</item>
<item quantity="other">%d de ecrane în Recente</item>
<item quantity="one">Un ecran în Recente</item>
</plurals>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nicio notificare"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"În desfăşurare"</string>
+ <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"În desfășurare"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>. Economisirea bateriei este activată."</string>
- <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizaţi numai încărcătorul furnizat."</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizați numai încărcătorul furnizat."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
<string name="battery_low_why" msgid="4553600287639198111">"Setări"</string>
@@ -50,16 +50,16 @@
<string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificări"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
- <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setaţi metode introducere text"</string>
+ <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setați metode introducere text"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastatură fizică"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui accesoriu USB?"</string>
- <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aplic. instal. nu funcţ. cu acest acces. USB. Aflați despre acest accesoriu la <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideți <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Deschideți <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui accesoriu USB?"</string>
+ <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aplic. instal. nu funcț. cu acest acces. USB. Aflați despre acest accesoriu la <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accesoriu USB"</string>
- <string name="label_view" msgid="6304565553218192990">"Afişaţi"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Afișați"</string>
+ <string name="always_use_device" msgid="1450287437017315906">"Utilizați în mod prestabilit pt. acest dispoz. USB"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Permiteți depanarea USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Amprenta digitală din cheia RSA a computerului este:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
@@ -74,10 +74,11 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Captură de ecran realizată."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Atingeți pentru a vedea captura de ecran."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Captura de ecran nu a putut fi realizată."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Captură de ecran impos. de realizat: spațiu de stoc. limitat sau nu este permisă de apl. sau de organiz."</string>
- <string name="usb_preference_title" msgid="6551050377388882787">"Opţiuni pentru transferul de fișiere prin USB"</string>
- <string name="use_mtp_button_title" msgid="4333504413563023626">"Montaţi ca player media (MTP)"</string>
- <string name="use_ptp_button_title" msgid="7517127540301625751">"Montaţi drept cameră foto (PTP)"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Captura de ecran nu poate fi salvată din cauza spațiului de stocare limitat."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Crearea capturilor de ecran nu este permisă de aplicație sau de organizația dvs."</string>
+ <string name="usb_preference_title" msgid="6551050377388882787">"Opțiuni pentru transferul de fișiere prin USB"</string>
+ <string name="use_mtp_button_title" msgid="4333504413563023626">"Montați ca player media (MTP)"</string>
+ <string name="use_ptp_button_title" msgid="7517127540301625751">"Montați drept cameră foto (PTP)"</string>
<string name="installer_cd_button_title" msgid="2312667578562201583">"Instal. aplic. Transfer de fișiere Android pt. Mac"</string>
<string name="accessibility_back" msgid="567011538994429120">"Înapoi"</string>
<string name="accessibility_home" msgid="8217216074895377641">"Ecranul de pornire"</string>
@@ -97,7 +98,7 @@
<string name="recents_caption_resize" msgid="3517056471774958200">"Selectați noul aspect pentru activitate"</string>
<string name="cancel" msgid="6442560571259935130">"Anulați"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
- <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
+ <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceți zoom de la o imagine mai mică la una mai mare."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
<string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Deconectat de la Bluetooth."</string>
<string name="accessibility_no_battery" msgid="358343022352820946">"Nu există baterie."</string>
@@ -157,7 +158,7 @@
<string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificări."</string>
<string name="accessibility_remove_notification" msgid="3603099514902182350">"Ștergeți notificarea."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS activat."</string>
- <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Se obţine GPS."</string>
+ <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Se obține GPS."</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter activat."</string>
<string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Vibrare sonerie."</string>
<string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonerie silențioasă."</string>
@@ -207,6 +208,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mai mult timp."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mai puțin timp."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna este dezactivată."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna este activată."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna este dezactivată."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna este activată."</string>
@@ -302,8 +305,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplicația <xliff:g id="APP">%s</xliff:g> este dezactivată în modul sigur."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Istoric"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Ștergeți"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Această aplicație nu acceptă ferestre multiple"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplicația nu acceptă ferestre multiple"</string>
<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>
@@ -313,8 +319,8 @@
<string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nu se încarcă"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
<string name="description_target_search" msgid="3091587249776033139">"Căutați"</string>
- <string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <string name="description_direction_left" msgid="7207478719805562165">"Glisaţi spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Glisați în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Glisați spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="zen_priority_introduction" msgid="3070506961866919502">"Nu veți fi deranjat(ă) de sunete și vibrații, exceptând alarmele, mementourile, evenimentele și apelanții pe care îi menționați."</string>
<string name="zen_priority_customize_button" msgid="7948043278226955063">"Personalizați"</string>
<string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Această opțiune blochează TOATE sunetele și vibrațiile, inclusiv cele ale alarmelor, muzicii, videoclipurilor și jocurilor. Totuși, veți putea iniția apeluri."</string>
@@ -333,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Niciun\nsunet"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Numai\ncu prioritate"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Numai\nalarme"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Toate"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Toate\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Se încarcă rapid (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Se încarcă lent (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
@@ -447,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
<string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Activați acceleratorul pentru accesarea ecranului împărțit prin glisarea în sus"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activați gestul de accesare a ecranului împărțit prin glisare în sus"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activați gestul de accesare a ecranului împărțit prin glisarea în sus de la butonul Recente"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activați"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Aplicați notificărilor de tip <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Aplicați tuturor notificărilor de la această aplicație"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blocate"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Importanță redusă"</string>
<string name="default_importance" msgid="8192107689995742653">"Importanță normală"</string>
<string name="high_importance" msgid="1527066195614050263">"Importanță ridicată"</string>
<string name="max_importance" msgid="5089005872719563894">"Importanță: urgente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Aceste notificări nu se afișează niciodată"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Aceste notificări se afișează fără a se emite un sunet"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Se afișează în partea de sus a listei cu notificări și se emite un sunet"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Se afișează pentru o scurtă durată pe ecran și se emite un sunet"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
<string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Culori normale"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Culori de noapte"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Culori personalizate"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automat"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Culori necunoscute"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modificarea culorilor"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afișați caseta cu Setările rapide"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Activați transformarea personalizată"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Culoare și aspect"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modul Noapte"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Calibrați afișarea"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Activat"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Dezactivat"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Activați automat"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Comutați la modul Noapte în funcție de locație și de momentul zilei"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Când modul Noapte este activat"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Folosiți tema întunecată pentru SO Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Ajustați culoarea"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Ajustați luminozitatea"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema întunecată se aplică zonelor principale ale sistemului de operare Android care sunt de obicei afișate cu o temă deschisă la culoare, cum ar fi Setările."</string>
<string name="color_apply" msgid="9212602012641034283">"Aplicați"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Confirmați setările"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Unele setări pentru culori pot face dispozitivul să nu mai funcționeze. Dați clic pe OK pentru a confirma aceste setări pentru culori. În caz contrar, acestea se vor reseta după 10 secunde."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Baterie (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce performanța și datele de fundal"</string>
@@ -486,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ecran de pornire"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Recente"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Înapoi"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Afișați opțiunile pentru Nu deranjați în dialogul de volum"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Permiteți controlul complet al modului Nu deranjați din dialogul pentru volum."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumul și Nu deranjați"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Accesați Nu deranjați la reducerea volumului"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Afișează cu comenzile de volum"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nu deranja"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Comandă rapidă din butoanele de volum"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Ieșiți din Nu deranjați la creșterea volumului"</string>
<string name="battery" msgid="7498329822413202973">"Baterie"</string>
<string name="clock" msgid="7416090374234785905">"Ceas"</string>
<string name="headset" msgid="4534219457597457353">"Set căști-microfon"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Căștile sunt conectate"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Setul căști-microfon este conectat"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Activați sau dezactivați afișarea pictogramelor în bara de stare."</string>
<string name="data_saver" msgid="5037565123367048522">"Economizor de date"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizorul de date este activat"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizorul de date este dezactivat"</string>
<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>
@@ -510,7 +533,7 @@
<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="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>
@@ -522,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Selectați butonul de la tastatură"</string>
<string name="preview" msgid="9077832302472282938">"Previzualizare"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Trageți pentru a adăuga sectoare"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Editați"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Oră"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Afișează orele, minutele și secundele"</item>
+ <item msgid="1427801730816895300">"Afișează orele și minutele (prestabilit)"</item>
+ <item msgid="3830170141562534721">"Nu afișa această pictogramă"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Afișează întotdeauna procentajul"</item>
+ <item msgid="2139628951880142927">"Afișează procentajul când se încarcă (prestabilit)"</item>
+ <item msgid="3327323682209964956">"Nu afișa această pictogramă"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Separator pentru ecranul împărțit"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mutați în jos"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mutați în sus"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mutați spre stânga"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mutați spre dreapta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0021827ebb64..5340d95ded54 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сохранен"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Нажмите, чтобы просмотреть"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Не удалось сохранить скриншот."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Не удается сделать скриншот: не хватает памяти или нет разрешения от приложения или организации."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Не удалось сохранить скриншот: недостаточно места."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Параметры передачи через USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Подключить как мультимедийный проигрыватель (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Установить как камеру (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Увеличить время."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Уменьшить время."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фонарик отключен."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фонарик включен."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фонарик отключен."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фонарик включен."</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Заблокировать в приложении"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" отключено в безопасном режиме."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Журнал"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Очистить"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Приложение не поддерживает многооконный режим"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Приложение не поддерживает многооконный режим"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Полная\nтишина"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Только\nважные"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Только\nбудильник"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Все"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Все\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Быстрая зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Медленная зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
<string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Разделять экран пролистыванием вверх"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделять экран пролистыванием вверх"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Включить разделение экрана пролистыванием вверх с кнопки \"Обзор\""</string>
<string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включить"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Применить к уведомлениям на тему \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
- <string name="apply_to_app" msgid="363016783939815960">"Применить ко всем уведомлениям этого приложения"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Блокировка"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Низкая важность"</string>
<string name="default_importance" msgid="8192107689995742653">"Средняя важность"</string>
<string name="high_importance" msgid="1527066195614050263">"Высокая важность"</string>
<string name="max_importance" msgid="5089005872719563894">"Крайняя важность"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Не показывать эти уведомления."</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Показывать без звука в конце списка уведомлений."</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Показывать уведомления без звука."</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Показывать со звуком в начале списка уведомлений."</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Показывать со звуком поверх всех окон."</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Обычные цвета"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Ночные цвета"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Собственные цвета"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Неизвестные цвета"</string>
- <string name="color_transform" msgid="6985460408079086090">"Цветовые настройки"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показывать панель быстрых настроек"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Включить собственные настройки"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Цвета и стиль"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Ночной режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Калибровка дисплея"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Включен"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Отключен"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Включать автоматически"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Включать ночной режим с учетом местоположения и времени суток"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"В ночном режиме"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Использовать темное оформление для Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Изменять оттенок"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Яркость"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Темное оформление применяется к основным элементам системы Android (таким, как приложение \"Настройки\"), которые обычно показываются в светлом."</string>
<string name="color_apply" msgid="9212602012641034283">"Применить"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Подтвердите настройки"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Некоторые цветовые настройки могут затруднить работу с устройством. Чтобы применить выбранные параметры, нажмите \"ОК\". В противном случае они будут сброшены через 10 секунд."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Батарея (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Ограничивает производительность и фоновую передачу данных"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Главный экран"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавние"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Показать панель \"Не беспокоить\" в окне регулировки звука"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Позволяет управлять режимом \"Не беспокоить\" в окне регулировки громкости."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Регулировка громкости и режим \"Не беспокоить\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Включать режим \"Не беспокоить\" при уменьшении громкости"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показывать при нажатии кнопок регулировки громкости"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не беспокоить"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки регулировки громкости"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Отключать режим \"Не беспокоить\" при увеличении громкости"</string>
<string name="battery" msgid="7498329822413202973">"Батарея"</string>
<string name="clock" msgid="7416090374234785905">"Часы"</string>
<string name="headset" msgid="4534219457597457353">"Гарнитура"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Наушники подключены"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнитура подключена"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Включение и отключение показа значков в строке состояния"</string>
<string name="data_saver" msgid="5037565123367048522">"Экономия трафика"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Режим экономии трафика включен"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Режим экономии трафика отключен"</string>
<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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Выберите клавишу"</string>
<string name="preview" msgid="9077832302472282938">"Просмотр"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Перетащите нужные элементы"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Изменить"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Время"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Часы, минуты и секунды"</item>
+ <item msgid="1427801730816895300">"Часы и минуты (по умолчанию)"</item>
+ <item msgid="3830170141562534721">"Не показывать этот значок"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Всегда показывать процент заряда"</item>
+ <item msgid="2139628951880142927">"Показывать процент во время зарядки (по умолчанию)"</item>
+ <item msgid="3327323682209964956">"Не показывать этот значок"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Разделитель экрана"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Опустить"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Поднять"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Сдвинуть влево"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Сдвинуть вправо"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index da6de9ca4c6a..b4853201b1ae 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"තිර රුව ග්‍රහණය කරන ලදි."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"ඔබගේ තිර රුව බැලීමට ස්පර්ශ කරන්න."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"තිර රුව ග්‍රහණය කිරීමට නොහැකි විය."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"සීමිත ආචයනය ඉඩ හේතුවෙන් තිර රුව ලබාගත නොහැක, හෝ ඔබගේ යෙදුම හෝ ඔබගේ සංවිධානය විසින් එය ඉඩ නොදී තිබේ."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"සීමිත ගබඩා ඉඩ නිසා තිර රුව සුරැකිය නොහැකිය."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"තිර රූ ගැනීමට යෙදුම හෝ ඔබගේ සංවිධානය ඉඩ නොදේ."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ගොනු හුවමාරු විකල්ප"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"මධ්‍ය ධාවකයක් (MTP) ලෙස සවි කරන්න"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"කැමරාවක් (PTP) ලෙස සවි කරන්න"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"වේලාව වැඩියෙන්."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"වේලාව අඩුවෙන්."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"සැණෙළි ආලෝකය අක්‍රිය කරන ලදි."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"සැණෙළි ආලෝකය ලබා ගත නොහැකිය."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"සැණෙළි ආලෝකය සක්‍රිය කරන ලදි."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"සැණෙළි ආලෝකය අක්‍රිය කරන ලදි."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"සැණෙළි ආලෝකය සක්‍රිය කරන ලදි."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"තිර ඇමිණීම"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ආරක්ෂිත ප්‍රකාරය තුළ අබලයි."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ඉතිහාසය"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"හිස් කරන්න"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"මෙම යෙදුම බහු-කවුළුව සඳහා සහාය නොදක්වයි"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"යෙදුම බහු-කවුළුව සඳහා සහාය නොදක්වයි"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"සම්පූර්ණ\nනිහඬතාව"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්‍රමුඛතා\nපමණි"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"සියලු"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"සියලු\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ඉක්මනින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"සෙමින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
<string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"බෙදුම්-තිර ඉහළට-ස්වයිප් කිරීමේ ත්වරකය සබල කරන්න"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"බෙදුම්-තිරය ඉහළට-ස්වයිප් කිරීමේ අභිනය සබල කරන්න"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"දළ විශ්ලේෂණ බොත්තම හරහා ඉහළට ස්වයිප් කිරීමෙන් බෙදුම් තිරයට ඇතුළු වීමට ඉඟිය සබල කිරීම"</string>
<string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්‍රියාත්මක කරන්නද?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්‍රියාත්මක කළ යුතුය."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ක්‍රියාත්මක කරන්න"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> දැනුම්දීම් වෙත යොදන්න"</string>
- <string name="apply_to_app" msgid="363016783939815960">"මෙම යෙදුම වෙතින් වන සියලු දැනුම්දීම් සඳහා යොදන්න"</string>
+ <string name="show_silently" msgid="6841966539811264192">"නිශ්ශබ්දව දැනුම්දීම් පෙන්වන්න"</string>
+ <string name="block" msgid="2734508760962682611">"සියලු දැනුම්දීම් අවහිර කරන්න"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"නිශ්ශබ්ද නොකරන්න"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"නිශ්ශබ්ද හෝ අවහිර නොකරන්න"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"පූර්ණ වැදගත්කම් සැකසීම් පෙන්වන්න"</string>
<string name="blocked_importance" msgid="5198578988978234161">"අවහිර කරන ලදි"</string>
+ <string name="min_importance" msgid="1901894910809414782">"අවම වැදගත්කම"</string>
<string name="low_importance" msgid="4109929986107147930">"අඩු වැදගත්කම"</string>
<string name="default_importance" msgid="8192107689995742653">"සාමාන්‍ය වැදගත්කම"</string>
<string name="high_importance" msgid="1527066195614050263">"වැඩි වැදගත්කම"</string>
<string name="max_importance" msgid="5089005872719563894">"හදිසි වැදගත්කම"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"මෙම දැනුම්දීම් කිසිදා නොපෙන්වන්න"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න සහ ශබ්ද කරන්න"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"තිරයට පැමිණ ශබ්ද කරන්න"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"මෙම දැනුම්දීම්වලට ශබ්ද නැගීමට ඉඩ දෙන්න"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"තිරයට එබිකම් කර ශබ්දයට ඉඩ දෙන්න සහ ශබ්දයට ඉඩ දෙන්න"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න, තිරයට එබිකම් කර ශබ්දයට ඉඩ දෙන්න"</string>
<string name="notification_more_settings" msgid="816306283396553571">"තව සැකසීම්"</string>
<string name="notification_done" msgid="5279426047273930175">"නිමයි"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"සාමාන්‍ය වර්ණ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"රාත්‍රී වර්ණ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"අභිරුචි වර්ණ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"ස්වයංක්‍රිය"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"නොදන්නා වර්ණ"</string>
- <string name="color_transform" msgid="6985460408079086090">"වර්ණ වෙනස් කිරීම"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"ඉක්මන් සැකසීම් ටයිලය පෙන්වන්න"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"අභිරුචි පරිවර්තනය සබල කරන්න"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"වර්ණය සහ පෙනුම"</string>
+ <string name="night_mode" msgid="3540405868248625488">"රාත්‍රී ප්‍රකාරය"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"සංදර්ශකය ක්‍රමාංකනය කරන්න"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ක්‍රියාත්මකයි"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ක්‍රියාවිරහිතයි"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"ස්වයංක්‍රියව ක්‍රියාත්මක කරන්න"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"ස්ථානය සහ දවසේ වේලාවට ගැළපෙන ලෙස රාත්‍රී ප්‍රකාරයට මාරු වන්න"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"රාත්‍රී ප්‍රකාරය ක්‍රියාත්මක විට"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS සඳහා අඳුරු තේමාව භාවිත කරන්න"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"පැහැය සීරුමාරු කරන්න"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"දීප්තිය සීරුමාරු කරන්න"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"සැකසීම් වැනි, සාමාන්‍යයෙන් ලා පැහැ තේමාවක සංදර්ශනය වන Android OS හි මූලික ප්‍රදේශවලට අඳුරු තේමාව යෙදේ."</string>
<string name="color_apply" msgid="9212602012641034283">"යොදන්න"</string>
<string name="color_revert_title" msgid="4746666545480534663">"සැකසීම් තහවුරු කරන්න"</string>
<string name="color_revert_message" msgid="9116001069397996691">"සමහර වර්ණ සැකසීම් මෙම උපාංගය භාවිත කළ නොහැකි තත්ත්වයට පත් කළ හැකිය. මෙම වර්ණ සැකසීම් තහවුරු කිරීමට හරි ක්ලික් කරන්න, නැතහොත් මෙම සැකසීම් තත්පර 10කට පසුව යළි සකසනු ඇත."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"බැටරිය (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ක්‍රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"මුල් පිටුව"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"මෑත"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"ආපසු"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"හඩ පරිමාව තුළ බාධා නොකරන්න පුවරුව පෙන්වන්න"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"හඬ පරිමා සංවාදය තුළ බාධා නොකරන්න පුවරුවට පූර්ණ පාලනය ඉඩ දෙන්න."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"හඬ පරිමාව සහ බාධා නොකරන්න"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"හඬ පරිමාව අඩු කරන්න මත බාධා නොකරන්න වෙත ඇතුළු වන්න"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"හඩ පරිමා පාලන සහිතව පෙන්වන්න"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"බාධා නොකරන්න"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"හඩ පරිමා බොත්තම් කෙටිමග"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"හඬ පරිමාව වැඩි කරන්න මත බාධා නොකරන්න වෙතින් ඉවත් වන්න"</string>
<string name="battery" msgid="7498329822413202973">"බැටරිය"</string>
<string name="clock" msgid="7416090374234785905">"ඔරලෝසුව"</string>
<string name="headset" msgid="4534219457597457353">"හෙඩ්සෙට්"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"හෙඩ්ෆෝන් සම්බන්ධ කළ"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"හෙඩ්සෙට් සම්බන්ධ කළ"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"තත්ත්ව තීරුව මත අයිකන පෙන්වීම සබල හෝ අබල කරන්න."</string>
<string name="data_saver" msgid="5037565123367048522">"දත්ත සුරැකුම"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"දත්ත සුරැකුම ක්‍රියාත්මකයි"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"දත්ත සුරැකුම ක්‍රියාවිරහිතයි"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"යතුරු පුවරු බොත්තම තෝරන්න"</string>
<string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය කරන්න"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"වේලාව"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"පැය, මිනිත්තු, සහ තත්පර පෙන්වන්න"</item>
+ <item msgid="1427801730816895300">"පැය සහ මිනිත්තු පෙන්වන්න (පෙරනිමි)"</item>
+ <item msgid="3830170141562534721">"මෙම නිරූපකය නොපෙන්වන්න"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"සෑම විටම ප්‍රතිශතය පෙන්වන්න"</item>
+ <item msgid="2139628951880142927">"ආරෝපණය වන විට ප්‍රතිශතය පෙන්වන්න (පෙරනිමි)"</item>
+ <item msgid="3327323682209964956">"මෙම නිරූපකය නොපෙන්වන්න"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"වෙනත්"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"බෙදුම්-තිර වෙන්කරණය"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"පහළට ගෙන යන්න"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ඉහළට ගෙන යන්න"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"වමට ගෙන යන්න"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"දකුණට ගෙන යන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 62f6b892999d..446590f3b61c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Snímku obrazovky zobrazíte dotykom."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Nie je možné vytvoriť viac sním. obraz. pre obmedz. úlož. priestor alebo to nie je povolené apl. či vašou organiz."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta na úložisku."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Pripojiť ako fotoaparát (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Dlhší čas"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší čas"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svietidlo je vypnuté."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svietidlo je zapnuté."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svietidlo je vypnuté."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svietidlo je zapnuté."</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripnutie k obrazovke"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikácia <xliff:g id="APP">%s</xliff:g> je v núdzovom režime zakázaná."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"História"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Vymazať"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Táto aplikácia nepodporuje režim viacerých okien"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikácia nepodporuje režim viacerých okien"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Úplné\nticho"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Iba\nprioritné"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Iba\nbudíky"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Všetky"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Všetky\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nabíja sa rýchlo (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Nabíja sa pomaly (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
<string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovať rozdelenú obrazovku prejdením prstom nahor od tlačidla Prehľad"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnúť"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Použiť na upozornenia týkajúce sa témy <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Použiť na všetky upozornenia z tejto aplikácie"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Zablokované"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Nízka dôležitosť"</string>
<string name="default_importance" msgid="8192107689995742653">"Normálna dôležitosť"</string>
<string name="high_importance" msgid="1527066195614050263">"Vysoká dôležitosť"</string>
<string name="max_importance" msgid="5089005872719563894">"Neodkladná dôležitosť"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Tieto upozornenia nikdy nezobrazovať"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Zobrazovať v hornej časti zoznamu upozornení so zvukovým signálom"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Zobrazovať cez obrazovku so zvukovým signálom"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normálne farby"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nočné farby"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastné farby"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatické"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznáme farby"</string>
- <string name="color_transform" msgid="6985460408079086090">"Úprava farieb"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Zobraziť dlaždicu Rýchle nastavenia"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Povoliť vlastnú transformáciu"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Farba a vzhľad"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nočný režim"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrovať obrazovku"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Zapnutý"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Vypnutý"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Zapínať automaticky"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Prepnúť do Nočného režimu podľa miesta a času dňa"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Keď je zapnutý Nočný režim"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Použiť tmavý motív pre systém Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Upraviť tónovanie"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Upraviť jas"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavných oblastiach systému Android OS (ako sú Nastavenia), ktoré sú obyčajne zobrazené v svetlom motíve, je použitý tmavý motív."</string>
<string name="color_apply" msgid="9212602012641034283">"Použiť"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Potvrdenie nastavení"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Niektoré nastavenia farieb môžu toto zariadenie znefunkčniť. Tieto nastavenia farieb potvrdíte kliknutím na tlačidlo OK, ináč sa tieto nastavenia o 10 sekúnd obnovia."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batéria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Obmedzí výkonnosť a údaje na pozadí"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Domovská stránka"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedávne"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Späť"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Zobrazovať panel Nerušiť v dialógu Hlasitosť"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Umožňuje povoliť úplné ovládanie režimu nerušiť v dialógu Hlasitosť."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Hlasitosť a režim Nerušiť"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Pri znížení hlasitosti prejsť do režimu Nerušiť"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Zobrazovať s ovládacími prvkami hlasitosti"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Nerušiť"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Skratka tlačidiel hlasitosti"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Pri zvýšení hlasitosti ukončiť režim Nerušiť"</string>
<string name="battery" msgid="7498329822413202973">"Batéria"</string>
<string name="clock" msgid="7416090374234785905">"Hodiny"</string>
<string name="headset" msgid="4534219457597457353">"Náhlavná súprava"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slúchadlá pripojené"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Náhlavná súprava pripojená"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Umožňuje aktivovať alebo deaktivovať zobrazenie ikon v stavovom riadku."</string>
<string name="data_saver" msgid="5037565123367048522">"Šetrič dát"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Šetrič dát je zapnutý"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Šetrič dát je vypnutý"</string>
<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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Výber tlačidla klávesnice"</string>
<string name="preview" msgid="9077832302472282938">"Ukážka"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Dlaždice pridáte presunutím"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Upraviť"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Čas"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Zobrazovať hodiny, minúty a sekundy"</item>
+ <item msgid="1427801730816895300">"Zobrazovať hodiny a minúty (predvolené)"</item>
+ <item msgid="3830170141562534721">"Nezobrazovať túto ikonu"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Vždy zobrazovať percentá"</item>
+ <item msgid="2139628951880142927">"Zobrazovať percentá počas nabíjania (predvolené)"</item>
+ <item msgid="3327323682209964956">"Nezobrazovať túto ikonu"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Rozdeľovač obrazovky"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Posunúť nadol"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Posunúť nahor"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Posunúť doľava"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Posunúť doprava"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 7e44fb0eed13..756c43df4e45 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Posnetek zaslona je shranjen."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Dotaknite se, če si želite ogledati posnetek zaslona."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Posnetka zaslona ni bilo mogoče shraniti."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Izdelava posnetka zaslona ni mogoča zaradi omejenega prostora za shranjevanje ali pa tega ne dovoli aplikacija ali vaša organizacija."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Shranjevanje posnetka zaslona ni mogoče zaradi omejenega prostora za shranjevanje."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Aplikacija ali organizacija ne dovoljuje posnetkov zaslona."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosa datotek prek USB-ja"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Vpni kot predvajalnik (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Vpni kot fotoaparat (PTP)"</string>
@@ -208,6 +209,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daljši čas."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Krajši čas."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svetilka je izklopljena."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svetilka ni na voljo."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svetilka je vklopljena."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svetilka je izklopljena."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svetilka je vklopljena."</string>
@@ -303,8 +305,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripenjanje zaslona"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je v varnem načinu onemogočena."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Zgodovina"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podpira načina z več okni"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacija ne podpira načina z več okni"</string>
<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>
@@ -334,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Popolna\ntišina"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprednostno"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Vse"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Vse\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hitro polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Počasno polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
@@ -448,38 +451,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
<string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Omogočanje pospeš. za razdeljeni zaslon z vlečenjem navzgor"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za zagon razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogočanje poteze za razdeljen zaslon z vlečenjem navzgor"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za vklop razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
<string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vklop"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Uporabi za obvestila za temo <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Uporabi za vsa obvestila za to aplikacijo"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Prikaži obvestila brez zvoka"</string>
+ <string name="block" msgid="2734508760962682611">"Blokiraj vsa obvestila"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Ne utišaj"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Ne utišaj ali blokiraj"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaz celotnih nastavitev za pomembnost"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Najmanjša pomembnost"</string>
<string name="low_importance" msgid="4109929986107147930">"Nizka pomembnost"</string>
<string name="default_importance" msgid="8192107689995742653">"Običajna pomembnost"</string>
<string name="high_importance" msgid="1527066195614050263">"Visoka pomembnost"</string>
<string name="max_importance" msgid="5089005872719563894">"Nujna pomembnost"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Nikoli ne prikaži teh obvestil"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Prikaži na dnu seznama obvestil brez zvoka"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži ta obvestila brez zvoka"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu seznama obvestil in predvajaj zvok"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Za hip pokaži predogled na zaslonu in predvajaj zvok"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Prikaži na dnu seznama obvestil brez zvoka"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Prikaži ta obvestila brez zvoka"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Dovoli zvoke za ta obvestila"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Za hip pokaži predogled na zaslonu in dovoli zvok"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu seznama obvestil, za hip pokaži predogled na zaslonu in dovoli zvok"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
<string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Običajne barve"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nočne barve"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Barve po meri"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Samodejno"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznane barve"</string>
- <string name="color_transform" msgid="6985460408079086090">"Spreminjanje barv"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaz ploščice s hitrimi nastavitvami"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Omogočanje spremembe po meri"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Barva in videz"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nočni način"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Umerjanje zaslona"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Vklopljeno"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Izklopljeno"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Samodejni vklop"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Preklop v nočni način, kot je ustrezno glede na lokacijo in uro v dnevu"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Ko je vklopljen nočni način"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Uporaba temne teme za sistem Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Prilagodi odtenek"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Prilagodi svetlost"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Za osrednja področja sistema Android, ki so običajno prikazana v svetli temi, na primer nastavitve, je uporabljena temna tema."</string>
<string name="color_apply" msgid="9212602012641034283">"Uporabi"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Potrditev nastavitev"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Zaradi nekaterih barvnih nastavitev lahko postane ta naprava neuporabna. Kliknite »V redu«, če želite potrditi te barvne nastavitve. V nasprotnem primeru se bodo čez 10 sekund ponastavile na prvotno vrednost."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Akumulator (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
@@ -487,21 +499,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Začetni zaslon"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Nedavni"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nazaj"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Pokaži način »ne moti« v nadzoru glasnosti"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Omogoča popoln nadzor načina »ne moti« v pogovornem oknu za glasnost."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Nadzor glasnosti in način »ne moti«"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Odpiranje načina »ne moti« pri zmanjšanju glasnosti"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikaži s kontrolniki glasnosti"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne moti"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Bližnjica z gumboma za glasnost"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Zapustitev načina »ne moti« pri povečanju glasnosti"</string>
<string name="battery" msgid="7498329822413202973">"Akumulator"</string>
<string name="clock" msgid="7416090374234785905">"Ura"</string>
<string name="headset" msgid="4534219457597457353">"Slušalke z mikrofonom"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Slušalke priključene"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Slušalke z mikrofonom priključene"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Omogoči ali onemogoči prikaz ikon v vrstici stanja."</string>
<string name="data_saver" msgid="5037565123367048522">"Varčevanje s podatki"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Varčevanje s podatki je vklopljeno"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Varčevanje s podatki je izklopljeno"</string>
<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>
@@ -523,4 +534,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Izbira gumba tipkovnice"</string>
<string name="preview" msgid="9077832302472282938">"Predogled"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Povlecite, če želite dodati ploščice"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Ura"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Prikaži ure, minute in sekunde"</item>
+ <item msgid="1427801730816895300">"Prikaži ure in minute (privzeto)"</item>
+ <item msgid="3830170141562534721">"Ne prikaži te ikone"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Vedno prikaži odstotek"</item>
+ <item msgid="2139628951880142927">"Prikaži odstotek med polnjenjem (privzeto)"</item>
+ <item msgid="3327323682209964956">"Ne prikaži te ikone"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Drugo"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Razdelilnik zaslonov"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Premakni navzdol"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Premakni navzgor"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Premakni levo"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Premakni desno"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index d679a58f67d0..8b3861e6972c 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Pamja e ekranit u kap."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Prek për të parë pamjen e ekranit tënd."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Nuk mundi të kapte pamjen e ekranit."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Nuk pranon pamje ekrani për shkak të hapësirës së kufizuar ruajtëse, ose një gjë e tillë nuk lejohet nga aplikacioni apo organizata jote."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Pamja e ekranit nuk mund të ruhet për shkak të hapësirës ruajtëse të kufizuar."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Nxjerrja e pamjeve të ekranit nuk lejohet nga aplikacioni ose organizata jote."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opsionet e transferimit të dosjeve të USB-së"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Lidh si një lexues \"media\" (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Montoje si kamerë (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Më shumë kohë."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Më pak kohë."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Elektriku është i çaktivizuar."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Blici është i padisponueshëm"</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Elektriku u aktivizua."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Elektriku u çaktivizua."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Elektriku është i aktivizuar."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"gozhdimi i ekranit"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"kërko"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nuk mundi të nisej."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> është i çaktivizuar në modalitetin e sigurt."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historiku"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Pastro"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ky aplikacion nuk e mbështet modalitetin me shumë dritare"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikacioni nuk e mbështet modalitetin me shumë dritare"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Heshtje\ne plotë"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vetëm\nme prioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vetëm\nalarmet"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Të gjitha"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Të gjitha\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Po ngarkohet (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> deri sa të mbushet)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Po ngarkon me shpejtësi (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Po ngarkon me ngadalë (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
<string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivizo përshpejtuesin e rrëshqitjes lart për ekranin e ndarë"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivizo gjestin e rrëshqitjes lart për ekranin e ndarë"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivizo gjestin për të hyrë tek ekrani i ndarë duke rrëshqitur lart nga butoni \"Përmbledhja\""</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivizo"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Zbatoje për njoftimet nga <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Zbatoje për të gjitha njoftimet nga ky aplikacion"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Shfaqi njoftimet në heshtje"</string>
+ <string name="block" msgid="2734508760962682611">"Blloko të gjitha njoftimet"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Mos e vendos në heshtje"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Mos e vendos në heshtje ose mos e blloko"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Shfaq cilësimet e plota të rëndësisë"</string>
<string name="blocked_importance" msgid="5198578988978234161">"I bllokuar"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Rëndësi minimale"</string>
<string name="low_importance" msgid="4109929986107147930">"Rëndësi e ulët"</string>
<string name="default_importance" msgid="8192107689995742653">"Rëndësi normale"</string>
<string name="high_importance" msgid="1527066195614050263">"Rëndësi e lartë"</string>
<string name="max_importance" msgid="5089005872719563894">"Rëndësi urgjente"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Mos i shfaq asnjëherë këto njoftime"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Shfaqi në heshtje në fund të listës së njoftimeve"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Shfaqi këto njoftime në heshtje"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Shfaqi në krye të listës së njoftimeve dhe lësho tingull"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Shfaq një vështrim të shpejtë në ekran dhe lësho tingull"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Shfaqi në heshtje në fund të listës së njoftimeve"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Shfaqi këto njoftime në heshtje"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Lejoji këto njoftime të nxjerrin tinguj"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Shfaq një vështrim të shpejtë në ekran dhe lësho një tingull"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Shfaqi në krye të listës së njoftimeve, shfaq vështrim të shpejtë në ekran dhe lësho një tingull"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
<string name="notification_done" msgid="5279426047273930175">"U krye"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Ngjyrat normale"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Ngjyrat e natës"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Ngjyrat e personalizuara"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatike"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Ngjyra të panjohura"</string>
- <string name="color_transform" msgid="6985460408079086090">"Modifikimi i ngjyrës"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Pllakëza Shfaq cilësimet e shpejta"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Zbato transformimin e personalizuar"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Ngjyra dhe pamja"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Modaliteti i natës"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibro ekranin"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aktiv"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Joaktiv"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Aktivizoje automatikisht"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Kalo në \"Modalitetin e natës\" sipas përshtatshmërisë për vendin dhe kohën e ditës"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kur \"Modaliteti i natës\" është aktiv"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Përdor temën e errët për Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Rregullo nuancën"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Rregullo ndriçimin"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Tema e errët zbatohet në zonat kryesore të Android OS që shfaqen zakonisht në një temë të çelur, siç janë \"Cilësimet\"."</string>
<string name="color_apply" msgid="9212602012641034283">"Zbato"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Konfirmo cilësimet"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Disa cilësime ngjyrash mund ta bëjnë këtë pajisje të papërdorshme. Kliko OK për të konfirmuar këto cilësime ngjyrash, përndryshe këto cilësime do të rivendosen pas 10 sekondash."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Kreu"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Të fundit"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Prapa"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Shfaq \"Mos shqetëso\" te volumi"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Lejo kontrollin e plotë të opsionit \"Mos shqetëso\" në dialogun e volumit."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volumi dhe \"Mos shqetëso\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Vendos \"Mos shqetëso\" me volumin poshtë"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Shfaq me kontrollet e volumit"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Mos shqetëso"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Shkurtorja e butonave të volumit"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Dil nga \"Mos shqetëso\" me volumin lart"</string>
<string name="battery" msgid="7498329822413202973">"Bateria"</string>
<string name="clock" msgid="7416090374234785905">"Ora"</string>
<string name="headset" msgid="4534219457597457353">"Kufjet me mikrofon"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Kufjet u lidhën"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Kufjet me mikrofon u lidhën"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Aktivizo ose çaktivizo shfaqjen e ikonave në shiritin e statusit."</string>
<string name="data_saver" msgid="5037565123367048522">"Kursyesi i të dhënave"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Kursyesi i të dhënave është aktiv"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Kursyesi i të dhënave është joaktiv"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Zgjidh butonin e tastierës"</string>
<string name="preview" msgid="9077832302472282938">"Pamja paraprake"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Zvarrit për të shtuar pllakëzat"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Redakto"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Ora"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Shfaq orët, minutat dhe sekondat"</item>
+ <item msgid="1427801730816895300">"Shfaq orët dhe minutat (e parazgjedhur)"</item>
+ <item msgid="3830170141562534721">"Mos e shfaq këtë ikonë"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Shfaq gjithmonë përqindjen"</item>
+ <item msgid="2139628951880142927">"Shfaq përqindjen gjatë ngarkimit (e parazgjedhur)"</item>
+ <item msgid="3327323682209964956">"Mos e shfaq këtë ikonë"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Të tjera"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Ndarësi i ekranit të ndarë"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Lëviz poshtë"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Lëviz lart"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Lëviz majtas"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Lëviz djathtas"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index fe3d12122c38..327e55336b8a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -74,7 +74,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Снимак екрана је направљен."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Додирните да бисте видели снимак екрана."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Није могуће направити снимак екрана."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Није могуће снимити екран због недовољне меморије или то не дозвољава апликација или организација."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Чување снимка екрана није успело због ограниченог меморијског простора."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Апликација или организација не дозвољавају прављење снимака екрана."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Опције USB преноса датотека"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Прикључи као медија плејер (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Прикључи као камеру (PTP)"</string>
@@ -207,6 +208,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Више времена."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Мање времена."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Батеријска лампа је искључена."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Батеријска лампа је укључена."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Батеријска лампа је искључена."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Батеријска лампа је укључена."</string>
@@ -302,8 +305,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"качење екрана"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Апликација <xliff:g id="APP">%s</xliff:g> је онемогућена у безбедном режиму."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Историја"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Обриши"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ова апликација не подржава режим са више прозора"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Апликација не подржава режим са више прозора"</string>
<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>
@@ -333,8 +339,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Потпуна\nтишина"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприорит. прекиди"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Све"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Сви\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Споро се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -447,38 +451,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
<string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Омогући убрзавач за превлачење нагоре за подељени екран"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Омогући покрет за превлачење нагоре за подељени екран"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Омогућава покрет за прелазак на подељени екран превлачењем нагоре од дугмета Преглед"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Укључи"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Примени на обавештења о теми <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Примени на сва обавештења из ове апликације"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Блокирана"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
<string name="default_importance" msgid="8192107689995742653">"Уобичајена важност"</string>
<string name="high_importance" msgid="1527066195614050263">"Велика важност"</string>
<string name="max_importance" msgid="5089005872719563894">"Важност: хитно"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ова обавештења се никада не приказују"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Приказују се у дну листе обавештења без звука"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Ова обавештења се приказују без звука"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Приказују се у врху листе обавештења и емитује се звук"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Накратко се приказују на екрану и емитује се звук"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Нормалне боје"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Ноћне боје"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Прилагођене боје"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Аутоматски"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Непознате боје"</string>
- <string name="color_transform" msgid="6985460408079086090">"Измена боја"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Прикажи плочицу Брза подешавања"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Омогући прилагођену трансформацију"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Ноћни режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Калибришите екран"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Укључено"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Искључено"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Аутоматски укључи"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Пређите на ноћни режим у зависности од локације и доба дана"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Када је ноћни режим укључен"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Користи тамну тему за Android ОС"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Прилагоди сенку"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Прилагоди осветљеност"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Тамна тема се примењује на кључне делове Android ОС-а који се обично приказују у светлој теми, попут Подешавања."</string>
<string name="color_apply" msgid="9212602012641034283">"Примени"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Потврдите подешавања"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Нека подешавања боја могу да учине уређај неупотребљивим. Кликните на Потврди да бисте потврдили ова подешавања боја, пошто ће се у супротном ова подешавања ресетовати након 10 секунди."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Батерија (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Смањује перформансе и позадинске податке"</string>
@@ -486,21 +510,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Почетни"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Недавни садржај"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Прикажи подешавање Не узнемиравај у дијалогу за јачину звука"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дозвољава потпуну контролу подешавања Не узнемиравај у дијалогу за јачину звука."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Јачина звука и Не узнемиравај"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Уђи у режим Не узнемиравај када је звук утишан"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Прикажи са контролама јачине звука"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не узнемиравај"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Пречица за дугмад за јачину звука"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Изађи из режима Не узнемиравај када је звук појачан"</string>
<string name="battery" msgid="7498329822413202973">"Батерија"</string>
<string name="clock" msgid="7416090374234785905">"Сат"</string>
<string name="headset" msgid="4534219457597457353">"Наглавне слушалице"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Слушалице су повезане"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Наглавне слушалице су повезане"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Омогућите или онемогућите приказивање икона на статусној траци."</string>
<string name="data_saver" msgid="5037565123367048522">"Уштеда података"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Уштеда података је укључена"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Уштеда података је искључена"</string>
<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>
@@ -522,4 +545,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Изаберите дугме за тастатуру"</string>
<string name="preview" msgid="9077832302472282938">"Преглед"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Превуците да бисте додали плочице"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Измени"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Време"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Прикажи сате, минуте и секунде"</item>
+ <item msgid="1427801730816895300">"Прикажи сате и минуте (подразумевано)"</item>
+ <item msgid="3830170141562534721">"Не приказуј ову икону"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Увек приказуј проценат"</item>
+ <item msgid="2139628951880142927">"Прикажи проценат током пуњења (подразумевано)"</item>
+ <item msgid="3327323682209964956">"Не приказуј ову икону"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Разделник подељеног екрана"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Помери надоле"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Помери нагоре"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Помери улево"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Помери удесно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e4d5d9725e8d..a23aba9074be 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Skärmdumpen har tagits."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Tryck här om du vill visa skärmdumpen."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Det gick inte att ta någon skärmdump."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Skärmdump misslyckades. Lagringsutrymmet räcker inte eller appen/organisationen tillåter det inte."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Det går inte att spara skärmdumpen eftersom lagringsutrymmet inte räcker."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Appen eller organisationen tillåter inte att du tar skärmdumpar."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Överföringsalternativ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Montera som mediaspelare (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Montera som kamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Längre tid."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kortare tid."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ficklampa av."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ficklampa på."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ficklampan har inaktiverats."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ficklampan har aktiverats."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fästa skärmen"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> är inaktiverad i säkert läge."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historik"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Rensa"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Den här appen har inte stöd för flera fönster"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Appen har inte stöd för flera fönster"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Helt\ntyst"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Endast\nprioriterade"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Endast\nalarm"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Alla"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Alla\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laddas snabbt (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laddas sakta (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
<string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Aktivera accelerator för delad skärm när du sveper uppåt"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivera delad skärm när du sveper uppåt"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivera en rörelse som delar skärmen när du sveper uppåt från knappen Översikt"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivera"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Ändra för alla aviseringar för <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Ändra för alla aviseringar från den här appen"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Blockerad"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Oviktig avisering"</string>
<string name="default_importance" msgid="8192107689995742653">"Vanlig avisering"</string>
<string name="high_importance" msgid="1527066195614050263">"Viktig avisering"</string>
<string name="max_importance" msgid="5089005872719563894">"Brådskande avisering"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Visa aldrig de här aviseringarna"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Visa längst ned på listan, utan ljud"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Visa aviseringarna utan ljud"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Visa högst upp på listan, med ljud"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Visa på skärmen, med ljud"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
<string name="notification_done" msgid="5279426047273930175">"Klar"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normala färger"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Nattfärger"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Anpassade färger"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Automatiskt"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Okända färger"</string>
- <string name="color_transform" msgid="6985460408079086090">"Färgändring"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Visa rutan Snabbinställningar"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Aktivera anpassad omvandling"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Färg och utseende"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Nattläge"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Kalibrera skärmen"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Aktiverat"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Inaktiverat"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Aktivera automatiskt"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Byt till Nattläge vid passande platser och tider på dygnet"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"När Nattläget är aktiverat"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Använd mörkt tema för Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Justera ton"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Justera ljusstyrka"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Det mörka temat används för kärnfunktioner i Android OS som brukar visas med ett ljust tema, t.ex. inställningarna."</string>
<string name="color_apply" msgid="9212602012641034283">"Verkställ"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Bekräfta inställningarna"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Vissa färginställningar kan göra den här enheten oanvändbar. Klicka på OK om du vill bekräfta färginställningarna, annars återställs inställningarna efter 10 sekunder."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Batteri (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Minskar prestanda och bakgrundsdata"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Startsida"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Senaste"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tillbaka"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Visa Stör ej i volymkontrollen"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Tillåt full kontroll över Stör ej i volymkontrollen"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volym och Stör ej"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Aktivera Stör ej när volymen sänks"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Visa med volymkontroller"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Stör ej"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Genväg till volymknappar"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Inaktivera Stör ej när volymen höjs"</string>
<string name="battery" msgid="7498329822413202973">"Batteri"</string>
<string name="clock" msgid="7416090374234785905">"Klocka"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Hörlurar anslutna"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Headset anslutet"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Visa eller dölj ikoner i statusfältet."</string>
<string name="data_saver" msgid="5037565123367048522">"Databesparing"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Databesparing är aktiverat"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Databesparing är inaktiverat"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Välj tangentbordsknapp"</string>
<string name="preview" msgid="9077832302472282938">"Förhandsgranskning"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Lägg till rutor genom att dra"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Redigera"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Tid"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Visa timmar, minuter och sekunder"</item>
+ <item msgid="1427801730816895300">"Visa timmar och minuter (standard)"</item>
+ <item msgid="3830170141562534721">"Visa inte den här ikonen"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Visa alltid procent"</item>
+ <item msgid="2139628951880142927">"Visa procent under laddning (standard)"</item>
+ <item msgid="3327323682209964956">"Visa inte den här ikonen"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Avdelare för delad skärm"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytta nedåt"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytta uppåt"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytta åt vänster"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytta åt höger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index e60496c4464b..4978d9423687 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Picha ya skrini imenaswa."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Gusa ili kuona picha yako ya skrini."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Haikuweza kunasa picha ya skrini"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Haiwezi kupiga picha ya skrini kwa sababu nafasi ya hifadhi haitoshi, au hairuhusiwi na programu yako au ya shirika."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Haina nafasi ya kutosha kuhifadhi picha ya skrini."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Shirika au programu yako haikuruhusu upige picha za skrini."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Machaguo ya uhamisho wa faili la USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Angika kama kichezeshi cha midia (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Angika kama kamera (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Muda zaidi."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Muda kidogo"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Tochi imezimwa."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Tochi haipatikani."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Tochi inawaka."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Tochi imezimwa."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Tochi imewashwa."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kudumisha programu moja"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> imezimwa katika hali salama."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Historia"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Futa"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Programu hii haitumiki katika hali ya madirisha mengi"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Programu haitumiki katika hali ya madirisha mengi"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Kimya\nkabisa"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kipaumbele\npekee"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kengele\npekee"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Zote"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Zote\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Inachaji kwa kasi (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Inachaji pole pole (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
<string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Washa kiakibishaji cha skrini inayogawanywa kwa kutelezesha kidole juu"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ruhusu kugawanya skrini kwa ishara ya kutelezesha kidole juu"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Washa kipengele cha ishara ili utumie skrini iliyogawanywa kwa kutelezesha kidole juu kutoka kitufe cha Muhtasari"</string>
<string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Washa"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Tumia katika arifa za <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Tumia katika arifa zote kutoka programu hii"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Onyesha arifa bila sauti"</string>
+ <string name="block" msgid="2734508760962682611">"Zuia arifa zote"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Usinyamazishe"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Usinyamazishe wala kuzuia"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Onyesha mipangilio kamili ya umuhimu"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Amezuiwa"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Umuhimu wa kiwango cha chini zaidi"</string>
<string name="low_importance" msgid="4109929986107147930">"Umuhimu kiwango cha chini"</string>
<string name="default_importance" msgid="8192107689995742653">"Umuhimu wa kiwango cha kawaida"</string>
<string name="high_importance" msgid="1527066195614050263">"Umuhimu wa kiwango cha juu"</string>
<string name="max_importance" msgid="5089005872719563894">"Umuhimu wa hali ya dharura"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Usionyeshe arifa hizi kamwe"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Onyesha katika sehemu ya chini ya orodha ya arifa bila sauti"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Onyesha arifa hizi bila sauti"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Onyesha katika sehemu ya juu ya orodha ya arifa na itoe sauti"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Weka onyesho la kuchungulia kwenye skrini na itoe sauti"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Onyesha katika sehemu ya chini ya orodha ya arifa bila sauti"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Onyesha arifa hizi bila sauti"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Ruhusu arifa hizi zitoe sauti"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Chungulia kwenye skrini na uruhusu sauti"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Onyesha katika sehemu ya juu ya orodha ya arifa, chungulia kwenye skrini na uruhusu sauti"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
<string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Rangi za kawaida"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Rangi za usiku"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Rangi maalum"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Otomatiki"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Rangi zisizojulikana"</string>
- <string name="color_transform" msgid="6985460408079086090">"Ubadilishaji wa rangi"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Onyesha kigae cha Mipangilio ya Haraka"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Washa ubadilishaji maalum"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Rangi na mwonekano"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Hali ya usiku"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Rekebisha onyesho"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Imewashwa"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Imezimwa"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Washa kiotomatiki"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Badilisha kuwa Hali ya Usiku kulingana na mahali na wakati"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Hali ya Usiku inapowashwa"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Tumia mandhari ya giza katika Mfumo wa Uendeshaji wa Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Rekebisha kivulivuli"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Rekebisha mwangaza"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Mandhari yenye giza yametumika katika maeneo muhimu ya Mfumo wa Uendeshaji wa Android ambayo kwa kawaida huonyeshwa katika mandhari yenye mwangaza, kama vile Mipangilio."</string>
<string name="color_apply" msgid="9212602012641034283">"Tumia"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Thibitisha mipangilio"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Baadhi ya mipangilio ya rangi inaweza kufanya kifaa hiki kisitumike. Bofya Sawa ili uthibitishe mipangilio hii ya rangi, vinginevyo, mipangilio hii itajiweka upya baada ya sekunde 10."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Betri (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Hupunguza data ya chini chini na utendaji"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Mwanzo"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Zilizotumika majuzi"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Nyuma"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Onyesha hali ya usinisumbue katika sauti"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Ruhusu udhibiti kamili wa hali ya usinisumbue katika kidirisha cha sauti."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Sauti na Usinisumbue"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Weka hali ya usinisumbue sauti inapopunguzwa"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Onyesha katika vidhibiti vya sauti"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Usinisumbue"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Njia ya mkato ya vitufe vya sauti"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Ondoa hali ya usinisumbue sauti inapoongezwa"</string>
<string name="battery" msgid="7498329822413202973">"Betri"</string>
<string name="clock" msgid="7416090374234785905">"Saa"</string>
<string name="headset" msgid="4534219457597457353">"Vifaa vya sauti"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Imeunganisha spika za masikioni"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Imeunganisha vifaa vya sauti"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Washa au uzime aikoni ili zisionekane kwenye sehemu ya arifa"</string>
<string name="data_saver" msgid="5037565123367048522">"Kiokoa Data"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Kiokoa Data kimewashwa"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Kiokoa Data kimezimwa"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"Chagua Kitufe cha Kibodi"</string>
<string name="preview" msgid="9077832302472282938">"Onyesho la kuchungulia"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Buruta ili uongeze vigae"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Badilisha"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Wakati"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Onyesha saa, dakika na sekunde"</item>
+ <item msgid="1427801730816895300">"Onyesha saa na dakika (chaguo-msingi)"</item>
+ <item msgid="3830170141562534721">"Usionyeshe aikoni hii"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Onyesha asilimia kila wakati"</item>
+ <item msgid="2139628951880142927">"Onyesha asilimia wakati inachaji (chaguo-msingi)"</item>
+ <item msgid="3327323682209964956">"Usionyeshe aikoni hii"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Nyingine"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Kitenganishi cha skrini inayogawanywa"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Sogeza chini"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sogeza juu"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sogeza kushoto"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sogeza kulia"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 7e8d802fc947..6594bd28c8b4 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -19,5 +19,8 @@
card. -->
<integer name="keyguard_max_notification_count">3</integer>
+ <!-- Whether QuickSettings is in a phone landscape -->
+ <bool name="quick_settings_wide">false</bool>
+
<integer name="quick_settings_num_columns">3</integer>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index be5b856a65f5..4ed15d5c400b 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -37,4 +37,7 @@
<dimen name="navigation_key_width">162dp</dimen>
<dimen name="navigation_key_padding">42dp</dimen>
+
+ <dimen name="battery_detail_graph_space_top">27dp</dimen>
+ <dimen name="battery_detail_graph_space_bottom">27dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index c0652d8a8e8b..122413d2677a 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -95,4 +95,10 @@
<dimen name="navigation_key_padding">25dp</dimen>
<dimen name="qs_expand_margin">0dp</dimen>
+
+ <!-- The top padding for the task stack. -->
+ <dimen name="recents_stack_top_padding">40dp</dimen>
+
+ <!-- The side padding for the task stack. -->
+ <dimen name="recents_stack_left_right_padding">64dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 4d7d6b5c9f77..791d7615eb80 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
- <item name="android:layout_width">480dp</item>
+ <item name="android:layout_width">@dimen/standard_notification_panel_width</item>
</style>
<style name="UserDetailView">
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 7cee38140fe7..8fe6be93917a 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -31,6 +31,8 @@
<!-- The radius of the rounded corners on a task view. -->
<dimen name="recents_task_view_rounded_corners_radius">3dp</dimen>
+ <!-- The radius of the rounded corners on a task view's shadow. -->
+ <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen>
<!-- The fraction of the screen height where the clock on the Keyguard has its center. The
max value is used when no notifications are displaying, and the min value is when the
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 1bb10e702315..02a193a92e7a 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"உங்கள் ஸ்க்ரீன் ஷாட்டைப் பார்க்க தொடவும்."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ஸ்க்ரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"குறைந்த சேமிப்பகம் காரணமாக ஸ்கிரீன்ஷாட் எடுக்க முடியவில்லை, அல்லது பயன்பாடு அல்லது உங்கள் நிறுவனத்தால் அனுமதிக்கப்படவில்லை."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன் ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"பயன்பாடு அல்லது உங்கள் நிறுவனம் ஸ்கிரீன் ஷாட்டுகளை எடுக்க அனுமதிக்கவில்லை."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"(PTP) கேமராவாக ஏற்று"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"நேரத்தை அதிகரி."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"நேரத்தைக் குறை."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ஃபிளாஷ்லைட் முடக்கத்தில்."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ஃபிளாஷ்லைட் இல்லை."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ஃபிளாஷ்லைட் இயக்கத்தில்."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ஃபிளாஷ்லைட் முடக்கப்பட்டது."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ஃபிளாஷ்லைட் இயக்கப்பட்டது."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"திரையை பின் செய்தல்"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"பாதுகாப்புப் பயன்முறையில் <xliff:g id="APP">%s</xliff:g> முடக்கப்பட்டது."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"வரலாறு"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"அழி"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"அறிவிப்புகள்\nவேண்டாம்"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"முன்னுரிமைகள்\nமட்டும்"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"அலாரங்கள்\nமட்டும்"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"எல்லாம்"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"எல்லாம்\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"வேகமாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"மெதுவாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
<string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"மேலே ஸ்வைப் செய்வதன் மூலம் திரைப் பிரிப்பை இயக்கு"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"மேலே ஸ்வைப் செய்வதன் மூலம் திரையைப் பிரிக்கும் சைகையை இயக்கு"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"மேலோட்டப் பார்வை பொத்தானிலிருந்து மேலே ஸ்வைப் செய்வதன் மூலம், திரைப் பிரிப்பைச் செயலாக்குவதற்கான சைகையை இயக்கும்"</string>
<string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"இயக்கு"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> அறிவிப்புகளுக்குப் பயன்படுத்து"</string>
- <string name="apply_to_app" msgid="363016783939815960">"இந்தப் பயன்பாட்டிலிருந்து வரும் எல்லா அறிவிப்புகளுக்கும் பயன்படுத்து"</string>
+ <string name="show_silently" msgid="6841966539811264192">"ஒலியின்றி அறிவிப்புகளைக் காட்டு"</string>
+ <string name="block" msgid="2734508760962682611">"எல்லா அறிவிப்புகளையும் தடு"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"ஒலியை அனுமதி"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"ஒலி அல்லது அறிவிப்பைத் தடுக்காதே"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"முக்கியத்துவ அமைப்புகள் முழுவதையும் காட்டு"</string>
<string name="blocked_importance" msgid="5198578988978234161">"தடுக்கப்பட்டது"</string>
+ <string name="min_importance" msgid="1901894910809414782">"குறைந்தபட்ச முக்கியத்துவம்"</string>
<string name="low_importance" msgid="4109929986107147930">"முக்கியத்துவம் (குறைவு)"</string>
<string name="default_importance" msgid="8192107689995742653">"முக்கியத்துவம் (இயல்பு)"</string>
<string name="high_importance" msgid="1527066195614050263">"முக்கியத்துவம் (அதிகம்)"</string>
<string name="max_importance" msgid="5089005872719563894">"முக்கியத்துவம் (அவசரம்)"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"இந்த அறிவிப்புகளை ஒருபோதும் காட்டாதே"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டு"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டு"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"அறிவிப்புகள் பட்டியலின் மேல் பகுதியில் ஒலியுடன் காட்டு"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"ஒலியுடன் திரையில் காட்டு"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டு"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டு"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"இந்த அறிவிப்புகளுக்கு ஒலியை அனுமதி"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"சில வினாடிகளுக்கு ஒலியுடன் திரையில் காட்டு"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"அறிவிப்புகள் பட்டியலின் மேற்பகுதியில், சில வினாடிகளுக்கு ஒலியுடன் திரையில் காட்டு"</string>
<string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
<string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"இயல்பான வண்ணங்கள்"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"இரவுநேர வண்ணங்கள்"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"தனிப்பயன் வண்ணங்கள்"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"தானியங்கு"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"அறியப்படாத வண்ணங்கள்"</string>
- <string name="color_transform" msgid="6985460408079086090">"வண்ண மாற்றம்"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"விரைவு அமைப்புகள் டைலைக் காட்டு"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"தனிப்பயன் வண்ண மாற்றத்தை இயக்கு"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"வண்ணமும் தோற்றமும்"</string>
+ <string name="night_mode" msgid="3540405868248625488">"இரவுப் பயன்முறை"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"திரையை அளவுத்திருத்தம் செய்"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"இயக்கத்தில்"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"முடக்கத்தில்"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"தானாகவே இயக்கு"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"இருப்பிடம் மற்றும் நேரத்தின்படி இரவுப் பயன்முறைக்கு மாற்று"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"இரவுப் பயன்முறை இயக்கப்பட்டிருக்கும் போது"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OSக்காக அடர் தீமினைப் பயன்படுத்து"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"டிண்ட்டைச் சரிசெய்"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ஒளிர்வைச் சரிசெய்"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"வழக்கமாக வெளிர் தீமில் காட்டப்படுகிற Android OS இன் முக்கிய பகுதிகளில் (எ.கா. அமைப்புகள்) அடர் தீம் பயன்படுத்தப்படுகிறது."</string>
<string name="color_apply" msgid="9212602012641034283">"பயன்படுத்து"</string>
<string name="color_revert_title" msgid="4746666545480534663">"அமைப்புகளை உறுதிப்படுத்து"</string>
<string name="color_revert_message" msgid="9116001069397996691">"சில வண்ண அமைப்புகள் இந்தச் சாதனத்தைப் பயன்படுத்த முடியாதபடி செய்யலாம். இந்த வண்ண அமைப்புகளை உறுதிப்படுத்த, சரி என்பதைக் கிளிக் செய்யவும், இல்லையெனில் இந்த அமைப்புகள் 10 வினாடிகளுக்குப் பின் மீட்டமைக்கப்படும்."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"பேட்டரி (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"செயல்திறனையும் பின்புலத்தில் தரவு செயலாக்கப்படுவதையும் குறைக்கும்"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"முகப்பு"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"சமீபத்தியவை"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"முந்தையது"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"ஒலி உரையாடலில் தொந்தரவு செய்ய வேண்டாம் என்பதைக் காட்டு"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"ஒலி உரையாடலில் தொந்தரவு செய்ய வேண்டாம் என்பதன் முழுக் கட்டுப்பாட்டையும் அனுமதி."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ஒலி மற்றும் தொந்தரவு செய்ய வேண்டாம்"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"ஒலியைக் குறைக்கும்போது தொந்தரவு செய்ய வேண்டாம் என்பதை இயக்கு"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"ஒலிக் கட்டுப்பாடுகளுடன் காட்டு"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"தொந்தரவு செய்ய வேண்டாம்"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ஒலியளவுப் பொத்தான்களுக்கான குறுக்குவழி"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ஒலியைக் கூட்டும் போது தொந்தரவு செய்ய வேண்டாம் என்பதை முடக்கு"</string>
<string name="battery" msgid="7498329822413202973">"பேட்டரி"</string>
<string name="clock" msgid="7416090374234785905">"கடிகாரம்"</string>
<string name="headset" msgid="4534219457597457353">"ஹெட்செட்"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ஹெட்ஃபோன்கள் இணைக்கப்பட்டன"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ஹெட்செட் இணைக்கப்பட்டது"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"நிலைப் பட்டியில் ஐகான்களைக் காட்டுவதை இயக்கும் அல்லது முடக்கும்."</string>
<string name="data_saver" msgid="5037565123367048522">"தரவுச்சேமிப்பான்"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"தரவு சேமிப்பான் இயக்கப்பட்டது"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"தரவு சேமிப்பான் முடக்கப்பட்டது"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"விசைப்பலகைப் பொத்தானைத் தேர்ந்தெடுக்கவும்"</string>
<string name="preview" msgid="9077832302472282938">"மாதிரிக்காட்சி"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"கட்டங்களைச் சேர்க்க, இழுக்கவும்"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"மாற்று"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"நேரம்"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"மணிநேரம், நிமிடங்கள், வினாடிகளைக் காட்டு"</item>
+ <item msgid="1427801730816895300">"மணிநேரம், நிமிடங்களைக் காட்டு (இயல்பு)"</item>
+ <item msgid="3830170141562534721">"இந்த ஐகானைக் காட்டாதே"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"எப்போதும் சதவீதத்தைக் காட்டு"</item>
+ <item msgid="2139628951880142927">"சார்ஜ் செய்யும் போது சதவீதத்தைக் காட்டு (இயல்பு)"</item>
+ <item msgid="3327323682209964956">"இந்த ஐகானைக் காட்டாதே"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"மற்றவை"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"திரையைப் பிரிக்கும் பிரிப்பான்"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"கீழே நகர்த்து"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"மேலே நகர்த்து"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"இடப்புறம் நகர்த்து"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"வலப்புறம் நகர்த்து"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index e57113e1a7cf..d02b35321ec2 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"స్క్రీన్‌షాట్ క్యాప్చర్ చేయబడింది."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"మీ స్క్రీన్‌షాట్‌ను వీక్షించడానికి తాకండి."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"స్క్రీన్‌షాట్‌ను క్యాప్చర్ చేయడం సాధ్యపడలేదు."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"పరిమిత నిల్వ స్థలం కారణంగా స్క్రీన్‌షాట్‌‌ను తీయడం సాధ్యపడదు లేదా దీన్ని మీ అనువర్తనం లేదా మీ సంస్థ అనుమతించలేదు."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"పరిమిత నిల్వ స్థలం కారణంగా స్క్రీన్‌షాట్‌ను సేవ్ చేయడం సాధ్యపడదు."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"స్క్రీన్‌షాట్‌లు తీయడానికి అనువర్తనం లేదా మీ సంస్థ అనుమతించలేదు."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ఫైల్ బదిలీ ఎంపికలు"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"మీడియా ప్లేయర్‌గా (MTP) మౌంట్ చేయి"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"కెమెరాగా (PTP) మౌంట్ చేయి"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ఎక్కువ సమయం."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"తక్కువ సమయం."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ఫ్లాష్‌లైట్ ఆఫ్‌లో ఉంది."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ఫ్లాష్‌లైట్ అందుబాటులో లేదు."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ఫ్లాష్‌లైట్ ఆన్‌లో ఉంది."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ఫ్లాష్‌లైట్ ఆఫ్ చేయబడింది."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ఫ్లాష్‌లైట్ ఆన్ చేయబడింది."</string>
@@ -301,8 +303,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"స్క్రీన్ పిన్నింగ్"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"శోధించు"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభించడం సాధ్యపడలేదు."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> సురక్షిత-మోడ్‌లో నిలిపివేయబడింది."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"చరిత్ర"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"తీసివేయి"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"ఈ అనువర్తనం బహుళ విండోలకు మద్దతు ఇవ్వదు"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"అనువర్తనం బహుళ విండోలకు మద్దతు ఇవ్వదు"</string>
<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>
@@ -332,8 +337,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"మొత్తం\nనిశ్శబ్దం"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ప్రాధాన్యమైనవి\nమాత్రమే"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"అలారాలు\nమాత్రమే"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"అన్నిటికీ"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"అన్నీ\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"వేగంగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"నెమ్మదిగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +449,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
<string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన యాక్సిలరేటర్‌ను ప్రారంభించు"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన సంజ్ఞను ప్రారంభించు"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"స్థూలదృష్టి బటన్ నుండి పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజనలోకి ప్రవేశించడానికి సంజ్ఞను ప్రారంభిస్తుంది"</string>
<string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ఆన్ చేయి"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> నోటిఫికేషన్‌లకు వర్తింపజేయి"</string>
- <string name="apply_to_app" msgid="363016783939815960">"ఈ అనువర్తనం నుండి అందించబడే అన్ని నోటిఫికేషన్‌లకు వర్తింపజేయి"</string>
+ <string name="show_silently" msgid="6841966539811264192">"నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపు"</string>
+ <string name="block" msgid="2734508760962682611">"అన్ని నోటిఫికేషన్‌లను బ్లాక్ చేయి"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"నిశ్శబ్దం చేయవద్దు"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"నిశ్శబ్దం చేయవద్దు లేదా బ్లాక్ చేయవద్దు"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"పూర్తి ప్రాముఖ్యత సెట్టింగ్‌లను చూపండి"</string>
<string name="blocked_importance" msgid="5198578988978234161">"బ్లాక్ చేయబడింది"</string>
+ <string name="min_importance" msgid="1901894910809414782">"కని. ప్రాముఖ్యత"</string>
<string name="low_importance" msgid="4109929986107147930">"తక్కువ ప్రాముఖ్యత"</string>
<string name="default_importance" msgid="8192107689995742653">"సాధారణ ప్రాముఖ్యత"</string>
<string name="high_importance" msgid="1527066195614050263">"అధిక ప్రాముఖ్యత"</string>
<string name="max_importance" msgid="5089005872719563894">"అత్యవసర ప్రాముఖ్యత"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ఈ నోటిఫికేషన్‌లను ఎప్పుడూ చూపదు"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"నోటిఫికేషన్‌ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"నోటిఫికేషన్‌ల జాబితా ఎగువ భాగంలో శబ్దంతో చూపుతుంది"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"నోటిఫికేషన్‌ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"ఈ నోటిఫికేషన్‌లను శబ్దంతో చూపేలా అనుమతిస్తుంది"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"నోటిఫికేషన్‌ల జాబితా అగ్ర భాగాన, స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
<string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్‌లు"</string>
<string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"సాధారణ రంగులు"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"రాత్రి రంగులు"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"అనుకూల రంగులు"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"స్వయంచాలకం"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"తెలియని రంగులు"</string>
- <string name="color_transform" msgid="6985460408079086090">"రంగు సవరణ"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"శీఘ్ర సెట్టింగ్‌ల టైల్‌ను చూపండి"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"అనుకూల పరివర్తనను ప్రారంభించండి"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"రంగు మరియు కనిపించే తీరు"</string>
+ <string name="night_mode" msgid="3540405868248625488">"రాత్రి మోడ్"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"డిస్‌ప్లేని క్రమాంకనం చేయండి"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"ఆన్‌లో ఉంది"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ఆఫ్‌లో ఉంది"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"స్వయంచాలకంగా ఆన్ చేయి"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"స్థానం మరియు రోజులో సమయానికి తగినట్లుగా రాత్రి మోడ్‌కి మారుస్తుంది"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"రాత్రి మోడ్ ఆన్‌లో ఉన్నప్పుడు"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS కోసం ముదురు రంగు థీమ్ ఉపయోగించండి"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"లేత రంగును సర్దుబాటు చేయండి"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ప్రకాశాన్ని సర్దుబాటు చేయండి"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"సాధారణంగా లేత రంగు థీమ్‌లో ప్రదర్శించబడే సెట్టింగ్‌ల వంటి Android OS ప్రధాన అంశాలకు ముదురు రంగు థీమ్ వర్తింపజేయబడుతుంది."</string>
<string name="color_apply" msgid="9212602012641034283">"వర్తింపజేయి"</string>
<string name="color_revert_title" msgid="4746666545480534663">"సెట్టింగ్‌లను నిర్ధారించండి"</string>
<string name="color_revert_message" msgid="9116001069397996691">"కొన్ని రంగు సెట్టింగ్‌ల వలన ఈ పరికరం ఉపయోగించలేని విధంగా అయిపోవచ్చు. ఈ రంగు సెట్టింగ్‌లను నిర్ధారించడానికి సరే క్లిక్ చేయండి లేదంటే ఈ సెట్టింగ్‌లు 10 సెకన్ల తర్వాత రీసెట్ చేయబడతాయి."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"బ్యాటరీ (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
@@ -485,21 +497,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"హోమ్"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ఇటీవలివి"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"వెనుకకు"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"వాల్యూమ్‌లో అంతరాయం కలిగించవద్దు ప్యానెల్‌ను చూపు"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"వాల్యూమ్‌ డైలాగ్‌లో అంతరాయం కలిగించవద్దు ప్యానెల్ పూర్తి నియంత్రణను అనుమతిస్తుంది."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"వాల్యూమ్ మరియు అంతరాయం కలిగించవద్దు"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"వాల్యూమ్ తగ్గిస్తే అంతరాయం కలిగించవద్దులోకి ప్రవేశిస్తుంది"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"వాల్యూమ్ నియంత్రణలతో చూపు"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"అంతరాయం కలిగించవద్దు"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"వాల్యూమ్ బటన్‌ల సత్వరమార్గం"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"వాల్యూమ్ పెంచితే అంతరాయం కలిగించవద్దు నుండి నిష్క్రమిస్తుంది"</string>
<string name="battery" msgid="7498329822413202973">"బ్యాటరీ"</string>
<string name="clock" msgid="7416090374234785905">"గడియారం"</string>
<string name="headset" msgid="4534219457597457353">"హెడ్‌సెట్"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"హెడ్‌ఫోన్‌లు కనెక్ట్ చేయబడ్డాయి"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"హెడ్‌సెట్ కనెక్ట్ చేయబడింది"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"స్థితి పట్టీలో చిహ్నాలు ప్రదర్శించడాన్ని ప్రారంభించండి లేదా నిలిపివేయండి."</string>
<string name="data_saver" msgid="5037565123367048522">"డేటా సేవర్"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"డేటా సేవర్ ఆన్‌లో ఉంది"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"డేటా సేవర్ ఆఫ్‌లో ఉంది"</string>
<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>
@@ -521,4 +532,22 @@
<string name="select_keycode" msgid="7413765103381924584">"కీబోర్డ్ బటన్‌ను ఎంచుకోండి"</string>
<string name="preview" msgid="9077832302472282938">"పరిదృశ్యం"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"టైల్‌లను జోడించడానికి లాగండి"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"సవరించు"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"సమయం"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"గంటలు, నిమిషాలు మరియు సెకన్లను చూపు"</item>
+ <item msgid="1427801730816895300">"గంటలు మరియు నిమిషాలను చూపు (డిఫాల్ట్)"</item>
+ <item msgid="3830170141562534721">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ఎల్లప్పుడూ శాతాన్ని చూపు"</item>
+ <item msgid="2139628951880142927">"ఛార్జ్ అవుతున్నప్పుడు శాతాన్ని చూపు (డిఫాల్ట్)"</item>
+ <item msgid="3327323682209964956">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"ఇతరం"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"విభజన స్క్రీన్ విభాగిని"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"క్రిందికి తరలించు"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"పైకి తరలించు"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ఎడమవైపుకు తరలించు"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"కుడివైపుకు తరలించు"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6a61f13c0929..33a07ec86716 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"จับภาพหน้าจอแล้ว"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"แตะเพื่อดูภาพหน้าจอของคุณ"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"ไม่สามารถจับภาพหน้าจอ"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"ไม่สามารถจับภาพหน้าจอได้ เนื่องจากพื้นที่ว่างมีจำกัด หรือไม่ได้รับอนุญาตจากแอปหรือองค์กรของคุณ"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ไม่สามารถบันทึกภาพหน้าจอเนื่องจากพื้นที่เก็บข้อมูลมีจำกัด"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"แอปหรือองค์กรของคุณไม่อนุญาตให้จับภาพหน้าจอ"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"ตัวเลือกการถ่ายโอนไฟล์ USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ต่อเชื่อมเป็นโปรแกรมเล่นสื่อ (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ต่อเชื่อมเป็นกล้องถ่ายรูป (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"เวลามากขึ้น"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"เวลาน้อยลง"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ไฟฉายปิดอยู่"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ไฟฉายเปิดอยู่"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ปิดไฟฉายแล้ว"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"เปิดไฟฉายแล้ว"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"การตรึงหน้าจอ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"ไม่สามารถเริ่มใช้ <xliff:g id="APP">%s</xliff:g>"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ปิดใช้ในโหมดปลอดภัย"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"ประวัติ"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ล้าง"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"แอปนี้ไม่สนับสนุนหลายหน้าต่าง"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"แอปไม่สนับสนุนหลายหน้าต่าง"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"ปิดเสียง\nทั้งหมด"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"เฉพาะเรื่อง\nสำคัญ"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"เฉพาะปลุก\nเท่านั้น"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"ทั้งหมด"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"ทั้งหมด\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"กำลังชาร์จอย่างรวดเร็ว (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"กำลังชาร์จอย่างช้าๆ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
<string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"เปิดใช้ตัวเร่งการกวาดขึ้นเพื่อแยกหน้าจอ"</string>
- <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยกวาดขึ้นจากปุ่มภาพรวม"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"เปิดใช้ท่าทางสัมผัสการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
+ <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยเลื่อนขึ้นจากปุ่มภาพรวม"</string>
<string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"เปิด"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"นำไปใช้กับการแจ้งเตือน <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"นำไปใช้กับการแจ้งเตือนทั้งหมดจากแอปนี้"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"บล็อกแล้ว"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"ความสำคัญต่ำ"</string>
<string name="default_importance" msgid="8192107689995742653">"ความสำคัญปกติ"</string>
<string name="high_importance" msgid="1527066195614050263">"ความสำคัญสูง"</string>
<string name="max_importance" msgid="5089005872719563894">"ความสำคัญเร่งด่วน"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"ไม่ต้องแสดงการแจ้งเตือนเหล่านี้"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"แสดงที่ด้านบนของรายการแจ้งเตือนและส่งเสียง"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"แสดงบนหน้าจอในช่วงเวลาสั้นๆ และส่งเสียง"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
<string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"สีปกติ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"สียามค่ำคืน"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"สีที่กำหนดเอง"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"อัตโนมัติ"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"สีที่ไม่รู้จัก"</string>
- <string name="color_transform" msgid="6985460408079086090">"การปรับเปลี่ยนสี"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"แสดงไทล์การตั้งค่าด่วน"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"เปิดใช้การเปลี่ยนที่กำหนดเอง"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"สีและลักษณะที่ปรากฏ"</string>
+ <string name="night_mode" msgid="3540405868248625488">"โหมดกลางคืน"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"ปรับเทียบการแสดงผล"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"เปิด"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"ปิด"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"เปิดอัตโนมัติ"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"เปลี่ยนเป็นโหมดกลางคืนตามความเหมาะสมกับสถานที่และเวลาของวัน"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"เมื่อเปิดโหมดกลางคืน"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"ใช้ธีมสีเข้มสำหรับ Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ปรับการแต้มสี"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"ปรับความสว่าง"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"ใช้ธีมสีเข้มในบริเวณสำคัญของระบบปฏิบัติการ Android ซึ่งปกติแล้วจะแสดงด้วยธีมสีอ่อน เช่น การตั้งค่า"</string>
<string name="color_apply" msgid="9212602012641034283">"ใช้"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ยืนยันการตั้งค่า"</string>
<string name="color_revert_message" msgid="9116001069397996691">"การตั้งค่าสีบางอย่างอาจทำให้อุปกรณ์นี้ใช้งานไม่ได้ คลิกตกลงเพื่อยืนยันการตั้งค่าสีเหล่านี้ มิฉะนั้นระบบจะรีเซ็ตการตั้งค่าหลังจาก 10 วินาที"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"แบตเตอรี่ (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"ลดประสิทธิภาพการทำงานและข้อมูลแบ็กกราวด์"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"หน้าแรก"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"ล่าสุด"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"กลับ"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"แสดงโหมดห้ามรบกวนในระดับเสียง"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"อนุญาตให้ควบคุมโหมดห้ามรบกวนได้อย่างสมบูรณ์ในกล่องโต้ตอบระดับเสียง"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"ระดับเสียงและโหมดห้ามรบกวน"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"เข้าสู่โหมดห้ามรบกวนเมื่อลดระดับเสียง"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"แสดงพร้อมการควบคุมระดับเสียง"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ห้ามรบกวน"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"ทางลัดปุ่มปรับระดับเสียง"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"ออกจากโหมดห้ามรบกวนเมื่อเพิ่มระดับเสียง"</string>
<string name="battery" msgid="7498329822413202973">"แบตเตอรี่"</string>
<string name="clock" msgid="7416090374234785905">"นาฬิกา"</string>
<string name="headset" msgid="4534219457597457353">"ชุดหูฟัง"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"เชื่อมต่อหูฟังแล้ว"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"เชื่อมต่อชุดหูฟังแล้ว"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"เปิดหรือปิดไอคอนจากการแสดงในแถบสถานะ"</string>
<string name="data_saver" msgid="5037565123367048522">"โปรแกรมประหยัดอินเทอร์เน็ต"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"โปรแกรมประหยัดอินเทอร์เน็ตเปิดอยู่"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"โปรแกรมประหยัดอินเทอร์เน็ตปิดอยู่"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"เลือกปุ่มแป้นพิมพ์"</string>
<string name="preview" msgid="9077832302472282938">"ดูตัวอย่าง"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ลากเพื่อเพิ่มชิ้นส่วน"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"แก้ไข"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"เวลา"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"แสดงชั่วโมง นาที และวินาที"</item>
+ <item msgid="1427801730816895300">"แสดงชั่วโมงและนาที (ค่าเริ่มต้น)"</item>
+ <item msgid="3830170141562534721">"อย่าแสดงไอคอนนี้"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"แสดงเปอร์เซ็นต์เสมอ"</item>
+ <item msgid="2139628951880142927">"แสดงเปอร์เซ็นต์เมื่อชาร์จ (ค่าเริ่มต้น)"</item>
+ <item msgid="3327323682209964956">"อย่าแสดงไอคอนนี้"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"เส้นแบ่งหน้าจอ"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"เลื่อนลง"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"เลื่อนขึ้น"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"เลื่อนไปทางซ้าย"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"เลื่อนไปทางขวา"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 038867d68e58..99fa7a2a9b5f 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Nakuha ang screenshot."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Pindutin upang tingnan ang iyong screenshot."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Hindi makuha ang screenshot."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Di makapag-screenshot dahil sa limitadong storage space o di ito pinapayagan ng app o organisasyon."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Hindi ma-save ang screenshot dahil sa limitadong espasyo ng storage."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkuha ng mga screenshot."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opsyon paglipat ng USB file"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"I-mount bilang isang media player (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"I-mount bilang camera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Higit pang oras."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mas kaunting oras."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Naka-off ang flashlight."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Naka-on ang flashlight."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Na-off ang flashlight."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Na-on ang flashlight."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pagpi-pin sa screen"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Naka-disable ang <xliff:g id="APP">%s</xliff:g> sa safe-mode."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"History"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"I-clear"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Hindi sinusuportahan ng app na ito ang multi-window"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Hindi sinusuportahan ng app na ito ang multi-window"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Ganap na\nkatahimikan"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priyoridad\nlang"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Mga alarm\nlang"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Lahat"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Lahat\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mabilis mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mabagal mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"I-enable ang split-screen na swipe-up accelerator"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"I-enable ang pag-swipe pataas na galaw para sa split-screen"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"I-enable ang gesture upang makapasok sa split-screen sa pamamagitan ng pagsa-swipe pataas mula sa button ng Pangkalahatang-ideya"</string>
<string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"I-on"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Naaangkop sa mga notification tungkol sa <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Naaangkop sa lahat ng notification mula sa app na ito"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Na-block"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Hindi masyadong mahalaga"</string>
<string name="default_importance" msgid="8192107689995742653">"Mahalaga"</string>
<string name="high_importance" msgid="1527066195614050263">"Napakahalaga"</string>
<string name="max_importance" msgid="5089005872719563894">"Mahalagang-mahalaga"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Huwag kailanman ipakita ang mga notification na ito"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Tahimik na ipakita sa ibaba ng listahan ng notification"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Tahimik na ipakita ang mga notification na ito"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Ipakita sa itaas ng listahan ng mga notification at mag-play ng tunog"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Ipasilip sa screen at mag-play ng tunog"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
<string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Mga karaniwang kulay"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Madidilim na kulay"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Mga custom na kulay"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Auto"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Mga hindi kilalang kulay"</string>
- <string name="color_transform" msgid="6985460408079086090">"Pagbago sa kulay"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ipakita ang tile ng Mga Mabilisang Setting"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"I-enable ang custom na pagpalit"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Kulay at hitsura"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Night mode"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"I-calibrate ang display"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Naka-on"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Naka-off"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Awtomatikong i-on"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Lumipat sa Night Mode kapag naaangkop sa lokasyon at oras"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Kapag naka-on ang Night Mode"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Gumamit ng madilim na tema para sa Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Isaayos ang tint"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Isaayos ang liwanag"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Ilalapat ang madilim na tema sa mga mahalagang bahagi ng Android OS na karaniwang ipinapakita nang may maliwanag na tema, gaya ng Mga Setting."</string>
<string name="color_apply" msgid="9212602012641034283">"Ilapat"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Kumpirmahin ang mga setting"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Maaaring hindi magamit ang device na ito dahil sa ilang setting ng kulay. I-click ang OK upang kumpirmahin ang mga setting ng kulay na ito, kung hindi ay mare-reset ang mga setting na ito pagkatapos ng 10 segundo."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Baterya (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Binabawasan ang pagganap at data sa background"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Home"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Mga Kamakailang Ginamit"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Bumalik"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ipakita ang huwag istorbohin sa volume"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Payagang ganap na makontrol ang huwag istorbohin sa dialog ng volume."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Volume at Huwag istorbohin"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Gamitin ang huwag istorbohin nang mahina ang volume"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ipakita nang may mga kontrol ng volume"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Huwag istorbohin"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Shortcut ng mga button ng volume"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Umalis sa huwag istorbohin nang malakas ang volume"</string>
<string name="battery" msgid="7498329822413202973">"Baterya"</string>
<string name="clock" msgid="7416090374234785905">"Orasan"</string>
<string name="headset" msgid="4534219457597457353">"Headset"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Nakakonekta ang mga headphone"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Nakakonekta ang headset"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"I-enable o i-disable ang pagpapakita sa mga icon sa status bar."</string>
<string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Naka-on ang Data Saver"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Naka-off ang Data Saver"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Pumili ng Button na Keyboard"</string>
<string name="preview" msgid="9077832302472282938">"I-preview"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Mag-drag upang magdagdag ng mga tile"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"I-edit"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Oras"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Ipakita ang oras, minuto at segundo"</item>
+ <item msgid="1427801730816895300">"Ipakita ang oras at minuto (default)"</item>
+ <item msgid="3830170141562534721">"Huwag ipakita ang icon na ito"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Palaging ipakita ang porsyento"</item>
+ <item msgid="2139628951880142927">"Ipakita ang porsyento kapag nagcha-charge (default)"</item>
+ <item msgid="3327323682209964956">"Huwag ipakita ang icon na ito"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Divider ng split-screen"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Ilipat pababa"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Ilipat pataas"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Ilipat pakaliwa"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Ilipat pakanan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 0da92bbef829..050f1f7bfa2a 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran görüntüsü alındı."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Ekran görüntünüzü izlemek için dokunun."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Ekran görüntüsü alınamadı."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Depolama alanı sınırlı olduğundan veya uygulamanız ya da kuruluşunuz tarafından izin verilmediğinden ekran görüntüsü alınamıyor."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Depolama alanı sınırlı olduğundan ekran görüntüsü kaydedilemiyor."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB dosya aktarım seçenekleri"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Medya oynatıcı olarak ekle (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera olarak ekle (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha uzun süre."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha kısa süre."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"El feneri kapalı."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"El feneri açık."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"El feneri kapatıldı."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"El feneri açıldı."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sabitleme"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>, güvenli modda devre dışıdır."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Geçmiş"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Sil"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu uygulama, çoklu pencere kullanımını desteklemiyor"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Uygulama, çoklu pencere kullanımını desteklemiyor"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Tamamen\nsessiz"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnızca\nöncelik"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnızca\nalarmlar"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tümü"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tümü\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hızlı şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Yavaş şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
<string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Ekranı bölmek için yukarı hızlıca kaydırmayı etkinleştir"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Hızlıca yukarı kaydırma hareketiyle ekran bölm. etkinleştir"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Genel bakış düğmesinden yukarı hızlıca kaydırarak bölünmüş ekrana geçme hareketini etkinleştir"</string>
<string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aç"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> bildirimlerine uygula"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Bu uygulamadan gelen tüm bildirimlere uygulansın mı?"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Engellendi"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Önem düzeyi düşük"</string>
<string name="default_importance" msgid="8192107689995742653">"Önem düzeyi normal"</string>
<string name="high_importance" msgid="1527066195614050263">"Önem düzeyi yüksek"</string>
<string name="max_importance" msgid="5089005872719563894">"Önem düzeyi acil"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirimleri hiçbir zaman gösterme"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Bildirim listesinin en altında sessizce göster"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirimleri sessizce göster"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Bildirim listesinin en üstünde göster ve ses çıkar"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Ekrana getir ve ses çıkar"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
<string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Normal renkler"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Gece renkleri"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Özel renkler"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Otomatik"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Bilinmeyen renkler"</string>
- <string name="color_transform" msgid="6985460408079086090">"Renk değişikliği"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Hızlı Ayarlar kutusunu göster"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Özel dönüşümü etkinleştir"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Renk ve görünüm"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Gece modu"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Ekranı kalibre et"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Açık"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Kapalı"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Otomatik olarak aç"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Konuma ve günün saatine uygun şekilde Gece Modu\'na geç"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Gece Modu açık olduğunda"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android OS için koyu renk tema kullan"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Tonu ayarla"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Parlaklığı ayarla"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Koyu renk tema, Android OS\'nin normalde Ayarlar gibi açık renk bir temayla görüntülenen temel alanlarına uygulanır."</string>
<string name="color_apply" msgid="9212602012641034283">"Uygula"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Ayarları onaylayın"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Bazı renkler bu cihazı kullanılmaz yapabilir. Bu renkleri onaylamak için Tamam\'ı tıklayın. Tıklamazsanız bu ayarlar 10 saniye sonra sıfırlanacaktır."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Pil (%%<xliff:g id="ID_1">%1$d</xliff:g>)"</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Performansı ve arka plan verilerini azaltır"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ana ekran"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Son çağrılar"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Geri"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ses iletişim kutusunda rahatsız etmeyin modunu göster"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Ses iletişim kutusunda rahatsız etmeyin modunu tam olarak denetlemeye izin ver."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ses ve Rahatsız etmeyin"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Ses kısıldığında rahatsız etmeyin moduna geç"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ses seviyesi kontrolleriyle göster"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Rahatsız etmeyin"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Ses düğmeleri kısayolu"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Ses açıldığında rahatsız etmeyin modundan çık"</string>
<string name="battery" msgid="7498329822413202973">"Pil"</string>
<string name="clock" msgid="7416090374234785905">"Saat"</string>
<string name="headset" msgid="4534219457597457353">"Mikrofonlu kulaklık"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Mikrofonlu kulaklık bağlı"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Mikrofonlu kulaklık bağlı"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Simgelerin durum çubuğunda görüntülenmesini etkinleştir veya devre dışı bırak"</string>
<string name="data_saver" msgid="5037565123367048522">"Veri Tasarrufu"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Veri Tasarrufu açık"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Veri Tasarrufu kapalı"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Klavye Düğmesini Seçin"</string>
<string name="preview" msgid="9077832302472282938">"Önizle"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Blok eklemek için sürükleyin"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Düzenle"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Saat"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Saati, dakikayı ve saniyeyi göster"</item>
+ <item msgid="1427801730816895300">"Saati ve dakikayı göster (varsayılan)"</item>
+ <item msgid="3830170141562534721">"Bu simgeyi gösterme"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Her zaman yüzdeyi göster"</item>
+ <item msgid="2139628951880142927">"Şarj olurken yüzdeyi göster (varsayılan)"</item>
+ <item msgid="3327323682209964956">"Bu simgeyi gösterme"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Bölünmüş ekran ayırıcı"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Aşağı taşı"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yukarı taşı"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola taşı"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa taşı"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index eaf4d3915c9f..485e2b201ebc 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -75,7 +75,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Знімок екрана зроблено."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Торкніться, щоб переглянути знімок екрана."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Не вдалося зробити знімок екрана."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Не вдається зробити знімок екрана через обмежений обсяг пам’яті або заборону додатка чи організації."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Не вдалося зберегти знімок екрана через обмежений обсяг пам’яті."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Додаток або ваша організація не дозволяють робити знімки екрана."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Парам.передав.файлів через USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Підключити як медіапрогравач (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Підключити як камеру (PTP)"</string>
@@ -208,6 +209,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Більше часу."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Менше часу."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ліхтарик вимк."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ліхтарик увімк."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ліхтарик вимкнено."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ліхтарик увімкнено."</string>
@@ -303,8 +306,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"закріпити екран"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Додаток <xliff:g id="APP">%s</xliff:g> вимкнено в безпечному режимі."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Історія"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Очистити"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Цей додаток не підтримує багатоекранний режим"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Додаток не підтримує багатоекранний режим"</string>
<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>
@@ -334,8 +340,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Без\nсигналів"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Лише\nприорітетні"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Лише\nсигнали"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Усі"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Усі\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Швидке заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Повільне заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
@@ -448,38 +452,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
<string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Увімкнути акселератор розділення екрана рухом пальця вгору"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Увімкнути розділення екрана рухом пальця вгору"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Увімкнути жест розділення екрана рухом пальця вгору від кнопки \"Огляд\""</string>
<string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Увімкнути"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Застосувати до сповіщень на тему \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
- <string name="apply_to_app" msgid="363016783939815960">"Застосувати до всіх сповіщень із цього додатка"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Заблоковано"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Низький пріоритет"</string>
<string name="default_importance" msgid="8192107689995742653">"Стандартний пріоритет"</string>
<string name="high_importance" msgid="1527066195614050263">"Високий пріоритет"</string>
<string name="max_importance" msgid="5089005872719563894">"Терміново"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколи не показувати ці сповіщення"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Показувати сповіщення внизу списку без звукового сигналу"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Показувати ці сповіщення без звукового сигналу"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Показувати сповіщення вгорі списку зі звуковим сигналом"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Стандартні кольори"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Нічні кольори"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Користувацькі кольори"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Авто"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Невідомі кольори"</string>
- <string name="color_transform" msgid="6985460408079086090">"Змінення кольорів"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показати опцію швидких налаштувань"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Увімкнути користувацьке перетворення"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Колір і вигляд"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Нічний режим"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Калібрувати дисплей"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Увімкнено"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Вимкнено"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Вмикати автоматично"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Переходити на нічний режим відповідно до місцезнаходження та часу доби"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Коли нічний режим увімкнено"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Використати нічну тему для ОС Android"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Налаштувати відтінок"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Регулювати яскравість"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Темна тема застосовується в основних областях ОС Android, які зазвичай відображаються у світлій темі, як-от у налаштуваннях."</string>
<string name="color_apply" msgid="9212602012641034283">"Застосувати"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Підтвердити налаштування"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Деякі налаштування кольорів можуть зробити цей пристрій непридатним для використання. Натисніть OK, щоб підтвердити налаштування, інакше їх буде скинуто через 10 секунд."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Акумулятор (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Знижується продуктивність і обмежується обмін даними у фоновому режимі"</string>
@@ -487,21 +511,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Головний екран"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Останні"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Назад"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Показувати режим \"Не турбувати\" у вікні регулятора гучності"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Дозволити керувати режимом \"Не турбувати\" у вікні регулятора гучності."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Регулятор гучності та режим \"Не турбувати\""</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Вмикати режим \"Не турбувати\" під час зменшення гучності"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Показувати регулятори гучності"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Не турбувати"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Кнопки гучності на корпусі"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Вимикати режим \"Не турбувати\" під час збільшення гучності"</string>
<string name="battery" msgid="7498329822413202973">"Акумулятор"</string>
<string name="clock" msgid="7416090374234785905">"Годинник"</string>
<string name="headset" msgid="4534219457597457353">"Гарнітура"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Навушники під’єднано"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Гарнітуру під’єднано"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Показати або сховати значки в рядку стану."</string>
<string name="data_saver" msgid="5037565123367048522">"Заощадження трафіку"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Заощадження трафіку ввімкнено"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Заощадження трафіку вимкнено"</string>
<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>
@@ -523,4 +546,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Вибрати кнопку клавіатури"</string>
<string name="preview" msgid="9077832302472282938">"Переглянути"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Перетягуйте фрагменти, щоб додавати їх"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Редагувати"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Час"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Показувати години, хвилини та секунди"</item>
+ <item msgid="1427801730816895300">"Показувати години та хвилини (за умовчанням)"</item>
+ <item msgid="3830170141562534721">"Не показувати цей значок"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Завжди показувати відсотки"</item>
+ <item msgid="2139628951880142927">"Показувати відсотки під час заряджання (за умовчанням)"</item>
+ <item msgid="3327323682209964956">"Не показувати цей значок"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Розділювач екрана"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Перемістити вниз"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перемістити вгору"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перемістити ліворуч"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перемістити праворуч"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 8bfd7c6f219f..20a2a6f5750b 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"اسکرین شاٹ کیپچر کیا گیا۔"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"اپنے اسکرین شاٹ دیکھنے کیلئے چھوئیں۔"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"اسکرین شاٹ کیپچر نہیں کر سکے۔"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"اسٹوریج کی محدود جگہ کی وجہ سے اسکرین شاٹ نہیں لے سکتے، یا ایپ یا آپکی تنظیم کے ذریعے یہ مجاز نہیں ہے۔"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"محدود اسٹوریج جگہ کی وجہ سے اسکرین شاٹس نہیں لئے جا سکتے۔"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے۔"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏USB فائل منتقل کرنیکے اختیارات"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏ایک میڈیا پلیئر (MTP) کے بطور ماؤنٹ کریں"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"‏ایک کیمرہ (PTP) کے بطور ماؤنٹ کریں"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"مزید وقت۔"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"کم وقت۔"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"فلیش لائٹ آف ہے۔"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"فلیش لائٹ آن ہے۔"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"فلیش لائٹ کو آف کر دیا گیا۔"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"فلیش لائٹ کو آن کر دیا گیا۔"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"اسکرین کو پن کرنا"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"محفوظ موڈ میں <xliff:g id="APP">%s</xliff:g> غیر فعال ہوتی ہے۔"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"سرگزشت"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"صاف کریں"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"یہ ایپ ملٹی ونڈو کی معاونت نہیں کرتی"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"ایپ ملٹی ونڈز کی معاونت نہیں کرتی"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"مکمل\nخاموشی"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"صرف\nترجیحی"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"صرف\nالارمز"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"سبھی"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"تمام\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"تیزی سے چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"آہستہ چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
<string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"سپلٹ اسکرین کیلئے سوائپ اپ ایکسلریٹر فعال کریں"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"سپلٹ اسکرین کیلئے سوائپ اپ اشارہ فعال کریں"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"مجموعی جائزہ بٹن سے سوائپ اپ کرکے سپلٹ اسکرین میں داخل ہونے کیلئے اشارہ فعال کریں"</string>
<string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"آن کریں"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> اطلاعات پر لاگو کریں"</string>
- <string name="apply_to_app" msgid="363016783939815960">"اس ایپ سے تمام اطلاعات پر لاگو کریں"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"مسدود کردہ"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"کم اہمیت"</string>
<string name="default_importance" msgid="8192107689995742653">"عمومی اہمیت"</string>
<string name="high_importance" msgid="1527066195614050263">"زیادہ اہمیت"</string>
<string name="max_importance" msgid="5089005872719563894">"فوری اہمیت"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"یہ اطلاعات کبھی مت دکھائیں"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"اطلاعات کی فہرست کے سب سے نیچے خاموشی سے دکھائیں"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"خاموشی سے یہ اطلاعات دکھائیں"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں اور آواز چلائیں"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"اسکرین پر دکھائیں اور آواز چلائیں"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
<string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"عام رنگ"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"رات کے رنگ"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"حسب ضرورت رنگ"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"خودکار"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"نامعلوم رنگ"</string>
- <string name="color_transform" msgid="6985460408079086090">"رنگوں کی تبدیلی"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"فوری ترتیبات والی ٹائل دکھائیں"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"حسب ضرورت ٹرانسفارم فعال کریں"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"رنگ اور ظہور"</string>
+ <string name="night_mode" msgid="3540405868248625488">"رات موڈ"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"نشان زد ڈسپلے"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"آن"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"آف"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"خودکار طور پر آن کریں"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"مقام اور دن کے وقت کی مناسبت سے نائٹ موڈ میں سوئچ کریں"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"جب نائٹ موڈ آن ہو"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"‏Android OS کیلئے ڈارک تھیم استعمال کریں"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"ٹنٹ ایڈجسٹ کریں"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"چمک کو ایڈجسٹ کریں"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"‏ڈارک تھیم Android OS کی بنیادی جگہوں پر لاگو کی جاتی ہے جو عام طور لائٹ تھیم میں ڈسپلے ہوتے ہیں، جیسے ترتیبات۔"</string>
<string name="color_apply" msgid="9212602012641034283">"لاگو کریں"</string>
<string name="color_revert_title" msgid="4746666545480534663">"ترتیبات کی توثیق کریں"</string>
<string name="color_revert_message" msgid="9116001069397996691">"رنگوں کی کچھ ترتیبات اس آلے کو ناقابل استعمال بنا سکتی ہیں۔ رنگوں کی ان ترتیبات کی توثیق کرنے کیلئے ٹھیک ہے پر کلک کریں، بصورت دیگر 10 سیکنڈ بعد یہ ترتیبات ری سیٹ ہو جائیں گی۔"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"بیٹری (%%<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ہوم"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"حالیہ"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"پیچھے"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"والیوم میں ڈسٹرب نہ کریں دکھائیں"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"والیوم ڈائیلاگ میں ڈسٹرب نہ کریں کے مکمل کنٹرول کی اجازت دیں۔"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"والیوم اور ڈسٹرب نہ کریں"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"کم والیوم پر \'ڈسٹرب نہ کریں\' میں داخل ہوں"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"والیوم کنٹرولز کے ساتھ دکھائیں"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"ڈسٹرب نہ کریں"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"والیوم بٹنز کے شارٹ کٹ"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"زیادہ والیوم پر \'ڈسٹرب نہ کریں\' سے خارج ہوں"</string>
<string name="battery" msgid="7498329822413202973">"بیٹری"</string>
<string name="clock" msgid="7416090374234785905">"گھڑی"</string>
<string name="headset" msgid="4534219457597457353">"ہیڈ سیٹ"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ہیڈ فونز منسلک ہیں"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ہیڈ سیٹ منسلک ہے"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"اسٹیٹس بار میں دکھائے جانے کیلئے آئیکنز فعال یا غیر فعال کریں۔"</string>
<string name="data_saver" msgid="5037565123367048522">"ڈیٹا سیور"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"ڈیٹا سیور آن ہے"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"ڈیٹا سیور آف ہے"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"کی بورڈ بٹن منتخب کریں"</string>
<string name="preview" msgid="9077832302472282938">"پیش منظر"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ٹائٹلز شامل کرنے کیلئے گھسیٹیں"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"ترمیم کریں"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"وقت"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"گھنٹے، منٹ اور سیکنڈ دکھائیں"</item>
+ <item msgid="1427801730816895300">"گھنٹے اور منٹ دکھائیں (ڈیفالٹ)"</item>
+ <item msgid="3830170141562534721">"یہ آئیکن نہ دکھائیں"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"ہمیشہ شرح فیصد دکھائیں"</item>
+ <item msgid="2139628951880142927">"چارج ہوتے وقت فیصد دکھائیں (ڈیفالٹ)"</item>
+ <item msgid="3327323682209964956">"یہ آئیکن نہ دکھائیں"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"سپلٹ اسکرین تقسیم کار"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"نیچے منتقل کریں"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"اوپر منتقل کریں"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"بائیں منتقل کریں"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"دائیں منتقل کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 315a86909796..3fc7aad034f9 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -67,13 +67,14 @@
<string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Bu qurilmaga ayni paytda o‘z hisobi bilan kirgan foydalanuvchi USB orqali tuzatish funksiyasini faollashtira olmaydi. Undan foydalanish uchun administrator profiliga o‘ting."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Ekranga moslashtirish"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ekran hajmida cho‘zish"</string>
- <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Ekran surati saqlanmoqda…"</string>
- <string name="screenshot_saving_title" msgid="8242282144535555697">"Ekran surati saqlanmoqda…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Ekran surati saqlanadi."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran surati olindi."</string>
- <string name="screenshot_saved_text" msgid="1152839647677558815">"Ekraningiz suratini ko‘rish uchun bosing."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran surati olinmadi."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Ekrandan suratga olib bo‘lmadi: xotirada joy kam yoki ilova/tashkilot bunga ruxsat bermagan."</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Skrinshot saqlanmoqda…"</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Skrinshot saqlanmoqda…"</string>
+ <string name="screenshot_saving_text" msgid="2419718443411738818">"Skrinshot saqlanmoqda."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinshot saqlandi."</string>
+ <string name="screenshot_saved_text" msgid="1152839647677558815">"Ko‘rish uchun bu yerga bosing."</string>
+ <string name="screenshot_failed_title" msgid="705781116746922771">"Skrinshot saqlanmadi."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Xotirada joy kamligi uchun skrinshotni saqlab bo‘lmadi."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Ilova yoki tashkilotingiz skrinshot olishni taqiqlagan."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB fayl ko‘chirish moslamalari"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer sifatida ulash (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera sifatida ulash (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ko‘proq vaqt."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kamroq vaqt."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Fonar o‘chirilgan."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Fonar yoqilgan."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Fonar o‘chirildi."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Fonar yoqildi."</string>
@@ -217,7 +220,7 @@
<string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Ish rejimi o‘chiq."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Ish rejimi yoniq."</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Ish rejimi o‘chirib qo‘yildi."</string>
- <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ish rejimi yoqildi."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ishchi rejim yoqildi."</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"Ekran yorqinligi"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G internet to‘xtatib qo‘yildi"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
@@ -269,7 +272,7 @@
<string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ulanmagan"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tarmoq mavjud emas"</string>
- <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chirilgan"</string>
+ <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chiq"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Hech qanday Wi-Fi tarmog‘i mavjud emas"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Wi-Fi monitor"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Translatsiya qilinmoqda"</string>
@@ -296,13 +299,16 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Cheklov: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<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="recents_empty_message" msgid="8682129509540827999">"Siz yaqinda ishlatgan ilova ekranlari bu yerda ko‘rinadi"</string>
+ <string name="recents_empty_message" msgid="8682129509540827999">"Bu yerda yaqinda ishlatilgan ilovalar ko‘rsatiladi"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"o‘zgarmas ekran"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Xavfsiz rejimda <xliff:g id="APP">%s</xliff:g> ilovasi o‘chirib qo‘yildi."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Jurnal"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Tozalash"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Tinchlik\nsaqlansin"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Faqat\nmuhimlar"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Faqat\nsignallar"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Barchasi"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Barcha\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Tez quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sekin quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
@@ -365,8 +369,8 @@
<string name="user_remove_user_message" msgid="1453218013959498039">"Ushbu foydalanuvchining barcha ilovalari va ma’lumotlari o‘chirib tashlanadi."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Olib tashlash"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Quvvat tejash rejimi yoqildi"</string>
- <string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlikni pasaytiradi va fonda int-dan foyd-ni cheklaydi"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash funksiyasini o‘chiring"</string>
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
+ <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash rejimidan chiqish"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Barchasini tozalash"</string>
@@ -374,7 +378,7 @@
<string name="empty_shade_text" msgid="708135716272867002">"Bildirishnomalar yo‘q"</string>
<string name="device_owned_footer" msgid="3802752663326030053">"Qurilma kuzatilishi mumkin"</string>
<string name="profile_owned_footer" msgid="8021888108553696069">"Profil kuzatilishi mumkin"</string>
- <string name="vpn_footer" msgid="2388611096129106812">"Tarmoq kuzatuv ostida bo‘lishi mumkin"</string>
+ <string name="vpn_footer" msgid="2388611096129106812">"Tarmoqni kuzatish mumkin"</string>
<string name="monitoring_title_device_owned" msgid="7121079311903859610">"Qurilmalarni kuzatish"</string>
<string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilni kuzatish"</string>
<string name="monitoring_title" msgid="169206259253048106">"Tarmoqlarni kuzatish"</string>
@@ -446,60 +450,79 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
<string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Tepaga surib, ekranni bo‘lish uchun tezlatkichni yoqish"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Tepaga surish orqali ekranni ikkiga bo‘lish"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umumiy ma’lumot tugmasini tepaga surish orqali ekranni bo‘lish ishorasini yoqish"</string>
<string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"“<xliff:g id="TOPIC_NAME">%1$s</xliff:g>” bildirishnomalariga qo‘llash"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Ushbu ilovaning barcha bildirishnomalariga qo‘llash"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Bloklangan"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Kamroq muhim"</string>
<string name="default_importance" msgid="8192107689995742653">"O‘rtacha muhim"</string>
<string name="high_importance" msgid="1527066195614050263">"Juda muhim"</string>
<string name="max_importance" msgid="5089005872719563894">"Favqulodda muhim"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
<string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Odatiy ranglar"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Qoramtir ranglar"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Foydalanuvchi rangi"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Avtomatik"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Noma’lum ranglar"</string>
- <string name="color_transform" msgid="6985460408079086090">"Rang sozlamalari"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tezkor sozlamalar panelini ko‘rsatish"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Foydalanuvchi sozlamalarini yoqish"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Rang va ko‘rinishi"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Tungi rejim"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Ekranni kalibrlash"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Yoniq"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"O‘chiq"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Avtomatik yoqish"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Joylashuv va vaqtga mos ravishda tungi rejimga o‘tish"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Agar tungi rejim yoniq bo‘lsa"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Android uchun to‘q rangli mavzudan foydalanish"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Rang tusini o‘zgartirish"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Yorqinlikni o‘zgartirish"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"To‘q rangli mavzu Android OS’ning o‘zak sahifalariga ham qo‘llaniladi va bu Sozlamalar kabi och rangli mavzularda odatdagiday ko‘rsatiladi."</string>
<string name="color_apply" msgid="9212602012641034283">"Qo‘llash"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Sozlamalarni tasdiqlang"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Ba’zi rang sozlamalari qurilmadan foydalanishni qiyinlashtirish mumkin. Tanlgan parametrlarni tasdiqlash uchun “OK” tugmasini bosing. Aks holda, ular 10 soniyadan so‘ng qayta tiklanadi."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Quvvat (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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>
- <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Unumdorlikni pasaytiradi va fonda internetdan foydalanishni cheklaydi"</string>
+ <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Unumdorlik pasayadi va fonda internetdan foydalanish cheklanadi"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Tizim"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Bosh ekran"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"So‘nggi ishlatilganlar"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Orqaga"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Ovoz boshqarish oynasida “Bezovta qilinmasin” panelini ko‘rsatish"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Ovoz balandligini boshqarish oynasida “Bezovta qilinmasin” rejimini to‘liq boshqarishga ruxsat beradi."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ovoz balandligini boshqarish va “Bezovta qilinmasin” rejimi"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Ovozni pasaytirganda “Bezovta qilinmasin” rejimini yoqish"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Ovoz balandligini boshqarish tugmalari bilan ko‘rsatish"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Bezovta qilinmasin"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Ovoz balandligini boshqarish tugmalari"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Ovozni ko‘targanda “Bezovta qilinmasin” rejimini o‘chirish"</string>
<string name="battery" msgid="7498329822413202973">"Batareya"</string>
<string name="clock" msgid="7416090374234785905">"Soat"</string>
<string name="headset" msgid="4534219457597457353">"Audio moslama"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Quloqchinlar ulandi"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Audio moslama ulandi"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Holat qatorida begilarning ko‘rsatilishini yoqish yoki o‘chirish."</string>
<string name="data_saver" msgid="5037565123367048522">"Trafik tejash"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Trafik tejash yoniq"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Trafik tejash o‘chiq"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Klaviatura tugmasini tanlang"</string>
<string name="preview" msgid="9077832302472282938">"Oldindan ko‘rish"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Fragmentlar qo‘shish uchun torting"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Vaqt"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Soat, daqiqa va soniyalar ko‘rsatilsin"</item>
+ <item msgid="1427801730816895300">"Soat va daqiqalar ko‘rsatilsin (birlamchi)"</item>
+ <item msgid="3830170141562534721">"Bu belgi boshqa ko‘rsatilmasin"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Har doim foizda ko‘rsatilsin"</item>
+ <item msgid="2139628951880142927">"Quvvat olayotganda foizda ko‘rsatilsin (birlamchi)"</item>
+ <item msgid="3327323682209964956">"Bu belgi boshqa ko‘rsatilmasin"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Ekranni ikkiga bo‘lgich"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pastga siljitish"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Tepaga siljitish"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Chapga siljitish"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"O‘ngga siljitish"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index b0209eee17c4..e8babe5deefc 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Đã chụp ảnh màn hình."</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Chạm để xem ảnh chụp màn hình của bạn."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Không thể chụp ảnh màn hình."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Ko thể chụp ảnh màn hình do dung lượng bộ nhớ hạn chế hoặc ứng dụng hay tổ chức của bạn ko cho phép."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Không thể lưu ảnh chụp màn hình do giới hạn dung lượng bộ nhớ."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Ứng dụng hoặc tổ chức của bạn không cho phép chụp ảnh màn hình."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Tùy chọn truyền tệp USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Gắn như một trình phát đa phương tiện (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Gắn như một máy ảnh (PTP)"</string>
@@ -206,6 +207,7 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Nhiều thời gian hơn."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Ít thời gian hơn."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Đèn pin tắt."</string>
+ <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Đèn flash không khả dụng."</string>
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Đèn pin bật."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Đã tắt đèn pin."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Đã bật đèn pin."</string>
@@ -301,8 +303,12 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"khóa màn hình"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
+ <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
+ <skip />
<string name="recents_history_button_label" msgid="5153358867807604821">"Lịch sử"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Xóa"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ứng dụng này không hỗ trợ chế độ nhiều cửa sổ"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Ứng dụng không hỗ trợ chế độ nhiều cửa sổ"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Hoàn toàn\ntắt tiếng"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Chỉ\nưu tiên"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Chỉ\nbáo thức"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Tất cả"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Tất cả\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sạc nhanh (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sạc chậm (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
@@ -446,38 +450,47 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
<string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Bật trình tăng tốc vuốt lên ở chế độ chia đôi màn hình"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bật cử chỉ vuốt lên ở chế độ chia đôi màn hình"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Cho phép cử chỉ truy cập chế độ chia đôi màn hình bằng cách vuốt lên từ nút Tổng quan"</string>
<string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bật"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Áp dụng cho thông báo <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Áp dụng cho tất cả thông báo từ ứng dụng này"</string>
+ <string name="show_silently" msgid="6841966539811264192">"Hiển thị im lặng các thông báo"</string>
+ <string name="block" msgid="2734508760962682611">"Chặn tất cả thông báo"</string>
+ <string name="do_not_silence" msgid="6878060322594892441">"Không im lặng"</string>
+ <string name="do_not_silence_block" msgid="4070647971382232311">"Không im lặng hoặc chặn"</string>
+ <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Hiển thị cài đặt tầm quan trọng đầy đủ"</string>
<string name="blocked_importance" msgid="5198578988978234161">"Bị chặn"</string>
+ <string name="min_importance" msgid="1901894910809414782">"Tầm quan trọng thấp nhất"</string>
<string name="low_importance" msgid="4109929986107147930">"Tầm quan trọng thấp"</string>
<string name="default_importance" msgid="8192107689995742653">"Tầm quan trọng bình thường"</string>
<string name="high_importance" msgid="1527066195614050263">"Tầm quan trọng cao"</string>
<string name="max_importance" msgid="5089005872719563894">"Tầm quan trọng khẩn cấp"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Không bao giờ hiển thị các thông báo này"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Hiển thị im lặng ở cuối danh sách thông báo"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Hiển thị im lặng các thông báo này"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Hiển thị ở đầu danh sách thông báo và phát ra âm thanh"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Hiển thị trên màn hình và phát ra âm thanh"</string>
+ <string name="notification_importance_min" msgid="1938190340516905748">"Hiển thị im lặng ở cuối danh sách thông báo"</string>
+ <string name="notification_importance_low" msgid="3657252049508213048">"Hiển thị im lặng các thông báo này"</string>
+ <string name="notification_importance_default" msgid="4466466472622442175">"Cho phép các thông báo này phát ra âm thanh"</string>
+ <string name="notification_importance_high" msgid="2135428926525093825">"Hiển thị trên màn hình và phát ra âm thanh"</string>
+ <string name="notification_importance_max" msgid="5806278962376556491">"Hiển thị ở đầu danh sách thông báo, hiển thị trên màn hình và phát ra âm thanh"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
<string name="notification_done" msgid="5279426047273930175">"Xong"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Màu thông thường"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Màu tối"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Màu tùy chỉnh"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Tự động"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Màu không xác định"</string>
- <string name="color_transform" msgid="6985460408079086090">"Sửa đổi màu"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Hiển thị ô Cài đặt nhanh"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Bật chuyển đổi tùy chỉnh"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Màu sắc và giao diện"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Chế độ ban đêm"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Hiệu chỉnh hiển thị"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Bật"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Tắt"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Tự động bật"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Chuyển sang Chế bộ ban đêm khi thích hợp cho vị trí và thời gian trong ngày"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Khi Chế độ ban đêm đang bật"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Sử dụng chủ đề sẫm màu cho Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Điều chỉnh phủ màu"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Điều chỉnh độ sáng"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Chủ đề sẫm màu được áp dụng cho các vùng chính của Android OS được hiển thị bình thường trong chủ đề sáng màu, chẳng hạn như Cài đặt."</string>
<string name="color_apply" msgid="9212602012641034283">"Áp dụng"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Xác nhận cài đặt"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Một số cài đặt màu có thể khiến thiết bị này không sử dụng được. Hãy nhấp vào OK để xác nhận các cài đặt màu này, nếu không những cài đặt này sẽ được đặt lại sau 10 giây."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Pin (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Giảm hiệu suất và dữ liệu nền"</string>
@@ -485,21 +498,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Màn hình chính"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Gần đây"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Quay lại"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Hiển thị không làm phiền theo âm lượng"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Cho phép kiểm soát toàn bộ tính năng không làm phiền trong hộp thoại âm lượng."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Âm lượng và Không làm phiền"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Truy cập không làm phiền khi giảm âm lượng"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Hiển thị với các điều khiển âm lượng"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Không làm phiền"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Phím tắt các nút âm lượng"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Thoát không làm phiền khi tăng âm lượng"</string>
<string name="battery" msgid="7498329822413202973">"Pin"</string>
<string name="clock" msgid="7416090374234785905">"Đồng hồ"</string>
<string name="headset" msgid="4534219457597457353">"Tai nghe"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Đã kết nối tai nghe"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Đã kết nối tai nghe"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Bật hoặc tắt biểu tượng hiển thị trong thanh trạng thái."</string>
<string name="data_saver" msgid="5037565123367048522">"Trình tiết kiệm dữ liệu"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Trình tiết kiệm dữ liệu đang bật"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Trình tiết kiệm dữ liệu đang tắt"</string>
<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>
@@ -521,4 +533,22 @@
<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="drag_to_add_tiles" msgid="7058945779098711293">"Kéo để thêm ô"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Chỉnh sửa"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Thời gian"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Hiển thị giờ, phút và giây"</item>
+ <item msgid="1427801730816895300">"Hiển thị giờ và phút (mặc định)"</item>
+ <item msgid="3830170141562534721">"Không hiển thị biểu tượng này"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Luôn hiển thị phần trăm"</item>
+ <item msgid="2139628951880142927">"Hiển thị phần trăm khi sạc (mặc định)"</item>
+ <item msgid="3327323682209964956">"Không hiển thị biểu tượng này"</item>
+ </string-array>
+ <string name="other" msgid="4060683095962566764">"Khác"</string>
+ <string name="accessibility_divider" msgid="5903423481953635044">"Bộ chia chia đôi màn hình"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Chuyển xuống"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Chuyển lên"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Di chuyển sang trái"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Di chuyển sang phải"</string>
</resources>
diff --git a/packages/SystemUI/res/values-w550dp-land/config.xml b/packages/SystemUI/res/values-w550dp-land/config.xml
index 71e54a1ca61c..16d5317636a2 100644
--- a/packages/SystemUI/res/values-w550dp-land/config.xml
+++ b/packages/SystemUI/res/values-w550dp-land/config.xml
@@ -20,5 +20,9 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
+
+ <!-- Whether QuickSettings is in a phone landscape -->
+ <bool name="quick_settings_wide">true</bool>
+
<integer name="quick_settings_num_columns">4</integer>
</resources>
diff --git a/packages/SystemUI/res/values-w550dp-land/dimens.xml b/packages/SystemUI/res/values-w550dp-land/dimens.xml
index 4160c83683cc..cd17bedcec32 100644
--- a/packages/SystemUI/res/values-w550dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-w550dp-land/dimens.xml
@@ -20,4 +20,7 @@
<dimen name="notification_panel_width">544dp</dimen>
<dimen name="qs_expand_margin">32dp</dimen>
+
+ <dimen name="battery_detail_graph_space_top">9dp</dimen>
+ <dimen name="battery_detail_graph_space_bottom">9dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a8522219b688..d48a9e6e056d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"已抓取屏幕截图。"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"触摸可查看您的屏幕截图。"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"无法抓取屏幕截图。"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"无法进行屏幕截图,原因可能是存储空间不足,或者该应用或您所属的单位不允许执行此操作。"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由于存储空间有限,无法保存屏幕截图。"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"此应用或贵单位不允许进行屏幕截图。"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB文件传输选项"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器(MTP)装载"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"作为相机(PTP)装载"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"延长时间。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"缩短时间。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"手电筒关闭。"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"手电筒打开。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"手电筒已关闭。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"手电筒已打开。"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"固定屏幕"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>已在安全模式下停用。"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"历史记录"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此应用不支持多窗口模式"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"应用不支持多窗口模式"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"完全\n静音"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"仅限\n优先打扰"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"仅限\n闹钟"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"全部\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在慢速充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
<string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"启用分屏向上滑动加速器"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"启用分屏上滑手势"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"启用通过从“概览”按钮向上滑动的手势进入分屏模式"</string>
<string name="experimental" msgid="6198182315536726162">"实验性"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"开启"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"应用于<xliff:g id="TOPIC_NAME">%1$s</xliff:g>通知"</string>
- <string name="apply_to_app" msgid="363016783939815960">"应用于来自此应用的所有通知"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"屏蔽"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"重要性:低"</string>
<string name="default_importance" msgid="8192107689995742653">"重要性:一般"</string>
<string name="high_importance" msgid="1527066195614050263">"重要性:高"</string>
<string name="max_importance" msgid="5089005872719563894">"重要性:紧急"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"一律不显示这些通知"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"在通知列表底部显示,但不发出提示音"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"显示这些通知,但不发出提示音"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"在通知列表顶部显示,并发出提示音"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"在屏幕上持续显示,并发出提示音"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"常规颜色"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"夜间颜色"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"自定义颜色"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"自动"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"未知颜色"</string>
- <string name="color_transform" msgid="6985460408079086090">"颜色修改"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"显示“快捷设置”图块"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"启用自定义转换"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"颜色和外观"</string>
+ <string name="night_mode" msgid="3540405868248625488">"夜间模式"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"校准显示画面"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"开启"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"关闭"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"自动开启"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"根据地点和时间适时切换到夜间模式"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"夜间模式开启时"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"对 Android 操作系统使用深色主题背景"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"调整色调"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"调整亮度"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"系统会将深色主题背景应用于 Android 操作系统的核心区域(通常以浅色主题背景显示),例如“设置”部分。"</string>
<string name="color_apply" msgid="9212602012641034283">"应用"</string>
<string name="color_revert_title" msgid="4746666545480534663">"确认设置"</string>
<string name="color_revert_message" msgid="9116001069397996691">"部分颜色设置可能会导致此设备无法使用。请点击“确定”确认这些颜色设置,否则,系统将在 10 秒后重置这些设置。"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"电池 (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低性能并限制后台流量"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主屏幕"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"在音量对话框中显示“请勿打扰”模式"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"允许在音量对话框中完全控制“请勿打扰”模式。"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量和“请勿打扰”设置"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"按音量调低键时进入“请勿打扰”模式"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"与音量控件一起显示"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"请勿打扰"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按钮快捷键"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"按音量调高键时退出“请勿打扰”模式"</string>
<string name="battery" msgid="7498329822413202973">"电池"</string>
<string name="clock" msgid="7416090374234785905">"时钟"</string>
<string name="headset" msgid="4534219457597457353">"耳机"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"已连接到耳机"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"已连接到耳机"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"指定在状态栏中显示或隐藏图标。"</string>
<string name="data_saver" msgid="5037565123367048522">"流量节省程序"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"流量节省程序已开启"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"流量节省程序已关闭"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"选择键盘按钮"</string>
<string name="preview" msgid="9077832302472282938">"预览"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"拖动即可添加图块"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"修改"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"时间"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"显示小时、分钟和秒"</item>
+ <item msgid="1427801730816895300">"显示小时和分钟(默认)"</item>
+ <item msgid="3830170141562534721">"不显示此图标"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"一律显示百分比"</item>
+ <item msgid="2139628951880142927">"充电时显示百分比(默认)"</item>
+ <item msgid="3327323682209964956">"不显示此图标"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"分屏分隔线"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下移"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上移"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左移"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右移"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 3402fc29da5f..609f94d2b7be 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"已擷取螢幕畫面。"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看螢幕擷取畫面。"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"無法擷取螢幕畫面。"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"由於儲存空間有限,或被應用程式或貴機構禁止,因此無法擷取螢幕擷圖。"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"此應用程式或您的機構禁止擷取螢幕畫面。"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」已在安全模式中停用。"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"記錄"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此應用程式不支援多視窗模式"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"應用程式不支援多視窗模式"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"完全\n靜音"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅限\n優先"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅限\n鬧鐘"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"全部\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在緩慢充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
<string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"啟用分割畫面向上滑動加速工具"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上快速滑動手勢"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"從 [概覽] 按鈕向上快速滑動,即可使用手勢功能進入分割畫面模式"</string>
<string name="experimental" msgid="6198182315536726162">"實驗版"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"套用到「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」通知"</string>
- <string name="apply_to_app" msgid="363016783939815960">"套用到此應用程式的所有通知"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"已封鎖"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
<string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
<string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
<string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"永不顯示這些通知"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部但不發出音效"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知但不發出音效"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂部並發出音效"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"不時於螢幕出現並發出音效"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"一般色系"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"深沉色系"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"自動"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"不明色系"</string>
- <string name="color_transform" msgid="6985460408079086090">"顏色修改"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"顯示「快速設定」圖塊"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"啟用自訂變色功能"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
+ <string name="night_mode" msgid="3540405868248625488">"夜間模式"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"校準螢幕"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"已開啟"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"已關閉"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"自動開啟"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"在適當的位置和時間切換至「夜間模式」"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"「夜間模式」開啟時"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"在 Android OS 中使用深色主題背景"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"調整色調"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"調整亮度"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"系統會將深色主題背景套用至 Android OS 核心區域 (一般以淺色主題背景顯示),例如「設定」。"</string>
<string name="color_apply" msgid="9212602012641034283">"套用"</string>
<string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
<string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定會令此裝置無法使用。請按一下 [確定] 加以確認,否則這些顏色設定將於 10 秒後重設。"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"電池電量 (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景數據傳輸"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近的活動"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"在音量對話框中顯示「請勿騷擾」設定"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"允許在音量對話框中全面控制「請勿騷擾」功能。"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量和「請勿騷擾」設定"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"調低音量時啟用「請勿騷擾」模式"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制一起顯示"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"請勿騷擾"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"調高音量時停用「請勿騷擾」模式"</string>
<string name="battery" msgid="7498329822413202973">"電池"</string>
<string name="clock" msgid="7416090374234785905">"時鐘"</string>
<string name="headset" msgid="4534219457597457353">"耳機"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"已連接至耳機"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"已連接至耳機"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"顯示或隱藏狀態列上的圖示。"</string>
<string name="data_saver" msgid="5037565123367048522">"數據節省程式"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"數據節省程式已開啟"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"數據節省程式已關閉"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"選取鍵盤按鈕"</string>
<string name="preview" msgid="9077832302472282938">"預覽"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"拖曳即可新增圖塊"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"時間"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"顯示小時、分鐘和秒"</item>
+ <item msgid="1427801730816895300">"顯示小時和分鐘 (預設)"</item>
+ <item msgid="3830170141562534721">"不顯示這個圖示"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"永遠顯示百分比"</item>
+ <item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
+ <item msgid="3327323682209964956">"不顯示這個圖示"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b9e34868e6db..2188c3c2b920 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"已拍攝螢幕擷取畫面。"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看螢幕擷取畫面。"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"無法拍攝螢幕擷取畫面。"</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"由於儲存空間有限,或是遭到應用程式或貴機構禁止,因此無法擷取螢幕畫面。"</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"這個應用程式或貴機構禁止擷取螢幕畫面。"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」在安全模式中為停用狀態。"</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"紀錄"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"清除"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"這個應用程式不支援多視窗模式"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"應用程式不支援多視窗模式"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"完全\n靜音"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅允許\n優先通知"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅允許\n鬧鐘"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"全部\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"快速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"慢速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
<string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
<string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"啟用分割畫面向上滑動加速工具"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上滑動手勢"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"啟用透過從 [總覽] 按鈕向上滑動的手勢進入分割畫面"</string>
<string name="experimental" msgid="6198182315536726162">"實驗性"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"套用到「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」通知"</string>
- <string name="apply_to_app" msgid="363016783939815960">"套用到這個應用程式的所有通知"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"封鎖"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
<string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
<string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
<string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"一律不顯示這些通知"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部且不發出任何音效"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知且不發出任何音效"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂端並發出音效"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"短暫顯示在螢幕上並發出音效"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"一般顏色"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"夜間顏色"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"自動"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"不明顏色"</string>
- <string name="color_transform" msgid="6985460408079086090">"顏色修改"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"顯示快速設定圖塊"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"啟用自訂顏色變換"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
+ <string name="night_mode" msgid="3540405868248625488">"夜間模式"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"校正顯示畫面"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"開啟"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"關閉"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"自動開啟"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"根據地點和時段適時切換到「夜間模式」"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"「夜間模式」開啟時"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"針對 Android 作業系統使用深色主題"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"調整色調"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"調整亮度"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"深色主題會套用到 Android 作業系統的核心區塊 (一般是以淺色主題顯示),例如「設定」區塊。"</string>
<string name="color_apply" msgid="9212602012641034283">"套用"</string>
<string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
<string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定可能會造成這部裝置無法使用。請按一下 [確定] 來確認您要使用這類顏色設定,否則系統將在 10 秒後重設這些設定。"</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"電池 (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低效能並限制背景資料傳輸"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主畫面"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"近期活動"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"返回"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"在音量對話方塊中顯示「零打擾」設定"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"在音量對話方塊中顯示完整的「零打擾」設定。"</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"音量和「零打擾」設定"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"按下調低音量鍵時啟用「零打擾」模式"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"與音量控制項一起顯示"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"零打擾"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"音量按鈕快速鍵"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"按下調高音量鍵時停用「零打擾」模式"</string>
<string name="battery" msgid="7498329822413202973">"電池"</string>
<string name="clock" msgid="7416090374234785905">"時鐘"</string>
<string name="headset" msgid="4534219457597457353">"耳機"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"已與耳機連線"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"已與耳機連線"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"指定在狀態列中顯示或隱藏圖示。"</string>
<string name="data_saver" msgid="5037565123367048522">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Data Saver 已開啟"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Data Saver 已關閉"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"選取鍵盤按鍵"</string>
<string name="preview" msgid="9077832302472282938">"預覽"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"拖曳即可新增圖塊"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"時間"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"顯示小時、分鐘和秒"</item>
+ <item msgid="1427801730816895300">"顯示小時和分鐘 (預設)"</item>
+ <item msgid="3830170141562534721">"不顯示這個圖示"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"一律顯示百分比"</item>
+ <item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
+ <item msgid="3327323682209964956">"不顯示這個圖示"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9f4878af9b9d..69c85ab94e6c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -73,7 +73,8 @@
<string name="screenshot_saved_title" msgid="6461865960961414961">"Umfanekiso weskrini uqoshiwe"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"Thinta ukubona imifanekiso yakho yeskrini"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Yehlulekile ukulondoloza umfanekiso weskrini."</string>
- <string name="screenshot_failed_text" msgid="1260203058661337274">"Ayikwazi ukuthatha izithombe zesikrini ngenxa yesikhala sesitoreji esikhawulelwe ngohlelo lokusebenza noma inhlangano yakho."</string>
+ <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ayikwazi ukulondoloza isithombe-skrini ngenxa yesikhala sesitoreji esikhawulelwe."</string>
+ <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Ukuthatha izithombe-skrini akuvunyelwe uhlelo lokusebenza noma inhlangano yakho."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string>
@@ -206,6 +207,8 @@
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Isikhathi esiningi."</string>
<string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Isikhathi esincane."</string>
<string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"I-Flashlight ivaliwe."</string>
+ <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
+ <skip />
<string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"I-Flashlight ivuliwe."</string>
<string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"I-Flashlight ivaliwe."</string>
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"I-Flashlight ivuliwe."</string>
@@ -301,8 +304,11 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ukuphina isikrini"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"I-<xliff:g id="APP">%s</xliff:g> ikhutshaziwe kumodi yokuphepha."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Umlando"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Sula"</string>
+ <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Lolu hlelo lokusebenza alusekeli amawindi amaningi"</string>
+ <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Uhlelo lokusebenza alusekeli amawindi amaningi"</string>
<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>
@@ -332,8 +338,6 @@
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Ukuthula\niokuphelele"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Okubalulekile\nkuphela"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ama-alamu\nkuphela"</string>
- <string name="interruption_level_all" msgid="1330581184930945764">"Konke"</string>
- <string name="interruption_level_all_twoline" msgid="3719402899156124780">"Konke\n"</string>
<string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
<string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Iyashaja ngokushesha (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Iyashaja kancane (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
@@ -446,38 +450,58 @@
<string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
<string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
<string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
- <string name="overview_nav_bar_gesture" msgid="1852503363271291341">"Nika amandla isisheshisi sokuhlukanisa isikrini sokuswayiphela phezulu"</string>
+ <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Nika amandla ukuthinta kokuswayiphela phezulu ukuhlukanisa isikrini"</string>
<string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Nika amandla ukuthinta ukuze ungene ekuhlukaniseni isikrini ngokuswayiphela phezulu kusukela kunkinobho yokubuka konke"</string>
<string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vula"</string>
- <string name="apply_to_topic" msgid="3641403489318659666">"Sebenzisa kuzaziso ze-<xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
- <string name="apply_to_app" msgid="363016783939815960">"Sebenzisa kuzo zonke izaziso ezivela kulolu hlelo lokusebenza"</string>
+ <!-- no translation found for show_silently (6841966539811264192) -->
+ <skip />
+ <!-- no translation found for block (2734508760962682611) -->
+ <skip />
+ <!-- no translation found for do_not_silence (6878060322594892441) -->
+ <skip />
+ <!-- no translation found for do_not_silence_block (4070647971382232311) -->
+ <skip />
+ <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
+ <skip />
<string name="blocked_importance" msgid="5198578988978234161">"Kuvinjelwe"</string>
+ <!-- no translation found for min_importance (1901894910809414782) -->
+ <skip />
<string name="low_importance" msgid="4109929986107147930">"Ukubaluleka okuphansi"</string>
<string name="default_importance" msgid="8192107689995742653">"Ukubaluleka okujwayelekile"</string>
<string name="high_importance" msgid="1527066195614050263">"Ukubaluleka okuphezulu"</string>
<string name="max_importance" msgid="5089005872719563894">"Ukubaluleka okusheshayo"</string>
<string name="notification_importance_blocked" msgid="2397192642657872872">"Ungalokothi ubonise lezi zaziso"</string>
- <string name="notification_importance_low" msgid="4383563267370859725">"Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
- <string name="notification_importance_default" msgid="4926529615920610817">"Bonisa ngokuthulile lezi zaziso"</string>
- <string name="notification_importance_high" msgid="3222680136612408223">"Bonisa ngaphezulu kohlu lwezaziso uphinde wenze umsindo"</string>
- <string name="notification_importance_max" msgid="5236987171904756134">"Bheka kusikrini uphinde wenze umsindo"</string>
+ <!-- no translation found for notification_importance_min (1938190340516905748) -->
+ <skip />
+ <!-- no translation found for notification_importance_low (3657252049508213048) -->
+ <skip />
+ <!-- no translation found for notification_importance_default (4466466472622442175) -->
+ <skip />
+ <!-- no translation found for notification_importance_high (2135428926525093825) -->
+ <skip />
+ <!-- no translation found for notification_importance_max (5806278962376556491) -->
+ <skip />
<string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
<string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
- <string name="color_matrix_none" msgid="2121957926040543148">"Imibala ejwayelekile"</string>
- <string name="color_matrix_night" msgid="5943817622105307072">"Imibala yasebusuku"</string>
- <string name="color_matrix_custom" msgid="3655576492322298713">"Imibala yangokwezifiso"</string>
- <string name="color_matrix_auto" msgid="4896624757412029265">"Okuzenzakalelayo"</string>
- <string name="color_matrix_unknown" msgid="2709202104256265107">"Imibala engaziwa"</string>
- <string name="color_transform" msgid="6985460408079086090">"Ukulungiswa kombala"</string>
- <string name="color_matrix_show_qs" msgid="1763244354399276679">"Bonisa ithayili lezilungiselelo ezisheshayo"</string>
- <string name="color_enable_custom" msgid="6729001308217347501">"Nika amandla ukuguqulwa kwangokwezifiso"</string>
+ <string name="color_and_appearance" msgid="1254323855964993144">"Umbala nokubonakala"</string>
+ <string name="night_mode" msgid="3540405868248625488">"Imodi yasebusuku"</string>
+ <string name="calibrate_display" msgid="5974642573432039217">"Sika isibonisi"</string>
+ <string name="night_mode_on" msgid="5597545513026541108">"Vuliwe"</string>
+ <string name="night_mode_off" msgid="8035605276956057508">"Valiwe"</string>
+ <string name="turn_on_automatically" msgid="4167565356762016083">"Vula ngokuzenzakalela"</string>
+ <string name="turn_on_auto_summary" msgid="2190994512406701520">"Shintshela kwimodi yasebusuku njengokuqondile ngendawo nesikhathi sosuku"</string>
+ <string name="when_night_mode_on" msgid="2969436026899172821">"Uma imodi yasebusuku ivulekile"</string>
+ <string name="use_dark_theme" msgid="2900938704964299312">"Sebenzisa ingqikithi emnyama ku-Android OS"</string>
+ <string name="adjust_tint" msgid="3398569573231409878">"Lungisa i-tint"</string>
+ <string name="adjust_brightness" msgid="980039329808178246">"Lungisa ukukhanya"</string>
+ <string name="night_mode_disclaimer" msgid="598914896926759578">"Itimu emnyama isetshenziswa ezindaweni eziqinile ze-Android OS ezivamise ukuoniswa ngetimu ekhanyayo, efana nezilungiselelo."</string>
<string name="color_apply" msgid="9212602012641034283">"Sebenzisa"</string>
<string name="color_revert_title" msgid="4746666545480534663">"Qinisekisa izilungiselelo"</string>
<string name="color_revert_message" msgid="9116001069397996691">"Ezinye izilungiselelo zombala zingenza le divayisi ingasebenziseki. Chofoza ku-KULUNGILE ukuze uqinisekise lezi zilungiselelo zombala, uma kungenjalo lezi zilungiselelo zizosethwa kabusha ngemuva kwamasekhondi angu-10."</string>
- <string name="battery_panel_title" msgid="3476715163685592453">"Ibhethri (<xliff:g id="ID_1">%1$d</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>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"Sehlisa ukusebenza nedatha yasemuva"</string>
@@ -485,21 +509,20 @@
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ekhaya"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Okwakamuva"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Emuva"</string>
- <string name="tuner_full_zen_title" msgid="5905081395132280054">"Bonisa ukungaphazamisi kuvolumu"</string>
- <string name="tuner_full_zen_summary" msgid="6883568374520596402">"Vumela ulawulo olugcwele lokungaphazamisi kungxoxo yevolumu."</string>
- <string name="volume_and_do_not_disturb" msgid="3114580364524650941">"Ivolumu nokungaphazamisi"</string>
- <string name="volume_down_silent" msgid="66962568467719591">"Faka ukungaphazamisi ekwehliseni ivolumu"</string>
+ <string name="tuner_full_zen_title" msgid="4540823317772234308">"Bonisa ngezilawuli zevolomu"</string>
+ <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ungaphazamisi"</string>
+ <string name="volume_dnd_silent" msgid="4363882330723050727">"Izinqamuleli zezinkinobho zevolomu"</string>
<string name="volume_up_silent" msgid="7141255269783588286">"Phuma kokuthi ungaphazamisi ekukhuphuleni ivolumu"</string>
<string name="battery" msgid="7498329822413202973">"Ibhethri"</string>
<string name="clock" msgid="7416090374234785905">"Iwashi"</string>
<string name="headset" msgid="4534219457597457353">"Ama-earphone"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Amahedfoni axhunyiwe"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Ama-earphone axhunyiwe"</string>
- <string name="tuner_status_bar_explanation" msgid="9032196769944137864">"Nika amandla noma khubaza izithonjana kusukela ekubonisweni kubha yesimo."</string>
<string name="data_saver" msgid="5037565123367048522">"Iseva yedatha"</string>
<string name="accessibility_data_saver_on" msgid="8454111686783887148">"Iseva yedatha ivuliwe"</string>
<string name="accessibility_data_saver_off" msgid="8841582529453005337">"Iseva yedatha ivaliwe"</string>
<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>
@@ -521,4 +544,23 @@
<string name="select_keycode" msgid="7413765103381924584">"Khetha inkinobho yekhibhodi"</string>
<string name="preview" msgid="9077832302472282938">"Hlola kuqala"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"Hudula ukuze ungeze amathayili"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"Hlela"</string>
+ <string name="tuner_time" msgid="6572217313285536011">"Isikhathi"</string>
+ <string-array name="clock_options">
+ <item msgid="5965318737560463480">"Bonisa amahora, amaminithi, namasekhondi"</item>
+ <item msgid="1427801730816895300">"Bonisa amahora namaminithi (okuzenzakalelayo)"</item>
+ <item msgid="3830170141562534721">"Ungabonisi lesi sithonjana"</item>
+ </string-array>
+ <string-array name="battery_options">
+ <item msgid="3160236755818672034">"Njlalo bonisa iphesentheji"</item>
+ <item msgid="2139628951880142927">"Bonisa iphesentheji uma ishaja (okuzenzakalelayo)"</item>
+ <item msgid="3327323682209964956">"Ungabonisi lesi sithonjana"</item>
+ </string-array>
+ <!-- no translation found for other (4060683095962566764) -->
+ <skip />
+ <string name="accessibility_divider" msgid="5903423481953635044">"Isihlukanisi sokuhlukanisa isikrini"</string>
+ <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Iya phansi"</string>
+ <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Iya phezulu"</string>
+ <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Iya kwesokunxele"</string>
+ <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Iya kwesokudla"</string>
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 19bc75594db8..189eb3be302a 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -91,6 +91,7 @@
<declare-styleable name="TunerSwitch">
<attr name="defValue" format="boolean" />
+ <attr name="metricsAction" format="integer" />
</declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a9b8df2934c7..8f69bbb16000 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -52,8 +52,12 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
+ <!-- The disabled recents task bar background color. -->
+ <color name="recents_task_bar_disabled_background_color">#ff676767</color>
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#ffe6e6e6</color>
+ <!-- The default recents task view background color. -->
+ <color name="recents_task_view_default_background_color">#fff3f3f3</color>
<!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
<color name="recents_task_bar_light_text_color">#ffeeeeee</color>
<!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
@@ -98,6 +102,9 @@
<!-- The color of the circle around the primary user in the user switcher -->
<color name="current_user_border_color">@color/system_accent_color</color>
+ <!-- The color of the gear shown behind a notification -->
+ <color name="notification_gear_color">#ff757575</color>
+
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">#eeeeee</color>
<color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a6ba8b59303d..4e1680d54653 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -89,6 +89,9 @@
<!-- Min alpha % that recent items will fade to while being dismissed -->
<integer name="config_recent_item_min_alpha">3</integer>
+ <!-- Whether QuickSettings is in a phone landscape -->
+ <bool name="quick_settings_wide">false</bool>
+
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
@@ -165,9 +168,6 @@
<!-- The animation duration for entering and exiting the history. -->
<integer name="recents_history_transition_duration">250</integer>
- <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
- <integer name="recents_max_task_stack_view_dim">96</integer>
-
<!-- The delay to enforce between each alt-tab key press. -->
<integer name="recents_alt_tab_key_delay">200</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e5e5710cd68a..fbe0207a1a1c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -58,7 +58,7 @@
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
<!-- Height of a small notification in the status bar-->
- <dimen name="notification_min_height">84dp</dimen>
+ <dimen name="notification_min_height">86dp</dimen>
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
@@ -78,6 +78,18 @@
<!-- 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>
+
+ <!-- Height of the space containing the gear icon behind a notification -->
+ <dimen name="notification_gear_height">74dp</dimen>
+
+ <!-- The space above the gear icon displayed behind a notification -->
+ <dimen name="notification_gear_top_padding">30dp</dimen>
+
+ <!-- The space on either side and below the gear icon displayed behind a notification -->
+ <dimen name="notification_gear_padding">20dp</dimen>
+
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">17dip</dimen>
@@ -162,7 +174,11 @@
<dimen name="qs_tile_margin">16dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
- <dimen name="qs_date_anim_translation">44.5dp</dimen>
+ <dimen name="qs_date_anim_translation">32dp</dimen>
+ <dimen name="qs_date_alarm_anim_translation">22dp</dimen>
+ <dimen name="qs_date_collapsed_text_size">14sp</dimen>
+ <dimen name="qs_date_text_size">16sp</dimen>
+ <dimen name="qs_header_gear_translation">150dp</dimen>
<dimen name="qs_page_indicator_size">12dp</dimen>
<dimen name="qs_tile_icon_size">24dp</dimen>
<dimen name="qs_tile_text_size">12sp</dimen>
@@ -187,6 +203,7 @@
<dimen name="qs_data_usage_text_size">14sp</dimen>
<dimen name="qs_data_usage_usage_text_size">36sp</dimen>
<dimen name="qs_expand_margin">0dp</dimen>
+ <dimen name="qs_battery_padding">2dp</dimen>
<dimen name="segmented_button_spacing">0dp</dimen>
<dimen name="borderless_button_radius">2dp</dimen>
@@ -218,7 +235,7 @@
<dimen name="glowpadview_inner_radius">15dip</dimen>
<!-- The size of the icon in the recents task view header. -->
- <dimen name="recents_task_view_header_icon_width">64dp</dimen>
+ <dimen name="recents_task_view_header_icon_width">56dp</dimen>
<dimen name="recents_task_view_header_icon_height">@dimen/recents_task_bar_height</dimen>
<!-- The size of a button in the recents task view header. -->
@@ -227,12 +244,14 @@
<!-- The radius of the rounded corners on a task view. -->
<dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
+ <!-- The radius of the rounded corners on a task view's shadow. -->
+ <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen>
<!-- The min translation in the Z index for the last task. -->
- <dimen name="recents_task_view_z_min">16dp</dimen>
+ <dimen name="recents_task_view_z_min">3dp</dimen>
<!-- The max translation in the Z index for the last task. -->
- <dimen name="recents_task_view_z_max">48dp</dimen>
+ <dimen name="recents_task_view_z_max">24dp</dimen>
<!-- The amount to translate when animating the removal of a task. -->
<dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
@@ -244,20 +263,20 @@
<dimen name="recents_task_view_affiliate_group_enter_offset">32dp</dimen>
<!-- The height of a task view bar. -->
- <dimen name="recents_task_bar_height">56dp</dimen>
+ <dimen name="recents_task_bar_height">50dp</dimen>
<!-- The height of the search bar space. -->
<dimen name="recents_search_bar_space_height">64dp</dimen>
- <!-- The side padding for the task stack as a percentage of the width. -->
- <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.03333</item>
-
<!-- The overscroll percentage allowed on the stack. -->
<item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
- <!-- The top offset for the task stack. -->
+ <!-- The top padding for the task stack. -->
<dimen name="recents_stack_top_padding">16dp</dimen>
+ <!-- The side padding for the task stack. -->
+ <dimen name="recents_stack_left_right_padding">16dp</dimen>
+
<!-- The dimesnsions of the dismiss all recents button. -->
<dimen name="recents_dismiss_all_button_size">48dp</dimen>
@@ -273,8 +292,11 @@
<!-- The amount to allow the stack to overscroll. -->
<dimen name="recents_stack_overscroll">24dp</dimen>
- <!-- The size of the peek area at the top of the stack. -->
- <dimen name="recents_layout_focused_peek_size">@dimen/recents_history_button_height</dimen>
+ <!-- The size of the peek area at the top of the stack (below the status bar). -->
+ <dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
+
+ <!-- The size of each task peek area at the bottom of the stack (above the nav bar). -->
+ <dimen name="recents_layout_focused_bottom_task_peek_size">16dp</dimen>
<!-- The height of the history button. -->
<dimen name="recents_history_button_height">48dp</dimen>
@@ -282,9 +304,6 @@
<!-- The padding between freeform workspace tasks -->
<dimen name="recents_freeform_workspace_task_padding">8dp</dimen>
- <!-- Space reserved for the cards behind the top card in the top stack -->
- <dimen name="top_stack_peek_amount">12dp</dimen>
-
<!-- Space reserved for the cards behind the top card in the bottom stack -->
<dimen name="bottom_stack_peek_amount">12dp</dimen>
@@ -295,9 +314,6 @@
<!-- The height of the area before the bottom stack in which the notifications slow down -->
<dimen name="bottom_stack_slow_down_length">12dp</dimen>
- <!-- The height of the area before the top stack in which the notifications slow down -->
- <dimen name="top_stack_slow_down_length">12dp</dimen>
-
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">0.5dp</dimen>
@@ -336,8 +352,8 @@
<!-- The margin between the clock and the notifications on Keyguard. See
keyguard_clock_height_fraction_* for the difference between min and max.-->
- <dimen name="keyguard_clock_notifications_margin_min">24dp</dimen>
- <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_min">30dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">42dp</dimen>
<dimen name="heads_up_scrim_height">250dp</dimen>
<!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
@@ -513,6 +529,13 @@
<dimen name="battery_margin_bottom">0dp</dimen>
+ <!-- Padding at the end of the view that displays the mobile signal icons. If the view is
+ empty, then this padding will not be added to that view. -->
+ <dimen name="mobile_signal_group_end_padding">0dp</dimen>
+
+ <!-- Padding between the mobile data type and the strength indicator. -->
+ <dimen name="mobile_data_icon_start_padding">0dp</dimen>
+
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide. -->
<dimen name="wide_type_icon_start_padding">2dp</dimen>
@@ -599,9 +622,6 @@
<dimen name="fab_elevation">12dp</dimen>
<dimen name="fab_press_translation_z">9dp</dimen>
- <!-- TODO: Remove this -->
- <dimen name="qs_header_neg_padding">-8dp</dimen>
-
<!-- How high we lift the divider when touching -->
<dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
@@ -610,4 +630,7 @@
<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>
</resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 77605bd3133e..bf32cc7505b7 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -31,4 +31,7 @@
<!-- Values for focus animation -->
<dimen name="recents_tv_unselected_item_z">6dp</dimen>
<dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
-</resources> \ No newline at end of file
+
+ <!-- Extra space around the PIP and its outline in PIP onboarding activity -->
+ <dimen name="tv_pip_bounds_space">3dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 87aedab6eec5..b9eee2e5d913 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -44,6 +44,10 @@
<item type="id" name="notification_screenshot"/>
<item type="id" name="notification_hidden"/>
<item type="id" name="notification_volumeui"/>
+ <item type="id" name="transformation_start_x_tag"/>
+ <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"/>
<!-- Whether the icon is from a notification for which targetSdk < L -->
<item type="id" name="icon_is_pre_L"/>
@@ -56,5 +60,11 @@
<item type="id" name="image_icon_tag" />
<item type="id" name="contains_transformed_view" />
<item type="id" name="is_clicked_heads_up_tag" />
+
+ <!-- Accessibility actions for the docked stack divider -->
+ <item type="id" name="action_move_left" />
+ <item type="id" name="action_move_right" />
+ <item type="id" name="action_move_up" />
+ <item type="id" name="action_move_down" />
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6ff9be14b3ce..1f239c3d1aa8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -186,7 +186,9 @@
<!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
<string name="screenshot_failed_title">Couldn\'t capture screenshot.</string>
<!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
- <string name="screenshot_failed_text">Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organization.</string>
+ <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space.</string>
+ <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
+ <string name="screenshot_failed_to_capture_text">Taking screenshots is not allowed by the app or your organization.</string>
<!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
<string name="usb_preference_title">USB file transfer options</string>
@@ -495,6 +497,8 @@
<string name="accessibility_quick_settings_less_time">Less time.</string>
<!-- Content description of the flashlight tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_flashlight_off">Flashlight off.</string>
+ <!-- Content description of the flashlight tile in quick settings when unavailable (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_flashlight_unavailable">Flashlight unavailable.</string>
<!-- Content description of the flashlight tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_flashlight_on">Flashlight on.</string>
<!-- Announcement made when the flashlight state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -714,10 +718,16 @@
<string name="recents_search_bar_label">search</string>
<!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
<string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+ <!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
+ <string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
<!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
<string name="recents_history_button_label">History</string>
<!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
<string name="recents_history_clear_all_button_label">Clear</string>
+ <!-- Recents: Non-dockable task drag message. [CHAR LIMIT=NONE] -->
+ <string name="recents_drag_non_dockable_task_message">This app does not support multi-window</string>
+ <!-- Recents: Non-dockable task launch sub header. [CHAR LIMIT=NONE] -->
+ <string name="recents_launch_non_dockable_task_label">App does not support multi-window</string>
<!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
<string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
@@ -808,12 +818,6 @@
<!-- Interruption level: Alarms only. Optimized for narrow two-line display. [CHAR LIMIT=40] -->
<string name="interruption_level_alarms_twoline">Alarms\nonly</string>
- <!-- Interruption level: All interruptions. [CHAR LIMIT=40] -->
- <string name="interruption_level_all">All</string>
-
- <!-- Interruption level: All interruptions. Optimized for narrow two-line display. [CHAR LIMIT=40] -->
- <string name="interruption_level_all_twoline">All\n</string>
-
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
<string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
@@ -1174,18 +1178,13 @@
<!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
<string name="qs_paging" translatable="false">Use the new Quick Settings</string>
- <!-- Toggles fast-toggling recents via the recents button. DO NOT TRANSLATE -->
- <string name="overview_fast_toggle_via_button">Enable fast toggle</string>
+ <!-- Disables fast-toggling recents via the recents button. DO NOT TRANSLATE -->
+ <string name="overview_disable_fast_toggle_via_button">Disable fast toggle</string>
<!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
- <string name="overview_fast_toggle_via_button_desc">Enable launch timeout while paging</string>
-
- <!-- Toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
- <string name="overview_initial_state_paging">Initialize to paging</string>
- <!-- Description for the toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
- <string name="overview_initial_state_paging_desc">Determines whether Overview will initially be in a stacked or paged state</string>
+ <string name="overview_disable_fast_toggle_via_button_desc">Disable launch timeout while paging</string>
<!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
- <string name="overview_nav_bar_gesture">Enable split-screen swipe-up accelerator</string>
+ <string name="overview_nav_bar_gesture">Enable split-screen swipe-up gesture</string>
<!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
<string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string>
@@ -1193,7 +1192,6 @@
settings are -->
<string name="experimental">Experimental</string>
- <string name="save" translatable="false">Save</string>
<string name="qs_customize" translatable="false">Allow long-press customize in Quick Settings</string>
<string name="qs_customize_info" translatable="false">Info</string>
<string name="qs_customize_remove" translatable="false">Remove</string>
@@ -1209,12 +1207,22 @@
<!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
<string name="enable_bluetooth_confirmation_ok">Turn on</string>
- <!-- Apply notification importance setting to a topic [CHAR LIMIT=NONE] -->
- <string name="apply_to_topic">Apply to <xliff:g id="topic_name" example="Friend Request">%1$s</xliff:g> notifications</string>
- <!-- Apply notification importance setting to an app [CHAR LIMIT=NONE] -->
- <string name="apply_to_app">Apply to all notifications from this app</string>
+ <!-- [CHAR LIMIT=100] Notification importance option -->
+ <string name="show_silently">Show notifications silently</string>
+ <!-- [CHAR LIMIT=100] Notification importance option -->
+ <string name="block">Block all notifications</string>
+ <!-- [CHAR LIMIT=100] Notification importance option -->
+ <string name="do_not_silence">Don\'t silence</string>
+ <!-- [CHAR LIMIT=100] Notification importance option -->
+ <string name="do_not_silence_block">Don\'t silence or block</string>
+
+ <!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
+ <string name="tuner_full_importance_settings">Show full importance settings</string>
+
<!-- Notification importance title, blocked status-->
<string name="blocked_importance">Blocked</string>
+ <!-- Notification importance title, min status-->
+ <string name="min_importance">Min importance</string>
<!-- Notification importance title, low status-->
<string name="low_importance">Low importance</string>
<!-- Notification importance title, normal status-->
@@ -1227,46 +1235,63 @@
<!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
<string name="notification_importance_blocked">Never show these notifications</string>
+ <!-- [CHAR LIMIT=100] Notification Importance slider: min importance level description -->
+ <string name="notification_importance_min">Silently show at the bottom of the notification list</string>
+
<!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
- <string name="notification_importance_low">Silently show at the bottom of the notification list</string>
+ <string name="notification_importance_low">Silently show these notifications</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
- <string name="notification_importance_default">Silently show these notifications</string>
+ <string name="notification_importance_default">Allow these notification to make sounds</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
- <string name="notification_importance_high">Show at the top of the notifications list and make sound</string>
+ <string name="notification_importance_high">Peek onto the screen and allow sound and allow sound</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
- <string name="notification_importance_max">Peek onto the screen and make sound</string>
+ <string name="notification_importance_max">Show at the top of the notifications list, peek onto the screen and allow sound</string>
<!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] -->
<string name="notification_more_settings">More settings</string>
<!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
<string name="notification_done">Done</string>
- <!-- Label for no color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_none">Normal colors</string>
+ <!-- SysUI Tuner: Color and appearance screen title [CHAR LIMIT=50] -->
+ <string name="color_and_appearance">Color and appearance</string>
- <!-- Label for night color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_night">Night colors</string>
+ <!-- SysUI Tuner: Name of the night mode feature [CHAR LIMIT=30] -->
+ <string name="night_mode">Night mode</string>
- <!-- Label for custom color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_custom">Custom colors</string>
+ <!-- SysUI Tuner: Name of calibrate display dialog [CHAR LIMIT=30] -->
+ <string name="calibrate_display">Calibrate display</string>
- <!-- Label for auto color transforms [CHAR LIMIT=30] -->
- <string name="color_matrix_auto">Auto</string>
+ <!-- SysUI Tuner: Summary of night mode when its on [CHAR LIMIT=NONE] -->
+ <string name="night_mode_on">On</string>
- <!-- Label for unknown color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_unknown">Unknown colors</string>
+ <!-- SysUI Tuner: Summary of night mode when its off [CHAR LIMIT=NONE] -->
+ <string name="night_mode_off">Off</string>
- <!-- Title for color transform [CHAR LIMIT=30] -->
- <string name="color_transform">Color modification</string>
+ <!-- SysUI Tuner: Label for switch to turn on night mode automatically [CHAR LIMIT=50] -->
+ <string name="turn_on_automatically">Turn on automatically</string>
- <!-- Title for setting to show Quick Settings tile [CHAR LIMIT=60] -->
- <string name="color_matrix_show_qs">Show Quick Settings tile</string>
+ <!-- SysUI Tuner: Summary for switch to turn on night mode automatically [CHAR LIMIT=NONE] -->
+ <string name="turn_on_auto_summary">Switch into Night Mode as appropriate for location and time of day</string>
- <!-- Title for switch to enable custom color transform [CHAR LIMIT=60] -->
- <string name="color_enable_custom">Enable custom transform</string>
+ <!-- SysUI Tuner: Label for section controlling what night mode does [CHAR LIMIT=60] -->
+ <string name="when_night_mode_on">When Night Mode is on</string>
+
+ <!-- SysUI Tuner: Switch controlling whether dark theme is turned on with night mode [CHAR LIMIT=45] -->
+ <string name="use_dark_theme">Use dark theme for Android OS</string>
+
+ <!-- SysUI Tuner: Switch controlling whether tint is changed with night mode [CHAR LIMIT=45] -->
+ <string name="adjust_tint">Adjust tint</string>
+
+ <!-- SysUI Tuner: Switch controlling whether brightness is changed with night mode [CHAR LIMIT=45] -->
+ <string name="adjust_brightness">Adjust brightness</string>
+
+ <!-- SysUI Tuner: Disclaimer about using dark theme with night mode [CHAR LIMIT=NONE] -->
+ <string name="night_mode_disclaimer">The dark theme is applied to
+ core areas of Android OS that are normally displayed in a light theme,
+ such as Settings.</string>
<!-- Button to apply settings [CHAR LIMIT=30] -->
<string name="color_apply">Apply</string>
@@ -1284,7 +1309,7 @@
<string name="color_modification_b" translatable="false">B</string>
<!-- Title of the battery settings detail panel [CHAR LIMIT=20] -->
- <string name="battery_panel_title">Battery (<xliff:g name="pattery_percent" example="52">%1$d</xliff:g>%%)</string>
+ <string name="battery_panel_title">Battery usage</string>
<!-- Summary of battery saver not available [CHAR LIMIT=NONE] -->
<string name="battery_detail_charging_summary">Battery Saver not available during charging</string>
@@ -1305,15 +1330,14 @@
<string name="keyboard_shortcut_group_system_back">Back</string>
<!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
- <string name="tuner_full_zen_title">Show do not disturb in volume</string>
- <!-- SysUI Tuner: Summary of option to show full do not disturb panel in volume [CHAR LIMIT=NONE] -->
- <string name="tuner_full_zen_summary">Allow full control of do not disturb in the volume dialog.</string>
+ <string name="tuner_full_zen_title">Show with volume controls</string>
- <!-- SysUI Tuner: Label for screen about volume and do not disturb settings [CHAR LIMIT=60] -->
- <string name="volume_and_do_not_disturb">Volume and Do not disturb</string>
+ <!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
+ <string name="volume_and_do_not_disturb">Do not disturb</string>
- <!-- SysUI Tuner: Switch to control volume down behavior [CHAR LIMIT=60] -->
- <string name="volume_down_silent">Enter do not disturb on volume down</string>
+ <!-- SysUI Tuner: Switch to control whether volume buttons enter/exit do
+ not disturb [CHAR LIMIT=60] -->
+ <string name="volume_dnd_silent">Volume buttons shortcut</string>
<!-- SysUI Tuner: Switch to control volume up behavior [CHAR LIMIT=60] -->
<string name="volume_up_silent">Exit do not disturb on volume up</string>
@@ -1333,9 +1357,6 @@
<!-- Accessibility description of headset icon [CHAR LIMIT=NONE] -->
<string name="accessibility_status_bar_headset">Headset connected</string>
- <!-- Explanation of the status bar section of the tuner [CHAR LIMIT=NONE] -->
- <string name="tuner_status_bar_explanation">Enable or disable icons from being shown in the status bar.</string>
-
<!-- Label for quick settings tile for data saver [CHAR LIMIT=30] -->
<string name="data_saver">Data Saver</string>
@@ -1348,6 +1369,9 @@
<!-- Label for feature switch [CHAR LIMIT=30] -->
<string name="switch_bar_on">On</string>
+ <!-- Label for feature switch [CHAR LIMIT=30] -->
+ <string name="switch_bar_off">Off</string>
+
<!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
<string name="nav_bar">Navigation bar</string>
@@ -1405,4 +1429,42 @@
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Drag to add tiles</string>
+ <!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
+ <string name="qs_edit">Edit</string>
+
+ <!-- SysUI Tuner: Options for how clock is displayed [CHAR LIMIT=NONE] -->
+ <string name="tuner_time">Time</string>
+
+ <!-- SysUI Tuner: Options for how clock is displayed [CHAR LIMIT=NONE] -->
+ <string-array name="clock_options">
+ <item>Show hours, minutes, and seconds</item>
+ <item>Show hours and minutes (default)</item>
+ <item>Don\'t show this icon</item>
+ </string-array>
+
+ <!-- SysUI Tuner: Options for how battery is displayed [CHAR LIMIT=NONE] -->
+ <string-array name="battery_options">
+ <item>Always show percentage</item>
+ <item>Show percentage when charging (default)</item>
+ <item>Don\'t show this icon</item>
+ </string-array>
+
+ <!-- SysUI Tuner: Other section -->
+ <string name="other">Other</string>
+
+ <!-- Accessibility label for the divider that separates the windows in split-screen mode [CHAR LIMIT=NONE] -->
+ <string name="accessibility_divider">Split-screen divider</string>
+
+ <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_move_down">Move down</string>
+
+ <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_move_up">Move up</string>
+
+ <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_move_left">Move left</string>
+
+ <!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_divider_move_right">Move right</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 7c4768d29cfe..4f382eae9398 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -20,7 +20,7 @@
<!-- Picture-in-Picture menu -->
<eat-comment />
<!-- Button to close PIP on PIP UI -->
- <string name="pip_exit" translatable="false">Close PIP</string>
+ <string name="pip_close" translatable="false">Close PIP</string>
<!-- Button to move PIP screen to the fullscreen on PIP UI -->
<string name="pip_fullscreen" translatable="false">Full screen</string>
<!-- Button to play the current media on PIP UI -->
@@ -34,8 +34,6 @@
<!-- Picture-in-Picture onboarding screen -->
<eat-comment />
- <!-- Title for onboarding screen. -->
- <string name="pip_onboarding_title" translatable="false">Picture-in-picture</string>
<!-- Description for onboarding screen. -->
<string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string>
<!-- Button to close onboarding screen. -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 60a9fc233aa3..a51b9317db6a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -300,7 +300,7 @@
</style>
<style name="TunerPreferenceTheme" parent="@android:style/Theme.Material.Settings">
- <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
+ <item name="dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
</style>
<style name="TextAppearance.NotificationGuts">
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
index 45cdc07c65ae..1fcc9e4a9d7e 100644
--- a/packages/SystemUI/res/values/values_tv.xml
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -14,5 +14,5 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <item format="float" type="raw" name="unselected_scale">1.0</item>
-</resources> \ No newline at end of file
+ <item format="float" type="integer" name="unselected_scale">1.0</item>
+</resources>
diff --git a/packages/SystemUI/res/xml/color_and_appearance.xml b/packages/SystemUI/res/xml/color_and_appearance.xml
new file mode 100644
index 000000000000..21f890eb058d
--- /dev/null
+++ b/packages/SystemUI/res/xml/color_and_appearance.xml
@@ -0,0 +1,30 @@
+<?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/color_and_appearance">
+
+ <Preference
+ android:key="night_mode"
+ android:title="@string/night_mode"
+ android:fragment="com.android.systemui.tuner.NightModeFragment" />
+
+ <com.android.systemui.tuner.CalibratePreference
+ android:key="calibrate"
+ android:title="@string/calibrate_display" />
+
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/night_mode.xml b/packages/SystemUI/res/xml/night_mode.xml
new file mode 100644
index 000000000000..d5f5333a513b
--- /dev/null
+++ b/packages/SystemUI/res/xml/night_mode.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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:title="@string/night_mode">
+
+ <SwitchPreference
+ android:key="auto"
+ android:title="@string/turn_on_automatically"
+ android:summary="@string/turn_on_auto_summary" />
+
+ <PreferenceCategory
+ android:title="@string/when_night_mode_on">
+
+ <SwitchPreference
+ android:key="dark_theme"
+ android:title="@string/use_dark_theme" />
+
+ <SwitchPreference
+ android:key="adjust_tint"
+ android:title="@string/adjust_tint" />
+
+ <SwitchPreference
+ android:key="adjust_brightness"
+ android:title="@string/adjust_brightness" />
+
+ </PreferenceCategory>
+
+ <Preference
+ android:selectable="false"
+ android:summary="@string/night_mode_disclaimer" />
+
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 4de4cede0faa..ddc03a39d3a7 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -18,19 +18,10 @@
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:title="@string/system_ui_tuner">
- <com.android.systemui.tuner.TunerSwitch
- android:key="qs_show_brightness"
- android:title="@string/show_brightness"
- sysui:defValue="true" />
-
<PreferenceScreen
android:key="status_bar"
android:title="@string/status_bar" >
- <Preference
- android:selectable="false"
- android:summary="@string/tuner_status_bar_explanation" />
-
<com.android.systemui.tuner.StatusBarSwitch
android:key="rotate"
android:title="@string/status_bar_settings_auto_rotation" />
@@ -91,9 +82,10 @@
<!-- other weird signal stuff -->
- <com.android.systemui.tuner.StatusBarSwitch
- android:key="battery"
- android:title="@string/battery" />
+ <com.android.systemui.tuner.BatteryPreference
+ android:title="@string/battery"
+ android:summary="%s"
+ android:entries="@array/battery_options" />
<com.android.systemui.tuner.StatusBarSwitch
android:key="alarm_clock"
@@ -101,81 +93,67 @@
<!-- secure -->
- <com.android.systemui.tuner.StatusBarSwitch
- android:key="clock"
- android:title="@string/clock" />
+ <com.android.systemui.tuner.ClockPreference
+ android:title="@string/tuner_time"
+ android:summary="%s"
+ android:entries="@array/clock_options" />
</PreferenceScreen>
+ <Preference
+ android:key="color_transform"
+ android:title="@string/color_and_appearance"
+ android:fragment="com.android.systemui.tuner.ColorAndAppearanceFragment" />
<PreferenceScreen
- android:key="overview"
- android:title="@string/overview" >
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="overview_initial_state_paging"
- android:title="@string/overview_initial_state_paging"
- android:summary="@string/overview_initial_state_paging_desc" />
+ android:key="volume_and_do_not_disturb"
+ android:title="@string/volume_and_do_not_disturb">
+ <!-- Action for this is
+ MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_PANEL -->
<com.android.systemui.tuner.TunerSwitch
- android:key="overview_fast_toggle_via_button"
- android:title="@string/overview_fast_toggle_via_button"
- android:summary="@string/overview_fast_toggle_via_button_desc" />
+ android:key="sysui_show_full_zen"
+ android:title="@string/tuner_full_zen_title"
+ sysui:metricsAction="314" />
+ <!-- Action for this is
+ MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_SHORTCUT -->
<com.android.systemui.tuner.TunerSwitch
- android:key="overview_nav_bar_gesture"
- android:title="@string/overview_nav_bar_gesture"
- android:summary="@string/overview_nav_bar_gesture_desc" />
+ android:key="sysui_volume_down_silent,sysui_volume_up_silent"
+ android:title="@string/volume_dnd_silent"
+ sysui:defValue="true"
+ sysui:metricsAction="315" />
</PreferenceScreen>
- <SwitchPreference
- android:key="battery_pct"
- android:title="@string/show_battery_percentage"
- android:summary="@string/show_battery_percentage_summary"
- android:persistent="false" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="clock_seconds"
- android:title="@string/clock_seconds"
- android:summary="@string/clock_seconds_desc" />
-
+ <!--
<Preference
- android:key="demo_mode"
- android:title="@string/demo_mode"
- android:fragment="com.android.systemui.tuner.DemoModeFragment" />
-
- <Preference
- android:key="color_transform"
- android:title="@string/color_transform"
- android:fragment="com.android.systemui.tuner.ColorMatrixFragment" />
+ android:key="nav_bar"
+ android:title="@string/nav_bar"
+ android:fragment="com.android.systemui.tuner.NavBarTuner" />
+ -->
<PreferenceScreen
- android:key="volume_and_do_not_disturb"
- android:title="@string/volume_and_do_not_disturb">
+ android:key="other"
+ android:title="@string/other" >
<com.android.systemui.tuner.TunerSwitch
- android:key="sysui_show_full_zen"
- android:title="@string/tuner_full_zen_title"
- android:summary="@string/tuner_full_zen_summary" />
+ android:key="overview_disable_fast_toggle_via_button"
+ android:title="@string/overview_disable_fast_toggle_via_button"
+ android:summary="@string/overview_disable_fast_toggle_via_button_desc" />
<com.android.systemui.tuner.TunerSwitch
- android:key="sysui_volume_down_silent"
- android:title="@string/volume_down_silent"
- sysui:defValue="true" />
+ android:key="overview_nav_bar_gesture"
+ android:title="@string/overview_nav_bar_gesture"
+ android:summary="@string/overview_nav_bar_gesture_desc" />
+ <!-- importance -->
<com.android.systemui.tuner.TunerSwitch
- android:key="sysui_volume_up_silent"
- android:title="@string/volume_up_silent"
- sysui:defValue="true" />
+ android:key="show_importance_slider"
+ android:title="@string/tuner_full_importance_settings" />
</PreferenceScreen>
- <Preference
- android:key="nav_bar"
- android:title="@string/nav_bar"
- android:fragment="com.android.systemui.tuner.NavBarTuner" />
-
<!-- Warning, this goes last. -->
<Preference
android:summary="@string/tuner_persistent_warning"
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 454d1ceb4b04..4845425c233e 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -62,6 +62,7 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode,
mPlusPaint;
private float mTextHeight, mWarningTextHeight;
private int mIconTint = Color.WHITE;
+ private float mOldDarkIntensity = 0f;
private int mHeight;
private int mWidth;
@@ -295,6 +296,9 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode,
}
public void setDarkIntensity(float darkIntensity) {
+ if (darkIntensity == mOldDarkIntensity) {
+ return;
+ }
int backgroundColor = getBackgroundColor(darkIntensity);
int fillColor = getFillColor(darkIntensity);
mIconTint = fillColor;
@@ -302,6 +306,7 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode,
mBoltPaint.setColor(fillColor);
mChargeColor = fillColor;
invalidateSelf();
+ mOldDarkIntensity = darkIntensity;
}
private int getBackgroundColor(float darkIntensity) {
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
index 43a1be1d0642..9238928de9e2 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
@@ -40,4 +40,15 @@ public class EventLogConstants {
public 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;
+
+ /** Secondary user tries binding to the system sysui service */
+ public static final int SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE = 1;
+ /** Secondary user is bound to the system sysui service */
+ public static final int SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND = 2;
+ /** Secondary user loses connection after system sysui has died */
+ public static final int SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND = 3;
+ /** System sysui registers secondary user's callbacks */
+ public static final int SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER = 4;
+ /** System sysui unregisters secondary user's callbacks (after death) */
+ public static final int SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER = 5;
}
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index a584cf638177..1601675197cb 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -51,3 +51,13 @@ option java_package com.android.systemui;
# SearchPanelView.java
# ---------------------------
36050 sysui_searchpanel_touch (type|1),(x|1),(y|1)
+
+# ---------------------------
+# Recents.java, RecentsSystemUser.java
+# ---------------------------
+## type: 1: USER_BIND_SERVICE Secondary user tries binding to the system sysui service
+## 2: USER_SYSTEM_BOUND Secondary user is bound to the system sysui service
+## 3: USER_SYSTEM_UNBOUND Secondary user loses connection after system sysui has died
+## 4: SYSTEM_REGISTER_USER System sysui registers user's callbacks
+## 5: SYSTEM_UNREGISTER_USER System sysui unregisters user's callbacks (after death)
+36060 sysui_recents_connection (type|1),(user|1) \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 147162232155..9f2745b9ac24 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -48,6 +48,7 @@ public final class Prefs {
Key.QS_DATA_SAVER_ADDED,
Key.QS_INVERT_COLORS_ADDED,
Key.QS_WORK_ADDED,
+ Key.QS_NIGHT_ADDED,
})
public @interface Key {
String OVERVIEW_SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
@@ -68,6 +69,7 @@ public final class Prefs {
String QS_DATA_SAVER_ADDED = "QsDataSaverAdded";
String QS_INVERT_COLORS_ADDED = "QsInvertColorsAdded";
String QS_WORK_ADDED = "QsWorkAdded";
+ String QS_NIGHT_ADDED = "QsNightAdded";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33b43fec6fc1..33f3c30fcc12 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -69,9 +69,9 @@ public class SwipeHelper implements Gefingerpoken {
private float mPerpendicularInitialTouchPos;
private boolean mDragging;
private View mCurrView;
- private View mCurrAnimView;
private boolean mCanCurrViewBeDimissed;
private float mDensityScale;
+ private float mTranslation = 0;
private boolean mLongPressSent;
private LongPressListener mLongPressListener;
@@ -121,7 +121,7 @@ public class SwipeHelper implements Gefingerpoken {
return mSwipeDirection == X ? ev.getY() : ev.getX();
}
- private float getTranslation(View v) {
+ protected float getTranslation(View v) {
return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
}
@@ -130,7 +130,7 @@ public class SwipeHelper implements Gefingerpoken {
vt.getYVelocity();
}
- private ObjectAnimator createTranslationAnimation(View v, float newPos) {
+ protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
ObjectAnimator anim = ObjectAnimator.ofFloat(v,
mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
return anim;
@@ -141,7 +141,17 @@ public class SwipeHelper implements Gefingerpoken {
vt.getXVelocity();
}
- private void setTranslation(View v, float translate) {
+ protected Animator getViewTranslationAnimator(View v, float target,
+ AnimatorUpdateListener listener) {
+ ObjectAnimator anim = createTranslationAnimation(v, target);
+ anim.addUpdateListener(listener);
+ return anim;
+ }
+
+ protected void setTranslation(View v, float translate) {
+ if (v == null) {
+ return;
+ }
if (mSwipeDirection == X) {
v.setTranslationX(translate);
} else {
@@ -237,15 +247,16 @@ public class SwipeHelper implements Gefingerpoken {
mTouchAboveFalsingThreshold = false;
mDragging = false;
mLongPressSent = false;
- mCurrView = mCallback.getChildAtPosition(ev);
mVelocityTracker.clear();
+ mCurrView = mCallback.getChildAtPosition(ev);
+
if (mCurrView != null) {
- mCurrAnimView = mCallback.getChildContentView(mCurrView);
+ onDownUpdate(mCurrView);
mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
mVelocityTracker.addMovement(ev);
mInitialTouchPos = getPos(ev);
mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
-
+ mTranslation = getTranslation(mCurrView);
if (mLongPressListener != null) {
if (mWatchLongPress == null) {
mWatchLongPress = new Runnable() {
@@ -268,7 +279,6 @@ public class SwipeHelper implements Gefingerpoken {
}
mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
}
-
}
break;
@@ -283,8 +293,8 @@ public class SwipeHelper implements Gefingerpoken {
&& Math.abs(delta) > Math.abs(deltaPerpendicular)) {
mCallback.onBeginDrag(mCurrView);
mDragging = true;
- mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
-
+ mInitialTouchPos = getPos(ev);
+ mTranslation = getTranslation(mCurrView);
removeLongPressCallback();
}
}
@@ -295,7 +305,6 @@ public class SwipeHelper implements Gefingerpoken {
final boolean captured = (mDragging || mLongPressSent);
mDragging = false;
mCurrView = null;
- mCurrAnimView = null;
mLongPressSent = false;
removeLongPressCallback();
if (captured) return true;
@@ -320,12 +329,11 @@ public class SwipeHelper implements Gefingerpoken {
* @param useAccelerateInterpolator Should an accelerating Interpolator be used
* @param fixedDuration If not 0, this exact duration will be taken
*/
- public void dismissChild(final View view, float velocity, final Runnable endAction,
+ public void dismissChild(final View animView, float velocity, final Runnable endAction,
long delay, boolean useAccelerateInterpolator, long fixedDuration) {
- final View animView = mCallback.getChildContentView(view);
- final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
+ final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
float newPos;
- boolean isLayoutRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
if (velocity < 0
|| (velocity == 0 && getTranslation(animView) < 0)
@@ -355,7 +363,13 @@ public class SwipeHelper implements Gefingerpoken {
if (!mDisableHwLayers) {
animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
- ObjectAnimator anim = createTranslationAnimation(animView, newPos);
+ AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
+ }
+ };
+
+ Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
if (useAccelerateInterpolator) {
anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
} else {
@@ -367,8 +381,8 @@ public class SwipeHelper implements Gefingerpoken {
}
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- mCallback.onChildDismissed(view);
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ mCallback.onChildDismissed(animView);
if (endAction != null) {
endAction.run();
}
@@ -377,11 +391,6 @@ public class SwipeHelper implements Gefingerpoken {
}
}
});
- anim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- }
- });
prepareDismissAnimation(animView, anim);
anim.start();
}
@@ -393,21 +402,21 @@ public class SwipeHelper implements Gefingerpoken {
// Do nothing
}
- public void snapChild(final View view, float velocity) {
- final View animView = mCallback.getChildContentView(view);
- final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
- ObjectAnimator anim = createTranslationAnimation(animView, 0);
- int duration = SNAP_ANIM_LEN;
- anim.setDuration(duration);
- anim.addUpdateListener(new AnimatorUpdateListener() {
+ public void snapChild(final View animView, final float targetLeft, float velocity) {
+ final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
+ AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
+ onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
}
- });
+ };
+
+ Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
+ int duration = SNAP_ANIM_LEN;
+ anim.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- mCallback.onChildSnappedBack(animView);
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ mCallback.onChildSnappedBack(animView, targetLeft);
}
});
prepareSnapBackAnimation(animView, anim);
@@ -421,6 +430,28 @@ public class SwipeHelper implements Gefingerpoken {
// Do nothing
}
+ /**
+ * Called when there's a down event.
+ */
+ public void onDownUpdate(View currView) {
+ // Do nothing
+ }
+
+ /**
+ * Called on a move event.
+ */
+ protected void onMoveUpdate(View view, float totalTranslation, float delta) {
+ // Do nothing
+ }
+
+ /**
+ * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
+ * view is being animated to dismiss or snap.
+ */
+ public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ }
+
public boolean onTouchEvent(MotionEvent ev) {
if (mLongPressSent) {
return true;
@@ -456,17 +487,18 @@ public class SwipeHelper implements Gefingerpoken {
// don't let items that can't be dismissed be dragged more than
// maxScrollDistance
if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
- float size = getSize(mCurrAnimView);
- float maxScrollDistance = 0.15f * size;
+ float size = getSize(mCurrView);
+ float maxScrollDistance = 0.25f * size;
if (absDelta >= size) {
delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
} else {
delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
}
}
- setTranslation(mCurrAnimView, delta);
- updateSwipeProgressFromOffset(mCurrAnimView, mCanCurrViewBeDimissed);
+ setTranslation(mCurrView, mTranslation + delta);
+ updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
+ onMoveUpdate(mCurrView, mTranslation + delta, delta);
}
break;
case MotionEvent.ACTION_UP:
@@ -478,12 +510,13 @@ public class SwipeHelper implements Gefingerpoken {
float velocity = getVelocity(mVelocityTracker);
float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
+ float translation = getTranslation(mCurrView);
// Decide whether to dismiss the current view
boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
- Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
+ Math.abs(translation) > 0.4 * getSize(mCurrView);
boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
(Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
- (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
+ (velocity > 0) == (translation > 0);
boolean falsingDetected = mCallback.isAntiFalsingNeeded();
if (mFalsingManager.isClassiferEnabled()) {
@@ -502,7 +535,7 @@ public class SwipeHelper implements Gefingerpoken {
} else {
// snappity
mCallback.onDragCancelled(mCurrView);
- snapChild(mCurrView, velocity);
+ snapChild(mCurrView, 0 /* leftTarget */, velocity);
}
}
break;
@@ -518,8 +551,6 @@ public class SwipeHelper implements Gefingerpoken {
public interface Callback {
View getChildAtPosition(MotionEvent ev);
- View getChildContentView(View v);
-
boolean canChildBeDismissed(View v);
boolean isAntiFalsingNeeded();
@@ -530,7 +561,13 @@ public class SwipeHelper implements Gefingerpoken {
void onDragCancelled(View v);
- void onChildSnappedBack(View animView);
+ /**
+ * Called when the child is snapped to a position.
+ *
+ * @param animView the view that was snapped.
+ * @param targetLeft the left position the view was snapped to.
+ */
+ void onChildSnappedBack(View animView, float targetLeft);
/**
* Updates the swipe progress on a child.
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 472648a2f7f6..b2b612787fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -54,7 +54,8 @@ public class SystemUIApplication extends Application {
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class,
com.android.systemui.keyboard.KeyboardUI.class,
- com.android.systemui.tv.pip.PipUI.class
+ com.android.systemui.tv.pip.PipUI.class,
+ com.android.systemui.shortcut.ShortcutKeyDispatcher.class
};
/**
@@ -143,12 +144,14 @@ public class SystemUIApplication extends Application {
Class<?> cl = services[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
try {
- mServices[i] = (SystemUI) cl.newInstance();
+ Object newService = SystemUIFactory.getInstance().createInstance(cl);
+ mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
+
mServices[i].mContext = this;
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 681b39e1ba43..913b2b346b34 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -18,11 +18,15 @@ package com.android.systemui;
import android.content.Context;
import android.util.Log;
+import android.view.View;
import android.view.ViewGroup;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.shortcut.ShortcutKeyDispatcher;
+import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
@@ -66,4 +70,13 @@ public class SystemUIFactory {
ViewGroup container) {
return new KeyguardBouncer(context, callback, lockPatternUtils, windowManager, container);
}
+
+ public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
+ View headsUpScrim, boolean scrimSrcEnabled) {
+ return new ScrimController(scrimBehind, scrimInFront, headsUpScrim, scrimSrcEnabled);
+ }
+
+ public <T> T createInstance(Class<T> classType) {
+ return null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 735a7c4bad4a..c09376bdd37e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -23,6 +23,7 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
+import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.view.MotionEvent;
@@ -64,6 +65,7 @@ public class FalsingManager implements SensorEventListener {
private boolean mBouncerOn = false;
private boolean mSessionActive = false;
private int mState = StatusBarState.SHADE;
+ private boolean mScreenOn;
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
@@ -77,6 +79,7 @@ public class FalsingManager implements SensorEventListener {
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mDataCollector = DataCollector.getInstance(mContext);
mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
+ mScreenOn = context.getSystemService(PowerManager.class).isInteractive();
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
@@ -98,17 +101,21 @@ public class FalsingManager implements SensorEventListener {
ENFORCE_BOUNCER, 0);
}
+ private boolean shouldSessionBeActive() {
+ return isEnabled() && mScreenOn &&
+ (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED);
+ }
+
private boolean sessionEntrypoint() {
- if (!mSessionActive && isEnabled() &&
- (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
+ if (!mSessionActive && shouldSessionBeActive()) {
onSessionStart();
return true;
}
return false;
}
- private void sessionExitpoint() {
- if (mSessionActive) {
+ private void sessionExitpoint(boolean force) {
+ if (mSessionActive && (force || !shouldSessionBeActive())) {
mSessionActive = false;
mSensorManager.unregisterListener(this);
}
@@ -167,15 +174,22 @@ public class FalsingManager implements SensorEventListener {
public void setStatusBarState(int state) {
mState = state;
+ if (shouldSessionBeActive()) {
+ sessionEntrypoint();
+ } else {
+ sessionExitpoint(false /* force */);
+ }
}
public void onScreenTurningOn() {
+ mScreenOn = true;
if (sessionEntrypoint()) {
mDataCollector.onScreenTurningOn();
}
}
public void onScreenOnFromTouch() {
+ mScreenOn = true;
if (sessionEntrypoint()) {
mDataCollector.onScreenOnFromTouch();
}
@@ -183,12 +197,13 @@ public class FalsingManager implements SensorEventListener {
public void onScreenOff() {
mDataCollector.onScreenOff();
- sessionExitpoint();
+ mScreenOn = false;
+ sessionExitpoint(false /* force */);
}
public void onSucccessfulUnlock() {
mDataCollector.onSucccessfulUnlock();
- sessionExitpoint();
+ sessionExitpoint(true /* force */);
}
public void onBouncerShown() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 7ddbdf0e6e70..45eb9ad3115a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -119,7 +119,7 @@ public class HumanInteractionClassifier extends Classifier {
return;
}
- // If the user is dragging down the notification, he might want to drag it down
+ // If the user is dragging down the notification, they might want to drag it down
// enough to see the content, read it for a while and then lift the finger to open
// the notification. This kind of motion scores very bad in the Classifier so the
// MotionEvents which are close to the current position of the finger are not
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 958572fd4fd5..6029c23ab30b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -475,6 +475,23 @@ public class KeyguardViewMediator extends SystemUI {
break;
}
}
+
+ @Override
+ public void onFingerprintAuthFailed() {
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportFailedFingerprintAttempt(
+ currentUser);
+ }
+ }
+
+ @Override
+ public void onFingerprintAuthenticated(int userId) {
+ if (mLockPatternUtils.isSecure(userId)) {
+ mLockPatternUtils.getDevicePolicyManager().reportSuccessfulFingerprintAttempt(
+ userId);
+ }
+ }
};
ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
@@ -741,7 +758,7 @@ public class KeyguardViewMediator extends SystemUI {
mPendingLock = false;
}
}
- doKeyguardLaterLockedForChildProfiles();
+ doKeyguardForChildProfilesLocked();
KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
}
@@ -764,8 +781,7 @@ public class KeyguardViewMediator extends SystemUI {
long timeout;
- if ((mLockPatternUtils.isSeparateProfileChallengeEnabled(userId))
- || policyTimeout <= 0) {
+ if (policyTimeout <= 0) {
timeout = lockAfterTimeout;
} else {
// From DisplaySettings
@@ -798,23 +814,31 @@ public class KeyguardViewMediator extends SystemUI {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+ mDelayedShowingSequence);
- doKeyguardLaterLockedForChildProfiles();
+ doKeyguardLaterForChildProfilesLocked();
}
- private void doKeyguardLaterLockedForChildProfiles() {
+ private void doKeyguardLaterForChildProfilesLocked() {
UserManager um = UserManager.get(mContext);
List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
- if (profiles.size() > 1) {
- for (UserInfo info : profiles) {
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
- long userTimeout = getLockTimeout(info.id);
- long userWhen = SystemClock.elapsedRealtime() + userTimeout;
- Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
- lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
- PendingIntent lockSender = PendingIntent.getBroadcast(
- mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
- }
+ for (UserInfo info : profiles) {
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
+ long userTimeout = getLockTimeout(info.id);
+ long userWhen = SystemClock.elapsedRealtime() + userTimeout;
+ Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
+ lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
+ PendingIntent lockSender = PendingIntent.getBroadcast(
+ mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
+ }
+ }
+ }
+
+ private void doKeyguardForChildProfilesLocked() {
+ UserManager um = UserManager.get(mContext);
+ List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
+ for (UserInfo info : profiles) {
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
+ lockProfile(info.id);
}
}
}
@@ -1370,8 +1394,9 @@ public class KeyguardViewMediator extends SystemUI {
* @see #KEYGUARD_DONE
*/
private void handleKeyguardDone(boolean authenticated) {
- if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed();
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser);
}
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
synchronized (this) {
@@ -1484,8 +1509,9 @@ public class KeyguardViewMediator extends SystemUI {
* @see #SHOW
*/
private void handleShow(Bundle options) {
- if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
- mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured();
+ final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
}
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index d72336739886..2c5cb89b3531 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,7 +6,6 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import com.android.systemui.R;
@@ -27,6 +26,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
private PageIndicator mPageIndicator;
private int mNumPages;
+ private View mDecorGroup;
+ private PageListener mPageListener;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -36,12 +37,19 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
public void onPageSelected(int position) {
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position);
+ if (mPageListener != null) {
+ mPageListener.onPageChanged(position == 0);
+ }
}
@Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position + positionOffset);
+ if (mPageListener != null) {
+ mPageListener.onPageChanged(position == 0 && positionOffsetPixels == 0);
+ }
}
@Override
@@ -52,10 +60,16 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
}
@Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
- ((LayoutParams) mPageIndicator.getLayoutParams()).isDecor = true;
+ mDecorGroup = findViewById(R.id.page_decor);
+ ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
mPages.add((TilePage) LayoutInflater.from(mContext)
.inflate(R.layout.qs_paged_page, this, false));
@@ -79,6 +93,10 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
}
}
+ public void setPageListener(PageListener listener) {
+ mPageListener = listener;
+ }
+
private void postDistributeTiles() {
removeCallbacks(mDistribute);
post(mDistribute);
@@ -137,7 +155,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
maxHeight = height;
}
}
- setMeasuredDimension(getMeasuredWidth(), maxHeight + mPageIndicator.getMeasuredHeight());
+ setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
}
private final Runnable mDistribute = new Runnable() {
@@ -197,4 +215,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
return view == object;
}
};
+
+ public interface PageListener {
+ void onPageChanged(boolean isFirst);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
new file mode 100644
index 000000000000..c643d6708adb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -0,0 +1,216 @@
+/*
+ * 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.qs;
+
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.view.animation.PathInterpolator;
+import android.widget.TextView;
+import com.android.systemui.qs.PagedTileLayout.PageListener;
+import com.android.systemui.qs.QSPanel.QSTileLayout;
+import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
+
+ private static final String TAG = "QSAnimator";
+
+ public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
+ new PathInterpolator(.1f, .3f, 1, 1);
+
+ public static final float EXPANDED_TILE_DELAY = .7f;
+
+ private final ArrayList<View> mAllViews = new ArrayList<>();
+ private final ArrayList<View> mTopFiveQs = new ArrayList<>();
+ private final QuickQSPanel mQuickQsPanel;
+ private final QSPanel mQsPanel;
+ private final QSContainer mQsContainer;
+
+ private boolean mOnFirstPage = true;
+ private TouchAnimator mFirstPageAnimator;
+ private TouchAnimator mFirstPageDelayedAnimator;
+ private TouchAnimator mTranslationYAnimator;
+ private TouchAnimator mNonfirstPageAnimator;
+
+ public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
+ mQsContainer = container;
+ mQuickQsPanel = quickPanel;
+ mQsPanel = panel;
+ container.addOnLayoutChangeListener(this);
+ QSTileLayout tileLayout = mQsPanel.getTileLayout();
+ if (tileLayout instanceof PagedTileLayout) {
+ ((PagedTileLayout) tileLayout).setPageListener(this);
+ } else {
+ Log.w(TAG, "QS Not using page layout");
+ }
+ }
+
+ public void setHost(QSTileHost qsh) {
+ qsh.addCallback(this);
+ }
+
+ @Override
+ public void onPageChanged(boolean isFirst) {
+ if (mOnFirstPage == isFirst) return;
+ if (!isFirst) {
+ setPosition(1);
+ clearAnimationState();
+ }
+ mOnFirstPage = isFirst;
+ }
+
+ private void updateAnimators() {
+ TouchAnimator.Builder firstPageBuilder = new Builder();
+ TouchAnimator.Builder translationYBuilder = new Builder();
+ TouchAnimator.Builder firstPageDelayedBuilder = new Builder();
+ Collection<QSTile<?>> tiles = mQsPanel.getHost().getTiles();
+ int count = 0;
+ int[] loc1 = new int[2];
+ int[] loc2 = new int[2];
+ firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
+ firstPageBuilder.setListener(this);
+ translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
+ // Fade in the tiles/labels as we reach the final position.
+ firstPageDelayedBuilder.addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1);
+ mAllViews.clear();
+ mTopFiveQs.clear();
+ for (QSTile<?> tile : tiles) {
+ QSTileBaseView tileView = mQsPanel.getTileView(tile);
+ final TextView label = ((QSTileView) tileView).getLabel();
+ if (count++ < 5) {
+ // Quick tiles.
+ QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
+ final View tileIcon = tileView.getIcon();
+
+ getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
+ getRelativePosition(loc2, tileIcon, mQsContainer);
+ final int xDiff = loc2[0] - loc1[0];
+ final int yDiff = loc2[1] - loc1[1];
+ // Move the quick tile right from its location to the new one.
+ firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
+ translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
+
+ // Counteract the parent translation on the tile. So we have a static base to
+ // animate the label position off from.
+ firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+
+ // Move the real tile's label from the quick tile position to its final
+ // location.
+ firstPageBuilder.addFloat(label, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+
+ mTopFiveQs.add(tileIcon);
+ mAllViews.add(tileIcon);
+ mAllViews.add(quickTileView);
+ }
+ mAllViews.add(tileView);
+ mAllViews.add(label);
+ }
+ mFirstPageAnimator = firstPageBuilder.build();
+ mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
+ mTranslationYAnimator = translationYBuilder.build();
+ mNonfirstPageAnimator = new TouchAnimator.Builder()
+ .addFloat(mQuickQsPanel, "alpha", 1, 0)
+ .setEndDelay(.5f)
+ .build();
+ }
+
+ private void getRelativePosition(int[] loc1, View view, View parent) {
+ loc1[0] = 0 + view.getWidth() / 2;
+ loc1[1] = 0;
+ getRelativePositionInt(loc1, view, parent);
+ }
+
+ private void getRelativePositionInt(int[] loc1, View view, View parent) {
+ if(view == parent || view == null) return;
+ loc1[0] += view.getLeft();
+ loc1[1] += view.getTop();
+ getRelativePositionInt(loc1, (View) view.getParent(), parent);
+ }
+
+ public void setPosition(float position) {
+ if (mFirstPageAnimator == null) return;
+ if (mOnFirstPage) {
+ mQuickQsPanel.setAlpha(1);
+ mFirstPageAnimator.setPosition(position);
+ mFirstPageDelayedAnimator.setPosition(position);
+ mTranslationYAnimator.setPosition(position);
+ } else {
+ mNonfirstPageAnimator.setPosition(position);
+ }
+ }
+
+ @Override
+ public void onAnimationAtStart() {
+ mQuickQsPanel.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onAnimationAtEnd() {
+ mQuickQsPanel.setVisibility(View.INVISIBLE);
+ final int N = mTopFiveQs.size();
+ for (int i = 0; i < N; i++) {
+ mTopFiveQs.get(i).setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onAnimationStarted() {
+ mQuickQsPanel.setVisibility(View.VISIBLE);
+ if (mOnFirstPage) {
+ final int N = mTopFiveQs.size();
+ for (int i = 0; i < N; i++) {
+ mTopFiveQs.get(i).setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ private void clearAnimationState() {
+ final int N = mAllViews.size();
+ mQuickQsPanel.setAlpha(0);
+ for (int i = 0; i < N; i++) {
+ View v = mAllViews.get(i);
+ v.setAlpha(1);
+ v.setTranslationX(1);
+ v.setTranslationY(1);
+ }
+ }
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ updateAnimators();
+ }
+
+ @Override
+ public void onTilesChanged() {
+ // Give the QS panels a moment to generate their new tiles, then create all new animators
+ // hooked up to the new views.
+ mQsPanel.post(mUpdateAnimators);
+ }
+
+ private Runnable mUpdateAnimators = new Runnable() {
+ @Override
+ public void run() {
+ updateAnimators();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index cfe8d07dd14b..c59da8d8baf7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -16,19 +16,41 @@
package com.android.systemui.qs;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
- * Wrapper view with background which contains {@link QSPanel}
+ * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
+ *
+ * Also manages animations for the QS Header and Panel.
*/
public class QSContainer extends FrameLayout {
+ private static final String TAG = "QSContainer";
+ private static final boolean DEBUG = false;
private int mHeightOverride = -1;
private QSPanel mQSPanel;
+ private QSDetail mQSDetail;
+ protected BaseStatusBarHeader mHeader;
+ private float mQsExpansion;
+ private boolean mQsExpanded;
+ private boolean mHeaderAnimating;
+ private boolean mKeyguardShowing;
+ private boolean mStackScrollerOverscrolling;
+
+ private long mDelay;
+ private QSAnimator mQSAnimator;
public QSContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -38,6 +60,26 @@ public class QSContainer extends FrameLayout {
protected void onFinishInflate() {
super.onFinishInflate();
mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+ mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
+ mQSDetail.setQsPanel(mQSPanel);
+ mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
+ mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
+ mQSPanel);
+ }
+
+ public void setHost(QSTileHost qsh) {
+ mQSPanel.setHost(qsh);
+ mHeader.setQSPanel(mQSPanel);
+ mQSDetail.setHost(qsh);
+ mQSAnimator.setHost(qsh);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Since we control our own bottom, be whatever size we want.
+ // Otherwise the QSPanel ends up with 0 height when the window is only the
+ // size of the status bar.
+ super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
}
@Override
@@ -62,15 +104,140 @@ public class QSContainer extends FrameLayout {
* during closing the detail panel, this already returns the smaller height.
*/
public int getDesiredHeight() {
- if (mQSPanel.isClosingDetail()) {
- return mQSPanel.getGridHeight() + getPaddingTop() + getPaddingBottom();
+ if (mQSDetail.isClosingDetail()) {
+ return mQSPanel.getGridHeight() + mHeader.getCollapsedHeight() + getPaddingBottom();
} else {
return getMeasuredHeight();
}
}
private void updateBottom() {
- int height = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+ int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+ int height = (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+ + mHeader.getCollapsedHeight();
setBottom(getTop() + height);
+ mQSDetail.setBottom(getTop() + height);
+ }
+
+ private void updateQsState() {
+ boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+ mQSPanel.setExpanded(mQsExpanded);
+ mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+ ? View.VISIBLE
+ : View.INVISIBLE);
+ mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+ || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ public BaseStatusBarHeader getHeader() {
+ return mHeader;
+ }
+
+ public QSPanel getQsPanel() {
+ return mQSPanel;
+ }
+
+ public boolean isShowingDetail() {
+ return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
+ }
+
+ public void setHeaderClickable(boolean clickable) {
+ if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
+ mHeader.setClickable(clickable);
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
+ mQsExpanded = expanded;
+ updateQsState();
}
+
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+ mKeyguardShowing = keyguardShowing;
+ updateQsState();
+ }
+
+ public void setOverscrolling(boolean stackScrollerOverscrolling) {
+ if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
+ mStackScrollerOverscrolling = stackScrollerOverscrolling;
+ updateQsState();
+ }
+
+ public void setListening(boolean listening) {
+ if (DEBUG) Log.d(TAG, "setListening " + listening);
+ mQSPanel.setListening(listening);
+ mHeader.setListening(listening);
+ }
+
+ public void setQsExpansion(float expansion, float headerTranslation) {
+ if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+ mQsExpansion = expansion;
+ final float translationScaleY = expansion - 1;
+ if (!mHeaderAnimating) {
+ setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+ : headerTranslation);
+ }
+ mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
+ mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+ mQSDetail.setFullyExpanded(expansion == 1);
+ mQSAnimator.setPosition(expansion);
+ updateBottom();
+ }
+
+ public void animateHeaderSlidingIn(long delay) {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
+ // If the QS is already expanded we don't need to slide in the header as it's already
+ // visible.
+ if (!mQsExpanded) {
+ mHeaderAnimating = true;
+ mDelay = delay;
+ getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+ }
+ }
+
+ public void animateHeaderSlidingOut() {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+ mHeaderAnimating = true;
+ animate().y(-mHeader.getHeight())
+ .setStartDelay(0)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animate().setListener(null);
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ })
+ .start();
+ }
+
+ private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ animate()
+ .translationY(0f)
+ .setStartDelay(mDelay)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(mAnimateHeaderSlidingInListener)
+ .start();
+ setY(-mHeader.getHeight());
+ return true;
+ }
+ };
+
+ private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+ = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
new file mode 100644
index 000000000000..50c0cca8d8e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -0,0 +1,287 @@
+/*
+ * 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.qs;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.drawable.Animatable;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.DetailAdapter;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+public class QSDetail extends LinearLayout {
+
+ private static final String TAG = "QSDetail";
+ private static final long FADE_DURATION = 300;
+
+ private final SparseArray<View> mDetailViews = new SparseArray<>();
+
+ private ViewGroup mDetailContent;
+ private TextView mDetailSettingsButton;
+ private TextView mDetailDoneButton;
+ private QSDetailClipper mClipper;
+ private DetailAdapter mDetailAdapter;
+ private QSPanel mQsPanel;
+
+ private View mQsDetailHeader;
+ private TextView mQsDetailHeaderTitle;
+ private Switch mQsDetailHeaderSwitch;
+ private ImageView mQsDetailHeaderProgress;
+
+ private QSTileHost mHost;
+
+ private boolean mScanState;
+ private boolean mClosingDetail;
+ private boolean mFullyExpanded;
+ private View mQsDetailHeaderBack;
+
+ public QSDetail(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size);
+ FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size);
+
+ for (int i = 0; i < mDetailViews.size(); i++) {
+ mDetailViews.valueAt(i).dispatchConfigurationChanged(newConfig);
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDetailContent = (ViewGroup) findViewById(android.R.id.content);
+ mDetailSettingsButton = (TextView) findViewById(android.R.id.button2);
+ mDetailDoneButton = (TextView) findViewById(android.R.id.button1);
+
+ mQsDetailHeader = findViewById(R.id.qs_detail_header);
+ mQsDetailHeaderBack = mQsDetailHeader.findViewById(com.android.internal.R.id.up);
+ mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
+ mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
+ mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
+
+ updateDetailText();
+
+ mClipper = new QSDetailClipper(this);
+
+ final OnClickListener doneListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ announceForAccessibility(
+ mContext.getString(R.string.accessibility_desc_quick_settings));
+ mQsPanel.closeDetail();
+ }
+ };
+ mQsDetailHeaderBack.setOnClickListener(doneListener);
+ mDetailDoneButton.setOnClickListener(doneListener);
+ }
+
+ public void setQsPanel(QSPanel panel) {
+ mQsPanel = panel;
+ mQsPanel.setCallback(mQsPanelCallback);
+ }
+
+ public void setHost(QSTileHost host) {
+ mHost = host;
+ }
+ public boolean isShowingDetail() {
+ return mDetailAdapter != null;
+ }
+
+ public void setFullyExpanded(boolean fullyExpanded) {
+ mFullyExpanded = fullyExpanded;
+ }
+
+ private void updateDetailText() {
+ mDetailDoneButton.setText(R.string.quick_settings_done);
+ mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
+ }
+
+ public void updateResources() {
+ updateDetailText();
+ }
+
+ public boolean isClosingDetail() {
+ return mClosingDetail;
+ }
+
+ private void handleShowingDetail(final QSTile.DetailAdapter adapter, int x, int y) {
+ final boolean showingDetail = adapter != null;
+ setClickable(showingDetail);
+ if (showingDetail) {
+ mQsDetailHeaderTitle.setText(adapter.getTitle());
+ final Boolean toggleState = adapter.getToggleState();
+ if (toggleState == null) {
+ mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
+ mQsDetailHeader.setClickable(false);
+ } else {
+ mQsDetailHeaderSwitch.setVisibility(VISIBLE);
+ mQsDetailHeaderSwitch.setChecked(toggleState);
+ mQsDetailHeader.setClickable(true);
+ mQsDetailHeader.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean checked = !mQsDetailHeaderSwitch.isChecked();
+ mQsDetailHeaderSwitch.setChecked(checked);
+ adapter.setToggleState(checked);
+ }
+ });
+ }
+ }
+
+ boolean visibleDiff = (mDetailAdapter != null) != (adapter != null);
+ if (!visibleDiff && mDetailAdapter == adapter) return; // already in right state
+ AnimatorListener listener = null;
+ if (adapter != null) {
+ int viewCacheIndex = adapter.getMetricsCategory();
+ View detailView = adapter.createDetailView(mContext, mDetailViews.get(viewCacheIndex),
+ mDetailContent);
+ if (detailView == null) throw new IllegalStateException("Must return detail view");
+
+ final Intent settingsIntent = adapter.getSettingsIntent();
+ mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
+ mDetailSettingsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHost.startActivityDismissingKeyguard(settingsIntent);
+ }
+ });
+
+ mDetailContent.removeAllViews();
+ mDetailContent.addView(detailView);
+ mDetailViews.put(viewCacheIndex, detailView);
+ MetricsLogger.visible(mContext, adapter.getMetricsCategory());
+ announceForAccessibility(mContext.getString(
+ R.string.accessibility_quick_settings_detail,
+ adapter.getTitle()));
+ mDetailAdapter = adapter;
+ listener = mHideGridContentWhenDone;
+ setVisibility(View.VISIBLE);
+ } else {
+ if (mDetailAdapter != null) {
+ MetricsLogger.hidden(mContext, mDetailAdapter.getMetricsCategory());
+ }
+ mClosingDetail = true;
+ mDetailAdapter = null;
+ listener = mTeardownDetailWhenDone;
+ mQsPanel.setGridContentVisibility(true);
+ mQsPanelCallback.onScanStateChanged(false);
+ }
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ if (visibleDiff) {
+ if (mFullyExpanded || mDetailAdapter != null) {
+ setAlpha(1);
+ mClipper.animateCircularClip(x, y, mDetailAdapter != null, listener);
+ } else {
+ animate().alpha(0)
+ .setDuration(FADE_DURATION)
+ .setListener(listener)
+ .start();
+ }
+ }
+ }
+
+ private void handleToggleStateChanged(boolean state) {
+ mQsDetailHeaderSwitch.setChecked(state);
+ }
+
+ private void handleScanStateChanged(boolean state) {
+ if (mScanState == state) return;
+ mScanState = state;
+ final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
+ if (state) {
+ mQsDetailHeaderProgress.animate().alpha(1f);
+ anim.start();
+ } else {
+ mQsDetailHeaderProgress.animate().alpha(0f);
+ anim.stop();
+ }
+ }
+
+ private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
+ @Override
+ public void onToggleStateChanged(final boolean state) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ handleToggleStateChanged(state);
+ }
+ });
+ }
+
+ @Override
+ public void onShowingDetail(final DetailAdapter detail, final int x, final int y) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ handleShowingDetail(detail, x, y);
+ }
+ });
+ }
+
+ @Override
+ public void onScanStateChanged(final boolean state) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ handleScanStateChanged(state);
+ }
+ });
+ }
+ };
+
+ private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
+ public void onAnimationCancel(Animator animation) {
+ // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
+ // called, this will avoid accidentally turning off the grid when we don't want to.
+ animation.removeListener(this);
+ };
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Only hide content if still in detail state.
+ if (mDetailAdapter != null) {
+ mQsPanel.setGridContentVisibility(false);
+ }
+ }
+ };
+
+ private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mDetailContent.removeAllViews();
+ setVisibility(View.INVISIBLE);
+ mClosingDetail = false;
+ };
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 1df372bc6f5e..267ed16d2d07 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -70,11 +70,13 @@ public class QSIconView extends ViewGroup {
protected void setIcon(ImageView iv, QSTile.State state) {
if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
Drawable d = state.icon != null ? state.icon.getDrawable(mContext) : null;
+ int padding = state.icon != null ? state.icon.getPadding() : null;
if (d != null && state.autoMirrorDrawable) {
d.setAutoMirrored(true);
}
iv.setImageDrawable(d);
iv.setTag(R.id.qs_icon_tag, state.icon);
+ iv.setPadding(0, padding, 0, padding);
if (d instanceof Animatable) {
Animatable a = (Animatable) d;
a.start();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 1961860d95f6..30a985052bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -16,12 +16,8 @@
package com.android.systemui.qs;
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
@@ -29,16 +25,10 @@ import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
-
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile.DetailAdapter;
import com.android.systemui.qs.customize.QSCustomizer;
@@ -54,27 +44,20 @@ import java.util.ArrayList;
import java.util.Collection;
/** View that represents the quick settings tile panel. **/
-public class QSPanel extends FrameLayout implements Tunable {
+public class QSPanel extends LinearLayout implements Tunable {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
protected final Context mContext;
protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
- private final View mDetail;
- private final ViewGroup mDetailContent;
- private final TextView mDetailSettingsButton;
- private final TextView mDetailDoneButton;
protected final View mBrightnessView;
- private final QSDetailClipper mClipper;
private final H mHandler = new H();
private int mPanelPaddingBottom;
private int mBrightnessPaddingTop;
private boolean mExpanded;
private boolean mListening;
- private boolean mClosingDetail;
- private Record mDetailRecord;
private Callback mCallback;
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
@@ -82,10 +65,10 @@ public class QSPanel extends FrameLayout implements Tunable {
protected QSFooter mFooter;
private boolean mGridContentVisible = true;
- protected LinearLayout mQsContainer;
protected QSTileLayout mTileLayout;
private QSCustomizer mCustomizePanel;
+ private Record mDetailRecord;
public QSPanel(Context context) {
this(context, null);
@@ -95,47 +78,40 @@ public class QSPanel extends FrameLayout implements Tunable {
super(context, attrs);
mContext = context;
- mDetail = LayoutInflater.from(context).inflate(R.layout.qs_detail, this, false);
- mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
- mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
- mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);
- updateDetailText();
- mDetail.setVisibility(GONE);
- mDetail.setClickable(true);
- addView(mDetail);
-
- mQsContainer = new LinearLayout(mContext);
- mQsContainer.setOrientation(LinearLayout.VERTICAL);
- mQsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT));
- addView(mQsContainer);
+ setOrientation(VERTICAL);
mBrightnessView = LayoutInflater.from(context).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
- mQsContainer.addView(mBrightnessView);
+ addView(mBrightnessView);
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
- R.layout.qs_paged_tile_layout, mQsContainer, false);
- mQsContainer.addView((View) mTileLayout);
+ R.layout.qs_paged_tile_layout, this, false);
+ addView((View) mTileLayout);
+ findViewById(android.R.id.edit).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ mHost.startRunnableDismissingKeyguard(new Runnable() {
+ @Override
+ public void run() {
+ showEdit(v);
+ }
+ });
+ }
+ });
mFooter = new QSFooter(this, context);
- mQsContainer.addView(mFooter.getView());
+ addView(mFooter.getView());
- mClipper = new QSDetailClipper(mDetail);
updateResources();
mBrightnessController = new BrightnessController(getContext(),
(ImageView) findViewById(R.id.brightness_icon),
(ToggleSlider) findViewById(R.id.brightness_slider));
- mDetailDoneButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- announceForAccessibility(
- mContext.getString(R.string.accessibility_desc_quick_settings));
- closeDetail();
- }
- });
+ }
+
+ public boolean isShowingCustomize() {
+ return mCustomizePanel != null && mCustomizePanel.isCustomizing();
}
@Override
@@ -178,11 +154,6 @@ public class QSPanel extends FrameLayout implements Tunable {
mCustomizePanel.setHost(mHost);
}
- private void updateDetailText() {
- mDetailDoneButton.setText(R.string.quick_settings_done);
- mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
- }
-
public void setBrightnessMirror(BrightnessMirrorController c) {
super.onFinishInflate();
ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
@@ -209,14 +180,13 @@ public class QSPanel extends FrameLayout implements Tunable {
final Resources res = mContext.getResources();
mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
- mQsContainer.setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
+ setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
for (TileRecord r : mRecords) {
r.tile.clearState();
}
if (mListening) {
refreshAllTiles();
}
- updateDetailText();
if (mTileLayout != null) {
mTileLayout.updateResources();
}
@@ -225,18 +195,6 @@ public class QSPanel extends FrameLayout implements Tunable {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size);
- FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size);
-
- // We need to poke the detail views as well as they might not be attached to the view
- // hierarchy but reused at a later point.
- int count = mRecords.size();
- for (int i = 0; i < count; i++) {
- View detailView = mRecords.get(i).detailView;
- if (detailView != null) {
- detailView.dispatchConfigurationChanged(newConfig);
- }
- }
mFooter.onConfigurationChanged();
}
@@ -249,6 +207,9 @@ public class QSPanel extends FrameLayout implements Tunable {
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
+ if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
+ ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+ }
MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded);
if (!mExpanded) {
closeDetail();
@@ -284,7 +245,7 @@ public class QSPanel extends FrameLayout implements Tunable {
public void showDetailAdapter(boolean show, DetailAdapter adapter, int[] locationInWindow) {
int xInWindow = locationInWindow[0];
int yInWindow = locationInWindow[1];
- mDetail.getLocationInWindow(locationInWindow);
+ ((View) getParent()).getLocationInWindow(locationInWindow);
Record r = new Record();
r.detailAdapter = adapter;
@@ -309,9 +270,6 @@ public class QSPanel extends FrameLayout implements Tunable {
for (QSTile<?> tile : tiles) {
addTile(tile);
}
- if (isShowingDetail()) {
- mDetail.bringToFront();
- }
}
private void drawTile(TileRecord r, QSTile.State state) {
@@ -329,9 +287,7 @@ public class QSPanel extends FrameLayout implements Tunable {
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
- if (!r.openingDetail) {
- drawTile(r, state);
- }
+ drawTile(r, state);
}
@Override
@@ -369,18 +325,7 @@ public class QSPanel extends FrameLayout implements Tunable {
final View.OnLongClickListener longClick = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- if (mCustomizePanel != null) {
- if (!mCustomizePanel.isCustomizing()) {
- int[] loc = new int[2];
- getLocationInWindow(loc);
- int x = r.tileView.getLeft() + r.tileView.getWidth() / 2 + loc[0];
- int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r)
- + r.tileView.getHeight() / 2 + loc[1];
- mCustomizePanel.show(x, y);
- }
- } else {
- r.tile.longClick();
- }
+ r.tile.longClick();
return true;
}
};
@@ -395,13 +340,27 @@ public class QSPanel extends FrameLayout implements Tunable {
}
}
- protected void onTileClick(QSTile<?> tile) {
- tile.click();
+
+ private void showEdit(final View v) {
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCustomizePanel != null) {
+ if (!mCustomizePanel.isCustomizing()) {
+ int[] loc = new int[2];
+ v.getLocationInWindow(loc);
+ int x = loc[0];
+ int y = loc[1];
+ mCustomizePanel.show(x, y);
+ }
+ }
+
+ }
+ });
}
- public boolean isShowingDetail() {
- return mDetailRecord != null
- || (mCustomizePanel != null && mCustomizePanel.isCustomizing());
+ protected void onTileClick(QSTile<?> tile) {
+ tile.click();
}
public void closeDetail() {
@@ -413,12 +372,8 @@ public class QSPanel extends FrameLayout implements Tunable {
showDetail(false, mDetailRecord);
}
- public boolean isClosingDetail() {
- return mClosingDetail;
- }
-
public int getGridHeight() {
- return mQsContainer.getMeasuredHeight();
+ return getMeasuredHeight();
}
protected void handleShowDetail(Record r, boolean show) {
@@ -447,60 +402,27 @@ public class QSPanel extends FrameLayout implements Tunable {
}
r.tile.setDetailListening(show);
int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
- int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2;
+ int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2
+ + getTop();
handleShowDetailImpl(r, show, x, y);
}
private void handleShowDetailImpl(Record r, boolean show, int x, int y) {
- boolean visibleDiff = (mDetailRecord != null) != show;
- if (!visibleDiff && mDetailRecord == r) return; // already in right state
- DetailAdapter detailAdapter = null;
- AnimatorListener listener = null;
- if (show) {
- detailAdapter = r.detailAdapter;
- r.detailView = detailAdapter.createDetailView(mContext, r.detailView, mDetailContent);
- if (r.detailView == null) throw new IllegalStateException("Must return detail view");
-
- final Intent settingsIntent = detailAdapter.getSettingsIntent();
- mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
- mDetailSettingsButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mHost.startActivityDismissingKeyguard(settingsIntent);
- }
- });
-
- mDetailContent.removeAllViews();
- mDetail.bringToFront();
- mDetailContent.addView(r.detailView);
- MetricsLogger.visible(mContext, detailAdapter.getMetricsCategory());
- announceForAccessibility(mContext.getString(
- R.string.accessibility_quick_settings_detail,
- detailAdapter.getTitle()));
- setDetailRecord(r);
- listener = mHideGridContentWhenDone;
- if (r instanceof TileRecord && visibleDiff) {
- ((TileRecord) r).openingDetail = true;
- }
- } else {
- if (mDetailRecord != null) {
- MetricsLogger.hidden(mContext, mDetailRecord.detailAdapter.getMetricsCategory());
- }
- mClosingDetail = true;
- setGridContentVisibility(true);
- listener = mTeardownDetailWhenDone;
- fireScanStateChanged(false);
- }
- sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- fireShowingDetail(show ? detailAdapter : null);
- if (visibleDiff) {
- mClipper.animateCircularClip(x, y, show, listener);
- }
+ setDetailRecord(show ? r : null);
+ fireShowingDetail(show ? r.detailAdapter : null, x, y);
}
- private void setGridContentVisibility(boolean visible) {
+ private void setDetailRecord(Record r) {
+ if (r == mDetailRecord) return;
+ mDetailRecord = r;
+ final boolean scanState = mDetailRecord instanceof TileRecord
+ && ((TileRecord) mDetailRecord).scanState;
+ fireScanStateChanged(scanState);
+ }
+
+ void setGridContentVisibility(boolean visible) {
int newVis = visible ? VISIBLE : INVISIBLE;
- mQsContainer.setVisibility(newVis);
+ setVisibility(newVis);
if (mGridContentVisible != visible) {
MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, newVis);
}
@@ -514,9 +436,9 @@ public class QSPanel extends FrameLayout implements Tunable {
}
}
- private void fireShowingDetail(QSTile.DetailAdapter detail) {
+ private void fireShowingDetail(DetailAdapter detail, int x, int y) {
if (mCallback != null) {
- mCallback.onShowingDetail(detail);
+ mCallback.onShowingDetail(detail, x, y);
}
}
@@ -532,14 +454,6 @@ public class QSPanel extends FrameLayout implements Tunable {
}
}
- private void setDetailRecord(Record r) {
- if (r == mDetailRecord) return;
- mDetailRecord = r;
- final boolean scanState = mDetailRecord instanceof TileRecord
- && ((TileRecord) mDetailRecord).scanState;
- fireScanStateChanged(scanState);
- }
-
public void clickTile(ComponentName tile) {
final String spec = CustomTile.toSpec(tile);
final int N = mRecords.size();
@@ -551,6 +465,19 @@ public class QSPanel extends FrameLayout implements Tunable {
}
}
+ QSTileLayout getTileLayout() {
+ return mTileLayout;
+ }
+
+ QSTileBaseView getTileView(QSTile<?> tile) {
+ for (TileRecord r : mRecords) {
+ if (r.tile == tile) {
+ return r.tileView;
+ }
+ }
+ return null;
+ }
+
private class H extends Handler {
private static final int SHOW_DETAIL = 1;
private static final int SET_TILE_VISIBILITY = 2;
@@ -563,7 +490,6 @@ public class QSPanel extends FrameLayout implements Tunable {
}
protected static class Record {
- View detailView;
DetailAdapter detailAdapter;
int x;
int y;
@@ -573,45 +499,10 @@ public class QSPanel extends FrameLayout implements Tunable {
public QSTile<?> tile;
public QSTileBaseView tileView;
public boolean scanState;
- public boolean openingDetail;
}
- private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- mDetailContent.removeAllViews();
- setDetailRecord(null);
- mClosingDetail = false;
- };
- };
-
- private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
- public void onAnimationCancel(Animator animation) {
- // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
- // called, this will avoid accidentally turning off the grid when we don't want to.
- animation.removeListener(this);
- redrawTile();
- };
-
- @Override
- public void onAnimationEnd(Animator animation) {
- // Only hide content if still in detail state.
- if (mDetailRecord != null) {
- setGridContentVisibility(false);
- redrawTile();
- }
- }
-
- private void redrawTile() {
- if (mDetailRecord instanceof TileRecord) {
- final TileRecord tileRecord = (TileRecord) mDetailRecord;
- tileRecord.openingDetail = false;
- drawTile(tileRecord, tileRecord.tile.getState());
- }
- }
- };
-
public interface Callback {
- void onShowingDetail(QSTile.DetailAdapter detail);
+ void onShowingDetail(DetailAdapter detail, int x, int y);
void onToggleStateChanged(boolean state);
void onScanStateChanged(boolean state);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index e363b767ab9f..df622b8f374c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.phone.ManagedProfileController;
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.DisplayController;
+import com.android.systemui.statusbar.policy.NightModeController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -212,9 +212,11 @@ public abstract class QSTile<TState extends State> implements Listenable {
}
protected void handleLongClick() {
- // optional
+ mHost.startActivityDismissingKeyguard(getLongClickIntent());
}
+ public abstract Intent getLongClickIntent();
+
protected void handleClearState() {
mTmpState = newTileState();
mState = newTileState();
@@ -279,10 +281,11 @@ public abstract class QSTile<TState extends State> implements Listenable {
mCallbacks.clear();
}
- protected void checkIfRestrictionEnforced(State state, String userRestriction) {
+ protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
userRestriction, ActivityManager.getCurrentUser());
- if (admin != null) {
+ if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+ userRestriction, ActivityManager.getCurrentUser())) {
state.disabledByPolicy = true;
state.enforcedAdmin = admin;
} else {
@@ -400,7 +403,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
UserInfoController getUserInfoController();
BatteryController getBatteryController();
TileServices getTileServices();
- DisplayController getDisplayController();
+ NightModeController getNightModeController();
void removeTile(String tileSpec);
ManagedProfileController getManagedProfileController();
@@ -417,6 +420,10 @@ public abstract class QSTile<TState extends State> implements Listenable {
public int hashCode() {
return Icon.class.hashCode();
}
+
+ public int getPadding() {
+ return 0;
+ }
}
public static class DrawableIcon extends Icon {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 1a854c22193b..f35aacf8f72d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -49,6 +49,8 @@ public class QSTileBaseView extends LinearLayout {
// Default to Quick Tile padding, and QSTileView will specify its own padding.
int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
setPadding(padding, padding, padding, padding);
+ setClipChildren(false);
+ setClipToPadding(false);
}
private Drawable newTileBackground() {
@@ -77,6 +79,7 @@ public class QSTileBaseView extends LinearLayout {
public void init(OnClickListener click, OnLongClickListener longClick) {
setClickable(true);
setOnClickListener(click);
+ setOnLongClickListener(longClick);
}
@Override
@@ -110,6 +113,10 @@ public class QSTileBaseView extends LinearLayout {
setContentDescription(state.contentDescription);
}
+ View getIcon() {
+ return mIcon;
+ }
+
private class H extends Handler {
private static final int STATE_CHANGED = 1;
public H() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 0d5d115ec817..98a1c23aa645 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -28,6 +28,7 @@ import android.widget.TextView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import libcore.util.Objects;
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
@@ -57,6 +58,10 @@ public class QSTileView extends QSTileBaseView {
setGravity(Gravity.CENTER);
}
+ TextView getLabel() {
+ return mLabel;
+ }
+
private void updateTopPadding() {
Resources res = getResources();
int padding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
@@ -84,14 +89,11 @@ public class QSTileView extends QSTileBaseView {
addView(view);
}
- public void init(OnClickListener clickPrimary, OnLongClickListener longClick) {
- setOnClickListener(clickPrimary);
- setOnLongClickListener(longClick);
- }
-
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
- mLabel.setText(state.label);
+ if (!Objects.equal(mLabel.getText(), state.label)) {
+ mLabel.setText(state.label);
+ }
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 f208470a2927..4408dbf236bf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -17,12 +17,10 @@
package com.android.systemui.qs;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
import com.android.systemui.R;
@@ -45,10 +43,10 @@ public class QuickQSPanel extends QSPanel {
for (int i = 0; i < mRecords.size(); i++) {
mTileLayout.removeTile(mRecords.get(i));
}
- mQsContainer.removeView((View) mTileLayout);
+ removeView((View) mTileLayout);
}
mTileLayout = new HeaderTileLayout(context);
- mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
+ addView((View) mTileLayout, 1 /* Between brightness and footer */);
}
@Override
@@ -103,7 +101,7 @@ public class QuickQSPanel extends QSPanel {
private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
- private final ImageView mDownArrow;
+ private final Space mEndSpacer;
public HeaderTileLayout(Context context) {
super(context);
@@ -112,16 +110,10 @@ public class QuickQSPanel extends QSPanel {
setGravity(Gravity.CENTER_VERTICAL);
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- int padding =
- mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
- mDownArrow = new ImageView(context);
- mDownArrow.setImageResource(R.drawable.ic_expand_more);
- mDownArrow.setImageTintList(ColorStateList.valueOf(context.getResources().getColor(
- android.R.color.white, null)));
- mDownArrow.setLayoutParams(generateLayoutParams());
- mDownArrow.setPadding(padding, padding, padding, padding);
+ mEndSpacer = new Space(context);
+ mEndSpacer.setLayoutParams(generateLayoutParams());
updateDownArrowMargin();
- addView(mDownArrow);
+ addView(mEndSpacer);
setOrientation(LinearLayout.HORIZONTAL);
}
@@ -132,10 +124,10 @@ public class QuickQSPanel extends QSPanel {
}
private void updateDownArrowMargin() {
- LayoutParams params = (LayoutParams) mDownArrow.getLayoutParams();
+ LayoutParams params = (LayoutParams) mEndSpacer.getLayoutParams();
params.setMarginStart(mContext.getResources().getDimensionPixelSize(
R.dimen.qs_expand_margin));
- mDownArrow.setLayoutParams(params);
+ mEndSpacer.setLayoutParams(params);
}
@Override
@@ -191,5 +183,10 @@ public class QuickQSPanel extends QSPanel {
// No resources here.
return false;
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index f7e2338e9be9..55eda9838664 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -81,7 +81,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
previousView = record.tileView.updateAccessibilityOrder(previousView);
}
- setMeasuredDimension(width, (mCellHeight + mCellMargin) * rows + mCellMargin);
+ setMeasuredDimension(width, (mCellHeight + mCellMargin) * rows);
}
private static int exactly(int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
new file mode 100644
index 000000000000..35ade580654a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -0,0 +1,248 @@
+/*
+ * 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.qs;
+
+import android.util.MathUtils;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class, that handles similar properties as animators (delay, interpolators)
+ * but can have a float input as to the amount they should be in effect. This allows
+ * easier animation that tracks input.
+ *
+ * All "delays" and "times" are as fractions from 0-1.
+ */
+public class TouchAnimator {
+
+ private final Object[] mTargets;
+ private final KeyframeSet[] mKeyframeSets;
+ private final float mStartDelay;
+ private final float mEndDelay;
+ private final float mSpan;
+ private final Interpolator mInterpolator;
+ private final Listener mListener;
+ private float mLastT = -1;
+
+ private TouchAnimator(Object[] targets, KeyframeSet[] keyframeSets,
+ float startDelay, float endDelay, Interpolator interpolator, Listener listener) {
+ mTargets = targets;
+ mKeyframeSets = keyframeSets;
+ mStartDelay = startDelay;
+ mEndDelay = endDelay;
+ mSpan = (1 - mEndDelay - mStartDelay);
+ mInterpolator = interpolator;
+ mListener = listener;
+ }
+
+ public void setPosition(float fraction) {
+ float t = MathUtils.constrain((fraction - mStartDelay) / mSpan, 0, 1);
+ if (mInterpolator != null) {
+ t = mInterpolator.getInterpolation(t);
+ }
+ if (t == mLastT) {
+ return;
+ }
+ if (mListener != null) {
+ if (t == 1) {
+ mListener.onAnimationAtEnd();
+ } else if (t == 0) {
+ mListener.onAnimationAtStart();
+ } else if (mLastT <= 0 || mLastT == 1) {
+ mListener.onAnimationStarted();
+ }
+ mLastT = t;
+ }
+ for (int i = 0; i < mTargets.length; i++) {
+ mKeyframeSets[i].setValue(t, mTargets[i]);
+ }
+ }
+
+ public static class ListenerAdapter implements Listener {
+ @Override
+ public void onAnimationAtStart() { }
+
+ @Override
+ public void onAnimationAtEnd() { }
+
+ @Override
+ public void onAnimationStarted() { }
+ }
+
+ public interface Listener {
+ /**
+ * Called when the animator moves into a position of "0". Start and end delays are
+ * taken into account, so this position may cover a range of fractional inputs.
+ */
+ void onAnimationAtStart();
+
+ /**
+ * Called when the animator moves into a position of "0". Start and end delays are
+ * taken into account, so this position may cover a range of fractional inputs.
+ */
+ void onAnimationAtEnd();
+
+ /**
+ * Called when the animator moves out of the start or end position and is in a transient
+ * state.
+ */
+ void onAnimationStarted();
+ }
+
+ public static class Builder {
+ private List<Object> mTargets = new ArrayList<>();
+ private List<KeyframeSet> mValues = new ArrayList<>();
+
+ private float mStartDelay;
+ private float mEndDelay;
+ private Interpolator mInterpolator;
+ private Listener mListener;
+
+ public Builder addFloat(Object target, String property, float... values) {
+ add(target, KeyframeSet.ofFloat(getProperty(target, property, float.class), values));
+ return this;
+ }
+
+ public Builder addInt(Object target, String property, int... values) {
+ add(target, KeyframeSet.ofInt(getProperty(target, property, int.class), values));
+ return this;
+ }
+
+ private void add(Object target, KeyframeSet keyframeSet) {
+ mTargets.add(target);
+ mValues.add(keyframeSet);
+ }
+
+ private static Property getProperty(Object target, String property, Class<?> cls) {
+ if (target instanceof View) {
+ switch (property) {
+ case "translationX":
+ return View.TRANSLATION_X;
+ case "translationY":
+ return View.TRANSLATION_Y;
+ case "translationZ":
+ return View.TRANSLATION_Z;
+ case "alpha":
+ return View.ALPHA;
+ case "rotation":
+ return View.ROTATION;
+ case "x":
+ return View.X;
+ case "y":
+ return View.Y;
+ case "scaleX":
+ return View.SCALE_X;
+ case "scaleY":
+ return View.SCALE_Y;
+ }
+ }
+ return Property.of(target.getClass(), cls, property);
+ }
+
+ public Builder setStartDelay(float startDelay) {
+ mStartDelay = startDelay;
+ return this;
+ }
+
+ public Builder setEndDelay(float endDelay) {
+ mEndDelay = endDelay;
+ return this;
+ }
+
+ public Builder setInterpolator(Interpolator intepolator) {
+ mInterpolator = intepolator;
+ return this;
+ }
+
+ public Builder setListener(Listener listener) {
+ mListener = listener;
+ return this;
+ }
+
+ public TouchAnimator build() {
+ return new TouchAnimator(mTargets.toArray(new Object[mTargets.size()]),
+ mValues.toArray(new KeyframeSet[mValues.size()]),
+ mStartDelay, mEndDelay, mInterpolator, mListener);
+ }
+ }
+
+ private static abstract class KeyframeSet {
+
+ private final float mFrameWidth;
+ private final int mSize;
+
+ public KeyframeSet(int size) {
+ mSize = size;
+ mFrameWidth = 1 / (float) (size - 1);
+ }
+
+ void setValue(float fraction, Object target) {
+ int i;
+ for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
+ float amount = fraction / mFrameWidth;
+ interpolate(i, amount, target);
+ }
+
+ protected abstract void interpolate(int index, float amount, Object target);
+
+ public static KeyframeSet ofInt(Property property, int... values) {
+ return new IntKeyframeSet((Property<?, Integer>) property, values);
+ }
+
+ public static KeyframeSet ofFloat(Property property, float... values) {
+ return new FloatKeyframeSet((Property<?, Float>) property, values);
+ }
+ }
+
+ private static class FloatKeyframeSet<T> extends KeyframeSet {
+ private final float[] mValues;
+ private final Property<T, Float> mProperty;
+
+ public FloatKeyframeSet(Property<T, Float> property, float[] values) {
+ super(values.length);
+ mProperty = property;
+ mValues = values;
+ }
+
+ @Override
+ protected void interpolate(int index, float amount, Object target) {
+ float firstFloat = mValues[index - 1];
+ float secondFloat = mValues[index];
+ mProperty.set((T) target, firstFloat + (secondFloat - firstFloat) * amount);
+ }
+ }
+
+ private static class IntKeyframeSet<T> extends KeyframeSet {
+ private final int[] mValues;
+ private final Property<T, Integer> mProperty;
+
+ public IntKeyframeSet(Property<T, Integer> property, int[] values) {
+ super(values.length);
+ mProperty = property;
+ mValues = values;
+ }
+
+ @Override
+ protected void interpolate(int index, float amount, Object target) {
+ int firstFloat = mValues[index - 1];
+ int secondFloat = mValues[index];
+ mProperty.set((T) target, (int) (firstFloat + (secondFloat - firstFloat) * amount));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index edcccaca2a14..225c10fc49e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -17,16 +17,20 @@ package com.android.systemui.qs.customize;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.LinearLayout;
+import android.widget.Toolbar;
+import android.widget.Toolbar.OnMenuItemClickListener;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTile;
@@ -42,7 +46,9 @@ import java.util.List;
* This adds itself to the status bar window, so it can appear on top of quick settings and
* *someday* do fancy animations to get into/out of it.
*/
-public class QSCustomizer extends LinearLayout implements AnimatorListener, OnClickListener {
+public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
+
+ private static final int MENU_RESET = Menu.FIRST;
private final QSDetailClipper mClipper;
@@ -52,9 +58,7 @@ public class QSCustomizer extends LinearLayout implements AnimatorListener, OnCl
private QSTileHost mHost;
private RecyclerView mRecyclerView;
private TileAdapter mTileAdapter;
- private View mClose;
- private View mSave;
- private View mReset;
+ private Toolbar mToolbar;
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
@@ -69,17 +73,25 @@ public class QSCustomizer extends LinearLayout implements AnimatorListener, OnCl
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mClose = findViewById(R.id.close);
- mSave = findViewById(R.id.save);
- mReset = findViewById(R.id.reset);
- mClose.setOnClickListener(this);
- mSave.setOnClickListener(this);
- mReset.setOnClickListener(this);
+ mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar);
+ TypedValue value = new TypedValue();
+ mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
+ mToolbar.setNavigationIcon(
+ getResources().getDrawable(value.resourceId, mContext.getTheme()));
+ mToolbar.setNavigationOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
+ }
+ });
+ mToolbar.setOnMenuItemClickListener(this);
+ mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
+ mContext.getString(com.android.internal.R.string.reset));
mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
mTileAdapter = new TileAdapter(getContext());
mRecyclerView.setAdapter(mTileAdapter);
- new ItemTouchHelper(mTileAdapter.getCallback()).attachToRecyclerView(mRecyclerView);
+ mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
mRecyclerView.setLayoutManager(layout);
@@ -90,22 +102,37 @@ public class QSCustomizer extends LinearLayout implements AnimatorListener, OnCl
}
public void show(int x, int y) {
- isShown = true;
- mPhoneStatusBar.getStatusBarWindow().addView(this);
- setTileSpecs();
- mClipper.animateCircularClip(x, y, true, this);
- new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
+ if (!isShown) {
+ isShown = true;
+ mPhoneStatusBar.getStatusBarWindow().addView(this);
+ setTileSpecs();
+ mClipper.animateCircularClip(x, y, true, null);
+ new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
+ }
}
public void hide(int x, int y) {
- isShown = false;
- mClipper.animateCircularClip(x, y, false, this);
+ if (isShown) {
+ isShown = false;
+ save();
+ mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
+ }
}
public boolean isCustomizing() {
return isShown;
}
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_RESET:
+ reset();
+ break;
+ }
+ return false;
+ }
+
private void reset() {
ArrayList<String> tiles = new ArrayList<>();
String defTiles = mContext.getString(R.string.quick_settings_tiles_default);
@@ -125,42 +152,21 @@ public class QSCustomizer extends LinearLayout implements AnimatorListener, OnCl
private void save() {
mTileAdapter.saveSpecs(mHost);
- hide((int) mSave.getX() + mSave.getWidth() / 2, (int) mSave.getY() + mSave.getHeight() / 2);
- }
-
- @Override
- public void onClick(View v) {
- if (v == mClose) {
- hide((int) mClose.getX() + mClose.getWidth() / 2,
- (int) mClose.getY() + mClose.getHeight() / 2);
- } else if (v == mSave) {
- save();
- } else if (v == mReset) {
- reset();
- }
}
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!isShown) {
- mPhoneStatusBar.getStatusBarWindow().removeView(this);
+ private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!isShown) {
+ mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
+ }
}
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- if (!isShown) {
- mPhoneStatusBar.getStatusBarWindow().removeView(this);
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!isShown) {
+ mPhoneStatusBar.getStatusBarWindow().removeView(QSCustomizer.this);
+ }
}
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- // Don't care.
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- // Don't care.
- }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index fb3818cf9db1..d1953b13eec9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -24,8 +24,8 @@ import android.support.v7.widget.RecyclerView.ItemDecoration;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.helper.ItemTouchHelper;
-import android.support.v7.widget.helper.ItemTouchHelper.Callback;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -52,6 +52,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
private final Context mContext;
private final List<TileInfo> mTiles = new ArrayList<>();
+ private final ItemTouchHelper mItemTouchHelper;
private int mDividerIndex;
private List<String> mCurrentSpecs;
private List<TileInfo> mOtherTiles;
@@ -61,6 +62,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
public TileAdapter(Context context) {
mContext = context;
+ mItemTouchHelper = new ItemTouchHelper(mCallbacks);
setHasStableIds(true);
}
@@ -69,8 +71,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
}
- public Callback getCallback() {
- return mCallbacks;
+ public ItemTouchHelper getItemTouchHelper() {
+ return mItemTouchHelper;
}
public ItemDecoration getItemDecoration() {
@@ -104,7 +106,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
mTiles.clear();
for (int i = 0; i < mCurrentSpecs.size(); i++) {
- mTiles.add(getAndRemoveOther(mCurrentSpecs.get(i)));
+ final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i));
+ if (tile != null) {
+ mTiles.add(tile);
+ }
}
mTiles.add(null);
mTiles.addAll(mOtherTiles);
@@ -148,7 +153,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
}
@Override
- public void onBindViewHolder(Holder holder, int position) {
+ public void onBindViewHolder(final Holder holder, int position) {
if (holder.getItemViewType() == TYPE_EDIT) return;
TileInfo info = mTiles.get(position);
@@ -166,6 +171,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
super(itemView);
if (itemView instanceof FrameLayout) {
mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+ mTileView.setBackground(null);
}
}
@@ -266,9 +272,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
if (to > mDividerIndex) {
- if (from < mDividerIndex) {
- to = mDividerIndex;
- } else {
+ if (from >= mDividerIndex) {
return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 2a10c0b39544..aa85f784fe4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.customize;
+import android.Manifest.permission;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -27,11 +28,14 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.service.quicksettings.TileService;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.DrawableIcon;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.Collection;
@@ -53,9 +57,10 @@ public class TileQueryHelper {
}
private void addSystemTiles(QSTileHost host) {
- boolean hasColorMod = host.getDisplayController().isEnabled();
+ boolean hasColorMod = Prefs.getBoolean(host.getContext(), Key.QS_NIGHT_ADDED, false)
+ && TunerService.isTunerEnabled(host.getContext());
String possible = mContext.getString(R.string.quick_settings_tiles_default)
- + ",hotspot,inversion,saver,work" + (hasColorMod ? ",colors" : "");
+ + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",night" : "");
String[] possibleTiles = possible.split(",");
final Handler qsHandler = new Handler(host.getLooper());
final Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -87,7 +92,12 @@ public class TileQueryHelper {
qsHandler.post(new Runnable() {
@Override
public void run() {
- new QueryTilesTask().execute();
+ mainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ new QueryTilesTask().execute();
+ }
+ });
}
});
}
@@ -132,6 +142,9 @@ public class TileQueryHelper {
ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
String spec = CustomTile.toSpec(componentName);
Drawable icon = info.serviceInfo.loadIcon(pm);
+ if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
+ continue;
+ }
if (icon != null) {
icon.mutate();
icon.setTint(mContext.getColor(android.R.color.white));
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 3cd9e67e1269..0709992c07ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -15,13 +15,18 @@
*/
package com.android.systemui.qs.external;
+import android.app.ActivityManager;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.Settings;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
@@ -156,8 +161,22 @@ public class CustomTile extends QSTile<QSTile.State> {
}
@Override
- protected void handleUserSwitch(int newUserId) {
- super.handleUserSwitch(newUserId);
+ public Intent getLongClickIntent() {
+ Intent i = new Intent(TileService.ACTION_QS_TILE_PREFERENCES);
+ i.setPackage(mComponent.getPackageName());
+ i = resolveIntent(i);
+ if (i != null) {
+ return i;
+ }
+ return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
+ Uri.fromParts("package", mComponent.getPackageName(), null));
+ }
+
+ private Intent resolveIntent(Intent i) {
+ ResolveInfo result = mContext.getPackageManager().resolveActivityAsUser(i, 0,
+ ActivityManager.getCurrentUser());
+ return result != null ? new Intent(TileService.ACTION_QS_TILE_PREFERENCES)
+ .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
}
@Override
@@ -184,10 +203,6 @@ public class CustomTile extends QSTile<QSTile.State> {
}
@Override
- protected void handleLongClick() {
- }
-
- @Override
protected void handleUpdateState(State state, Object arg) {
Drawable drawable = mTile.getIcon().loadDrawable(mContext);
int color = mContext.getColor(getColor(mTile.getState()));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 5222e61ab5d3..f0860fe181d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
+import android.provider.Settings;
import android.provider.Settings.Global;
import com.android.internal.logging.MetricsLogger;
@@ -68,6 +69,11 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
final boolean airplaneMode = value != 0;
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 72cdf180f999..39d14473b271 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -15,19 +15,26 @@
*/
package com.android.systemui.qs.tiles;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.RelativeSizeSpan;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.TextView;
-
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.BatteryInfo;
+import com.android.settingslib.graph.UsageView;
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -44,6 +51,7 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
private int mLevel;
private boolean mPowerSave;
private boolean mCharging;
+ private boolean mDetailShown;
public BatteryTile(Host host) {
super(host);
@@ -88,6 +96,11 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ }
+
+ @Override
protected void handleClick() {
showDetail(true);
}
@@ -102,6 +115,12 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
public Drawable getDrawable(Context context) {
return mDrawable;
}
+
+ @Override
+ public int getPadding() {
+ return mHost.getContext().getResources().getDimensionPixelSize(
+ R.dimen.qs_battery_padding);
+ }
};
state.label = percentage;
}
@@ -111,20 +130,21 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
mLevel = level;
mCharging = charging;
refreshState((Integer) level);
- if (mBatteryDetail.mCurrentView != null) {
- mBatteryDetail.bindView();
+ if (mDetailShown) {
+ mBatteryDetail.postBindView();
}
}
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
mPowerSave = isPowerSave;
- if (mBatteryDetail.mCurrentView != null) {
- mBatteryDetail.bindView();
+ if (mDetailShown) {
+ mBatteryDetail.postBindView();
}
}
- private final class BatteryDetail implements DetailAdapter, View.OnClickListener {
+ private final class BatteryDetail implements DetailAdapter, OnClickListener,
+ OnAttachStateChangeListener {
private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
private View mCurrentView;
@@ -146,10 +166,20 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
false);
}
mCurrentView = convertView;
+ mCurrentView.addOnAttachStateChangeListener(this);
bindView();
return convertView;
}
+ private void postBindView() {
+ mCurrentView.post(new Runnable() {
+ @Override
+ public void run() {
+ bindView();
+ }
+ });
+ }
+
private void bindView() {
mDrawable.onBatteryLevelChanged(100, false, false);
mDrawable.onPowerSaveChanged(true);
@@ -157,33 +187,49 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
checkbox.setChecked(mPowerSave);
- if (mCharging) {
- BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
- @Override
- public void onBatteryInfoLoaded(BatteryInfo info) {
- if (mCurrentView != null && mCharging) {
- ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
- info.mChargeLabelString);
- }
+ BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
+ @Override
+ public void onBatteryInfoLoaded(BatteryInfo info) {
+ if (mCurrentView != null) {
+ bindBatteryInfo(info);
}
- });
- ((TextView) mCurrentView.findViewById(android.R.id.summary)).setText(
+ }
+ });
+ if (mCharging) {
+ ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
R.string.battery_detail_charging_summary);
- mCurrentView.setClickable(false);
mCurrentView.findViewById(android.R.id.icon).setVisibility(View.INVISIBLE);
- mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.INVISIBLE);
+ mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.GONE);
+ mCurrentView.findViewById(R.id.switch_container).setClickable(false);
} else {
((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
R.string.battery_detail_switch_title);
((TextView) mCurrentView.findViewById(android.R.id.summary)).setText(
R.string.battery_detail_switch_summary);
- mCurrentView.setClickable(true);
mCurrentView.findViewById(android.R.id.icon).setVisibility(View.VISIBLE);
mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE);
- mCurrentView.setOnClickListener(this);
+ mCurrentView.findViewById(R.id.switch_container).setClickable(true);
+ mCurrentView.findViewById(R.id.switch_container).setOnClickListener(this);
}
}
+ private void bindBatteryInfo(BatteryInfo info) {
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ builder.append(info.batteryPercentString, new RelativeSizeSpan(2),
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ if (info.remainingLabel != null) {
+ if (mContext.getResources().getBoolean(R.bool.quick_settings_wide)) {
+ builder.append(' ');
+ } else {
+ builder.append('\n');
+ }
+ builder.append(info.remainingLabel);
+ }
+ ((TextView) mCurrentView.findViewById(R.id.charge_and_estimation)).setText(builder);
+
+ info.bindHistory((UsageView) mCurrentView.findViewById(R.id.battery_usage));
+ }
+
@Override
public void onClick(View v) {
mBatteryController.setPowerSaveMode(!mPowerSave);
@@ -203,5 +249,29 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
public int getMetricsCategory() {
return MetricsEvent.QS_BATTERY_DETAIL;
}
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ if (!mDetailShown) {
+ mDetailShown = true;
+ v.getContext().registerReceiver(mReceiver,
+ new IntentFilter(Intent.ACTION_TIME_TICK));
+ }
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (mDetailShown) {
+ mDetailShown = false;
+ v.getContext().unregisterReceiver(mReceiver);
+ }
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ postBindView();
+ }
+ };
}
}
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 c4b7944039ad..80f667c41987 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,11 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (!mController.canConfigBluetooth()) {
mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
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 15e082abff67..e0ad002bc149 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -86,6 +86,11 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_CAST_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
mHost.startRunnableDismissingKeyguard(new Runnable() {
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 15617c7f9c8f..5f87741ced8a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -37,7 +37,7 @@ import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTile<QSTile.SignalState> {
- private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+ static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
"com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
private final NetworkController mController;
@@ -78,6 +78,11 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return CELLULAR_SETTINGS;
+ }
+
+ @Override
protected void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory());
if (mDataController.isMobileDataSupported()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index e98734cb3f43..42ce69c57978 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import com.android.internal.logging.MetricsLogger;
@@ -70,6 +72,11 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mSetting.setValue(mState.value ? 0 : 1);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index c6a98b4fb1d9..fa235d33e4e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -14,6 +14,7 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -44,6 +45,11 @@ public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
}
@Override
+ public Intent getLongClickIntent() {
+ return CellularTile.CELLULAR_SETTINGS;
+ }
+
+ @Override
protected void handleClick() {
mState.value = !mDataSaverController.isDataSaverEnabled();
mDataSaverController.setDataSaverEnabled(mState.value);
@@ -55,8 +61,8 @@ public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
state.value = arg instanceof Boolean ? (Boolean) arg
: mDataSaverController.isDataSaverEnabled();
state.label = mContext.getString(R.string.data_saver);
- state.contentDescription = mContext.getString(state.value ?
- R.string.accessibility_data_saver_on : R.string.accessibility_data_saver_off);
+ state.contentDescription = mContext.getString(state.value
+ ? R.string.accessibility_data_saver_on : R.string.accessibility_data_saver_off);
state.icon = ResourceIcon.get(state.value ? R.drawable.ic_data_saver
: R.drawable.ic_data_saver_off);
}
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 29ca06bfb878..8982b3e1de13 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -29,11 +29,13 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.SysUIToast;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.ZenModePanel;
@@ -99,7 +101,20 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return ZEN_SETTINGS;
+ }
+
+ @Override
public void handleClick() {
+ if (mController.isVolumeRestricted()) {
+ // Collapse the panels, so the user can see the toast.
+ mHost.collapsePanels();
+ SysUIToast.makeText(mContext, mContext.getString(
+ com.android.internal.R.string.error_message_change_not_allowed),
+ Toast.LENGTH_LONG).show();
+ return;
+ }
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
if (mState.value) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
@@ -116,8 +131,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
final boolean newValue = zen != Global.ZEN_MODE_OFF;
final boolean valueChanged = state.value != newValue;
state.value = newValue;
- state.disabledByPolicy = mController.isVolumeRestricted();
- checkIfRestrictionEnforced(state, UserManager.DISALLOW_ADJUST_VOLUME);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index f06634e9cb78..12c8c44412ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -17,7 +17,11 @@
package com.android.systemui.qs.tiles;
import android.app.ActivityManager;
-
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.provider.MediaStore;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -60,6 +64,16 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mFlashlightController.hasFlashlight();
+ }
+
+ @Override
protected void handleClick() {
if (ActivityManager.isUserAMonkey()) {
return;
@@ -72,9 +86,19 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- // TODO: Flashlight available handling...
-// state.visible = mFlashlightController.isAvailable();
state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
+ if (!mFlashlightController.isAvailable()) {
+ Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_disable);
+ final int disabledColor = mHost.getContext().getColor(R.color.qs_tile_tint_unavailable);
+ icon.setTint(disabledColor);
+ state.icon = new DrawableIcon(icon);
+ state.label = new SpannableStringBuilder().append(state.label,
+ new ForegroundColorSpan(disabledColor),
+ SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_flashlight_unavailable);
+ return;
+ }
if (arg instanceof Boolean) {
boolean value = (Boolean) arg;
if (value == state.value) {
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 943b502a565f..ad1c7a0acf01 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,8 +16,10 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import android.os.UserManager;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -58,6 +60,11 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
final boolean isEnabled = (Boolean) mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
@@ -68,8 +75,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
- state.disabledByPolicy = mController.isTetheringAllowed();
- checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
if (arg instanceof Boolean) {
state.value = (boolean) arg;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index bdf95d8782bf..bb5ff8e4cc16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -92,6 +92,11 @@ public class IntentTile extends QSTile<QSTile.State> {
}
@Override
+ public Intent getLongClickIntent() {
+ return null;
+ }
+
+ @Override
protected void handleLongClick() {
sendIntent("long-click", mOnLongClick, mOnLongClickUri);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 9f41f9a17a83..65332529d881 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,8 +16,10 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import android.os.UserManager;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -61,6 +63,11 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (mKeyguard.isSecure() && mKeyguard.isShowing()) {
mHost.startRunnableDismissingKeyguard(new Runnable() {
@@ -87,8 +94,7 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
// bug is fixed, this should be reverted to only hiding it on secure lock screens:
// state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
state.value = locationEnabled;
- state.disabledByPolicy = mController.isUserLocationRestricted();
- checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_SHARE_LOCATION);
if (locationEnabled) {
state.icon = mEnable;
state.label = mContext.getString(R.string.quick_settings_location_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index c94cf5a9bec2..b267ccd1ec46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -17,8 +17,10 @@
package com.android.systemui.qs.tiles;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -60,6 +62,11 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (mController == null) return;
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 33befd0058b9..fcf758b45868 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -103,6 +103,11 @@ public class UserDetailItemView extends LinearLayout {
mAvatar.setDisabled(disabled);
}
+ public void setEnabled(boolean enabled) {
+ mName.setEnabled(enabled);
+ mAvatar.setDisabled(!enabled);
+ }
+
@Override
protected void onFinishInflate() {
mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 2c8a4784e5f2..da9876235263 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -82,6 +82,9 @@ public class UserDetailView extends PseudoGridView {
}
v.setActivated(item.isCurrent);
v.setDisabledByAdmin(item.isDisabledByAdmin);
+ if (!item.isSwitchToEnabled) {
+ v.setEnabled(false);
+ }
v.setTag(item);
return v;
}
@@ -94,7 +97,7 @@ public class UserDetailView extends PseudoGridView {
final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
mContext, tag.enforcedAdmin);
mController.startActivity(intent);
- } else {
+ } else if (tag.isSwitchToEnabled) {
MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
switchTo(tag);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index ba7ea4d66453..f1066c11c11a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -16,7 +16,9 @@
package com.android.systemui.qs.tiles;
import android.content.Context;
+import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.provider.Settings;
import android.util.Pair;
import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -42,6 +44,11 @@ public class UserTile extends QSTile<QSTile.State> implements UserInfoController
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_USER_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
showDetail(true);
}
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 7a58f1553bcd..7ee795f924b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -93,6 +93,11 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
@Override
+ public Intent getLongClickIntent() {
+ return WIFI_SETTINGS;
+ }
+
+ @Override
protected void handleSecondaryClick() {
// Secondary clicks are header clicks, just toggle.
mState.copyTo(mStateBeforeClick);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 053a98a5ce05..003e9c15ad43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -52,6 +54,11 @@ public class WorkModeTile extends QSTile<QSTile.BooleanState> implements
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_SYNC_SETTINGS);
+ }
+
+ @Override
public void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mProfileController.setWorkModeEnabled(!mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index e4fd31d75ead..f5ae3514d780 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -31,10 +31,13 @@ import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.EventLog;
import android.util.Log;
import android.view.Display;
import android.view.View;
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
@@ -83,20 +86,23 @@ public class Recents extends SystemUI
private int mDraggingInRecentsCurrentUser;
// Only For system user, this is the callbacks instance we return to each secondary user
- private RecentsSystemUser mSystemUserCallbacks;
+ private RecentsSystemUser mSystemToUserCallbacks;
// Only for secondary users, this is the callbacks instance provided by the system user to make
// calls back
- private IRecentsSystemUserCallbacks mCallbacksToSystemUser;
+ private IRecentsSystemUserCallbacks mUserToSystemCallbacks;
// The set of runnables to run after binding to the system user's service.
private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>();
// Only for secondary users, this is the death handler for the binder from the system user
- private final IBinder.DeathRecipient mCallbacksToSystemUserDeathRcpt = new IBinder.DeathRecipient() {
+ private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
- mCallbacksToSystemUser = null;
+ mUserToSystemCallbacks = null;
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND,
+ sSystemServicesProxy.getProcessUser());
// Retry after a fixed duration
mHandler.postDelayed(new Runnable() {
@@ -109,16 +115,19 @@ public class Recents extends SystemUI
};
// Only for secondary users, this is the service connection we use to connect to the system user
- private final ServiceConnection mServiceConnectionToSystemUser = new ServiceConnection() {
+ private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service != null) {
- mCallbacksToSystemUser = IRecentsSystemUserCallbacks.Stub.asInterface(
+ mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(
service);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND,
+ sSystemServicesProxy.getProcessUser());
// Listen for system user's death, so that we can reconnect later
try {
- service.linkToDeath(mCallbacksToSystemUserDeathRcpt, 0);
+ service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0);
} catch (RemoteException e) {
Log.e(TAG, "Lost connection to (System) SystemUI", e);
}
@@ -142,7 +151,7 @@ public class Recents extends SystemUI
* Returns the callbacks interface that non-system users can call.
*/
public IBinder getSystemUserCallbacks() {
- return mSystemUserCallbacks;
+ return mSystemToUserCallbacks;
}
public static RecentsTaskLoader getTaskLoader() {
@@ -190,7 +199,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
- mSystemUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+ mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
} else {
// For the secondary user, bind to the primary user's service to get a persistent
// interface to register its implementation and to later update its state
@@ -224,9 +233,9 @@ public class Recents extends SystemUI
mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
true /* animate */, false /* reloadTasks */);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
@@ -260,9 +269,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
@@ -295,9 +304,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.toggleRecents();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.toggleRecents();
@@ -326,9 +335,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.preloadRecents();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.preloadRecents();
@@ -354,9 +363,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.cancelPreloadingRecents();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.cancelPreloadingRecents();
@@ -387,9 +396,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
@@ -413,9 +422,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
mImpl.onDraggingInRecents(distanceFromTop);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
mDraggingInRecentsCurrentUser);
if (callbacks != null) {
try {
@@ -436,9 +445,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
mImpl.onDraggingInRecentsEnded(velocity);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
mDraggingInRecentsCurrentUser);
if (callbacks != null) {
try {
@@ -484,9 +493,9 @@ public class Recents extends SystemUI
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.onConfigurationChanged();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.onConfigurationChanged();
@@ -512,7 +521,7 @@ public class Recents extends SystemUI
@Override
public void run() {
try {
- mCallbacksToSystemUser.updateRecentsVisibility(event.visible);
+ mUserToSystemCallbacks.updateRecentsVisibility(event.visible);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -533,7 +542,7 @@ public class Recents extends SystemUI
@Override
public void run() {
try {
- mCallbacksToSystemUser.startScreenPinning();
+ mUserToSystemCallbacks.startScreenPinning();
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -549,7 +558,7 @@ public class Recents extends SystemUI
@Override
public void run() {
try {
- mCallbacksToSystemUser.sendRecentsDrawnEvent();
+ mUserToSystemCallbacks.sendRecentsDrawnEvent();
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -565,7 +574,7 @@ public class Recents extends SystemUI
@Override
public void run() {
try {
- mCallbacksToSystemUser.sendDockingTopTaskEvent(event.dragMode);
+ mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -581,7 +590,7 @@ public class Recents extends SystemUI
@Override
public void run() {
try {
- mCallbacksToSystemUser.sendLaunchRecentsEvent();
+ mUserToSystemCallbacks.sendLaunchRecentsEvent();
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -599,7 +608,7 @@ public class Recents extends SystemUI
@Override
public void run() {
try {
- mCallbacksToSystemUser.registerNonSystemUserCallbacks(
+ mUserToSystemCallbacks.registerNonSystemUserCallbacks(
new RecentsImplProxy(mImpl), processUser);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register", e);
@@ -614,11 +623,14 @@ public class Recents extends SystemUI
*/
private void postToSystemUser(final Runnable onConnectRunnable) {
mOnConnectRunnables.add(onConnectRunnable);
- if (mCallbacksToSystemUser == null) {
+ if (mUserToSystemCallbacks == null) {
Intent systemUserServiceIntent = new Intent();
systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
- mServiceConnectionToSystemUser, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+ mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE,
+ sSystemServicesProxy.getProcessUser());
if (!bound) {
// Retry after a fixed duration
mHandler.postDelayed(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 3b49d3785384..c41098f3c0ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -230,7 +230,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
* Dismisses the history view back into the stack view.
*/
boolean dismissHistory() {
- if (mRecentsView.isHistoryVisible()) {
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
return true;
}
@@ -240,11 +240,11 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
/**
* Dismisses recents if we are already visible and the intent is to toggle the recents view.
*/
- boolean dismissRecentsToFocusedTask() {
+ boolean dismissRecentsToFocusedTask(int logCategory) {
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
// If we have a focused Task, launch that Task now
- if (mRecentsView.launchFocusedTask()) return true;
+ if (mRecentsView.launchFocusedTask(logCategory)) return true;
}
return false;
}
@@ -270,7 +270,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
// If we have a focused Task, launch that Task now
- if (mRecentsView.launchFocusedTask()) return true;
+ if (mRecentsView.launchFocusedTask(0 /* logCategory */)) return true;
// If none of the other cases apply, then just go Home
dismissRecentsToHome(true /* animateTaskViews */);
return true;
@@ -360,7 +360,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
@Override
public void run() {
- dismissRecentsToFocusedTask();
+ dismissRecentsToFocusedTask(MetricsEvent.OVERVIEW_SELECT_TIMEOUT);
}
});
@@ -447,7 +447,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
// Reset some states
mIgnoreAltTabRelease = false;
- if (mRecentsView.isHistoryVisible()) {
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
}
@@ -503,13 +503,16 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
+ }
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
- if (savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
+ if (RecentsDebugFlags.Static.EnableHistory &&
+ savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
EventBus.getDefault().send(new ShowHistoryEvent());
}
}
@@ -525,17 +528,16 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
@Override
public void onMultiWindowChanged(boolean inMultiWindow) {
super.onMultiWindowChanged(inMultiWindow);
- if (!inMultiWindow) {
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.loadIcons = false;
- launchOpts.loadThumbnails = false;
- launchOpts.onlyLoadForCache = true;
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1, false);
- loader.loadTasks(this, loadPlan, launchOpts);
- EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
- }
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.loadIcons = false;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1, false);
+ loader.loadTasks(this, loadPlan, launchOpts);
+ EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack(),
+ inMultiWindow));
}
@Override
@@ -603,7 +605,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
/**** EventBus events ****/
public final void onBusEvent(ToggleRecentsEvent event) {
- if (!dismissHistory()) {
+ if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
if (launchState.launchedFromHome) {
dismissRecentsToHome(true /* animateTaskViews */);
@@ -614,7 +616,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
}
public final void onBusEvent(IterateRecentsEvent event) {
- if (!dismissHistory()) {
+ if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
// Start dozing after the recents button is clicked
@@ -634,7 +636,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
// Focus the next task
EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
- MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
+ MetricsLogger.action(this, MetricsEvent.OVERVIEW_PAGE);
}
}
@@ -651,7 +653,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
}
} else if (event.triggeredFromHomeKey) {
// Otherwise, dismiss Recents to Home
- if (mRecentsView.isHistoryVisible()) {
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
// If the history view is visible, then just cross-fade home
ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
R.anim.recents_to_launcher_enter,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index f7ebd945f761..aa1437b28ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -66,17 +66,18 @@ public class RecentsActivityLaunchState {
*/
public int getInitialFocusTaskIndex(int numTasks) {
RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
if (launchedFromAppWithThumbnail) {
- if (debugFlags.isFastToggleRecentsEnabled()) {
+ if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
// If fast toggling, focus the front most task so that the next tap will focus the
// N-1 task
return numTasks - 1;
}
// If coming from another app, focus the next task
- return numTasks - 2;
+ return Math.max(0, numTasks - 2);
} else {
- if (debugFlags.isFastToggleRecentsEnabled()) {
+ if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
// If fast toggling, defer focusing until the next tap (which will automatically
// focus the front most task)
return -1;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index fc14758af0f4..cd643230a167 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -37,6 +37,8 @@ public class RecentsDebugFlags implements TunerService.Tunable {
public static final boolean DisableBackgroundCache = false;
// Enables the task affiliations
public static final boolean EnableAffiliatedTaskGroups = true;
+ // Enables the history
+ public static final boolean EnableHistory = false;
// Overrides the Tuner flags and enables the fast toggle and timeout
public static final boolean EnableFastToggleTimeoutOverride = true;
@@ -52,11 +54,9 @@ public class RecentsDebugFlags implements TunerService.Tunable {
public static final int MockTaskGroupsTaskCount = 12;
}
- private static final String KEY_FAST_TOGGLE = "overview_fast_toggle_via_button";
- private static final String KEY_INITIAL_STATE_PAGING = "overview_initial_state_paging";
+ private static final String KEY_DISABLE_FAST_TOGGLE = "overview_disable_fast_toggle_via_button";
- private boolean mFastToggleRecents;
- private boolean mInitialStatePaging;
+ private boolean mDisableFastToggleRecents;
/**
* We read the prefs once when we start the activity, then update them as the tuner changes
@@ -65,7 +65,7 @@ public class RecentsDebugFlags implements TunerService.Tunable {
public RecentsDebugFlags(Context context) {
// Register all our flags, this will also call onTuningChanged() for each key, which will
// initialize the current state of each flag
- TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_INITIAL_STATE_PAGING);
+ TunerService.get(context).addTunable(this, KEY_DISABLE_FAST_TOGGLE);
}
/**
@@ -74,32 +74,21 @@ public class RecentsDebugFlags implements TunerService.Tunable {
public boolean isFastToggleRecentsEnabled() {
// These checks EnableFastToggleTimeoutOverride
SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask() ||
- ssp.isTouchExplorationEnabled()) {
+ if (mDisableFastToggleRecents || ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask()
+ || ssp.isTouchExplorationEnabled()) {
return false;
}
if (Static.EnableFastToggleTimeoutOverride) {
return true;
}
- return mFastToggleRecents;
- }
-
- /**
- * @return whether the initial stack state is paging.
- */
- public boolean isInitialStatePaging() {
- return mInitialStatePaging;
+ return true;
}
@Override
public void onTuningChanged(String key, String newValue) {
switch (key) {
- case KEY_FAST_TOGGLE:
- mFastToggleRecents = (newValue != null) &&
- (Integer.parseInt(newValue) != 0);
- break;
- case KEY_INITIAL_STATE_PAGING:
- mInitialStatePaging = (newValue != null) &&
+ case KEY_DISABLE_FAST_TOGGLE:
+ mDisableFastToggleRecents = (newValue != null) &&
(Integer.parseInt(newValue) != 0);
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 5890b5f959d3..28b2faed58fb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -124,6 +124,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
public void onPinnedActivityRestartAttempt() {
}
+ @Override
+ public void onPinnedStackAnimationEnded() {
+ }
+
/** Preloads the next task */
public void run() {
RecentsConfiguration config = Recents.getConfiguration();
@@ -157,10 +161,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
Handler mHandler;
TaskStackListenerImpl mTaskStackListener;
RecentsAppWidgetHost mAppWidgetHost;
- boolean mBootCompleted;
boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
- boolean mReloadTasks;
boolean mLaunchedWhileDocking;
// Task launching
@@ -232,7 +234,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
public void onBootCompleted() {
- mBootCompleted = true;
updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
}
@@ -313,23 +314,21 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mBootCompleted) {
- if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
- // The user has released alt-tab before the trigger has run, so just show the next
- // task immediately
- showNextTask();
-
- // Cancel the fast alt-tab trigger
- mFastAltTabTrigger.stopDozing();
- mFastAltTabTrigger.resetTrigger();
- return;
- }
+ if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
+ // The user has released alt-tab before the trigger has run, so just show the next
+ // task immediately
+ showNextTask();
- // Defer to the activity to handle hiding recents, if it handles it, then it must still
- // be visible
- EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
- triggeredFromHomeKey));
+ // Cancel the fast alt-tab trigger
+ mFastAltTabTrigger.stopDozing();
+ mFastAltTabTrigger.resetTrigger();
+ return;
}
+
+ // Defer to the activity to handle hiding recents, if it handles it, then it must still
+ // be visible
+ EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
+ triggeredFromHomeKey));
}
public void toggleRecents() {
@@ -343,7 +342,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
mTriggeredFromAltTab = false;
try {
- ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
MutableBoolean isTopTaskHome = new MutableBoolean(true);
@@ -402,9 +400,9 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
MutableBoolean topTaskHome = new MutableBoolean(true);
- RecentsTaskLoader loader = Recents.getTaskLoader();
- sInstanceLoadPlan = loader.createLoadPlan(mContext);
if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ sInstanceLoadPlan = loader.createLoadPlan(mContext);
sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value);
TaskStack stack = sInstanceLoadPlan.getTaskStack();
@@ -833,11 +831,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
* Draws the header of a task used for the window animation into a bitmap.
*/
private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
if (toTransform != null && toTask.key != null) {
Bitmap thumbnail;
synchronized (mHeaderBarLock) {
int toHeaderWidth = (int) toTransform.rect.width();
int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
(int) toTransform.rect.height());
thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
@@ -847,7 +847,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
} else {
Canvas c = new Canvas(thumbnail);
c.scale(toTransform.scale, toTransform.scale);
- mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */);
+ mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
+ disabledInSafeMode);
mHeaderBar.draw(c);
c.setBitmap(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index ae0051cba04e..f8000b8990bf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -19,9 +19,12 @@ package com.android.systemui.recents;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -46,7 +49,8 @@ public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub {
}
@Override
- public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks, int userId) {
+ public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks,
+ final int userId) {
try {
final IRecentsNonSystemUserCallbacks callback =
IRecentsNonSystemUserCallbacks.Stub.asInterface(nonSystemUserCallbacks);
@@ -54,9 +58,14 @@ public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub {
@Override
public void binderDied() {
mNonSystemUserRecents.removeAt(mNonSystemUserRecents.indexOfValue(callback));
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER,
+ userId);
}
}, 0);
mNonSystemUserRecents.put(userId, callback);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER, userId);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register NonSystemUserCallbacks", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index f87f6de3be7c..0d614e8c675c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -28,8 +28,10 @@ public class TaskStackUpdatedEvent extends EventBus.AnimatedEvent {
* A new TaskStack instance representing the latest stack state.
*/
public final TaskStack stack;
+ public final boolean inMultiWindow;
- public TaskStackUpdatedEvent(TaskStack stack) {
+ public TaskStackUpdatedEvent(TaskStack stack, boolean inMultiWindow) {
this.stack = stack;
+ this.inMultiWindow = inMultiWindow;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index 5eeda72637ea..d7b9b9e71d69 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -161,7 +161,7 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
ActivityOptions.makeBasic());
- MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
+ MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
task.key.getComponent().toString());
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
index acad0ea1695a..3d1ea8eedfbe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
@@ -21,6 +21,7 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
@@ -72,6 +73,8 @@ public class RecentsHistoryItemTouchCallbacks extends ItemTouchHelper.SimpleCall
// Keep track of deletions by swiping within history
MetricsLogger.histogram(mContext, "overview_task_dismissed_source",
Constants.Metrics.DismissSourceHistorySwipeGesture);
+ MetricsLogger.action(mContext, MetricsEvent.OVERVIEW_DISMISS,
+ taskRow.task.key.getComponent().toString());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 843adc15c54a..3c4adb23e77a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -186,6 +186,7 @@ public class RecentsHistoryView extends LinearLayout
mRecyclerView = (RecyclerView) findViewById(R.id.list);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ mRecyclerView.getItemAnimator().setRemoveDuration(100);
ItemTouchHelper touchHelper = new ItemTouchHelper(mItemTouchHandler);
touchHelper.attachToRecyclerView(mRecyclerView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 244c0df30da4..95aa10f4876e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.misc;
import android.os.Handler;
+import android.view.ViewDebug;
/**
* A dozer is a class that fires a trigger after it falls asleep.
@@ -26,8 +27,11 @@ public class DozeTrigger {
Handler mHandler;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mIsDozing;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mHasTriggered;
+ @ViewDebug.ExportedProperty(category="recents")
int mDozeDurationMilliseconds;
Runnable mOnSleepRunnable;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 22ab79430cd2..4b29c2986e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -112,6 +112,8 @@ public class SystemServicesProxy {
Display mDisplay;
String mRecentsPackage;
ComponentName mAssistComponent;
+
+ boolean mIsSafeMode;
boolean mHasFreeformWorkspaceSupport;
Bitmap mDummyIcon;
@@ -137,6 +139,7 @@ public class SystemServicesProxy {
mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+ mIsSafeMode = mPm.isSafeMode();
// Get the dummy thumbnail width/heights
Resources res = context.getResources();
@@ -187,7 +190,8 @@ public class SystemServicesProxy {
rti.firstActiveTime = rti.lastActiveTime = i;
if (i % 2 == 0) {
rti.taskDescription = new ActivityManager.TaskDescription(description,
- Bitmap.createBitmap(mDummyIcon),
+ Bitmap.createBitmap(mDummyIcon), null,
+ 0xFF000000 | (0xFFFFFF & new Random().nextInt()),
0xFF000000 | (0xFFFFFF & new Random().nextInt()));
} else {
rti.taskDescription = new ActivityManager.TaskDescription();
@@ -260,6 +264,13 @@ public class SystemServicesProxy {
return mHasFreeformWorkspaceSupport;
}
+ /**
+ * Returns whether this device is in the safe mode.
+ */
+ public boolean isInSafeMode() {
+ return mIsSafeMode;
+ }
+
/** Returns whether the recents is currently running */
public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
MutableBoolean isHomeTopMost) {
@@ -987,20 +998,4 @@ public class SystemServicesProxy {
e.printStackTrace();
}
}
-
- public void focusPinnedStack() {
- try {
- mIam.setFocusedStack(PINNED_STACK_ID);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- public void focusHomeStack() {
- try {
- mIam.setFocusedStack(HOME_STACK_ID);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 4deea542610a..72b1cab5af22 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -17,6 +17,8 @@
package com.android.systemui.recents.misc;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.annotation.FloatRange;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -30,6 +32,7 @@ import android.view.ViewParent;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskViewTransform;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -62,6 +65,8 @@ public class Utilities {
}
};
+ public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
+
/**
* @return the first parent walking up the view hierarchy that has the given class type.
*
@@ -100,6 +105,46 @@ public class Utilities {
return setOut;
}
+ /**
+ * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+ */
+ public static float clamp(float value, float min, float max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ /**
+ * @return the clamped {@param value} between the provided {@param min} and {@param max}.
+ */
+ public static int clamp(int value, int min, int max) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ /**
+ * @return the clamped {@param value} between 0 and 1.
+ */
+ public static float clamp01(float value) {
+ return Math.max(0f, Math.min(1f, value));
+ }
+
+ /**
+ * Scales the {@param value} to be proportionally between the {@param min} and
+ * {@param max} values.
+ *
+ * @param value must be between 0 and 1
+ */
+ public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) {
+ return min + (value * (max - min));
+ }
+
+ /**
+ * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1.
+ *
+ * @param value must be between {@param min} and {@param max}
+ */
+ public static float unmapRange(float value, float min, float max) {
+ return (value - min) / (max - min);
+ }
+
/** Scales a rect about its centroid */
public static void scaleRectAboutCenter(RectF r, float scale) {
if (scale != 1.0f) {
@@ -151,13 +196,26 @@ public class Utilities {
* are not called.
*/
public static void cancelAnimationWithoutCallbacks(Animator animator) {
- if (animator != null) {
- animator.removeAllListeners();
+ if (animator != null && animator.isStarted()) {
+ removeAnimationListenersRecursive(animator);
animator.cancel();
}
}
/**
+ * Recursively removes all the listeners of all children of this animator
+ */
+ public static void removeAnimationListenersRecursive(Animator animator) {
+ if (animator instanceof AnimatorSet) {
+ ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations();
+ for (int i = animators.size() - 1; i >= 0; i--) {
+ removeAnimationListenersRecursive(animators.get(i));
+ }
+ }
+ animator.removeAllListeners();
+ }
+
+ /**
* Updates {@param transforms} to be the same size as {@param tasks}.
*/
public static void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
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 c51aa7ce38c9..6fef8a24fff3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -18,6 +18,8 @@ package com.android.systemui.recents.model;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -179,6 +181,7 @@ public class RecentsTaskLoadPlan {
}
// Load the title, icon, and color
+ ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
String dismissDescription = dismissDescFormatter.format(dismissDescFormat,
@@ -188,11 +191,15 @@ public class RecentsTaskLoadPlan {
: null;
Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false);
int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
+ int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
+ boolean isSystemApp = (info != null) &&
+ ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, contentDescription, dismissDescription, activityColor,
- !isStackTask, isLaunchTarget, t.bounds, t.taskDescription);
+ backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.isDockable,
+ t.bounds, t.taskDescription);
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 26130abc138b..5e1af1280400 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -264,13 +264,16 @@ public class RecentsTaskLoader {
private int mNumVisibleThumbnailsLoaded;
int mDefaultTaskBarBackgroundColor;
+ int mDefaultTaskViewBackgroundColor;
BitmapDrawable mDefaultIcon;
Bitmap mDefaultThumbnail;
public RecentsTaskLoader(Context context) {
Resources res = context.getResources();
mDefaultTaskBarBackgroundColor =
- res.getColor(R.color.recents_task_bar_default_background_color);
+ context.getColor(R.color.recents_task_bar_default_background_color);
+ mDefaultTaskViewBackgroundColor =
+ context.getColor(R.color.recents_task_view_default_background_color);
mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count);
mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count);
int iconCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 :
@@ -556,10 +559,20 @@ public class RecentsTaskLoader {
}
/**
+ * Returns the task's background color if possible.
+ */
+ int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+ if (td != null && td.getBackgroundColor() != 0) {
+ return td.getBackgroundColor();
+ }
+ return mDefaultTaskViewBackgroundColor;
+ }
+
+ /**
* Returns the activity info for the given task key, retrieving one from the system if the
* task key is expired.
*/
- private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+ ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
SystemServicesProxy ssp = Recents.getSystemServices();
ComponentName cn = taskKey.getComponent();
ActivityInfo activityInfo = mActivityInfoCache.get(cn);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 1c277d5a3d92..e5d4f1bf50bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -23,6 +23,7 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.view.ViewDebug;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -48,11 +49,17 @@ public class Task {
/* The Task Key represents the unique primary key for the task */
public static class TaskKey {
+ @ViewDebug.ExportedProperty(category="recents")
public final int id;
+ @ViewDebug.ExportedProperty(category="recents")
public int stackId;
+ @ViewDebug.ExportedProperty(category="recents")
public final Intent baseIntent;
+ @ViewDebug.ExportedProperty(category="recents")
public final int userId;
+ @ViewDebug.ExportedProperty(category="recents")
public long firstActiveTime;
+ @ViewDebug.ExportedProperty(category="recents")
public long lastActiveTime;
private int mHashCode;
@@ -105,17 +112,21 @@ public class Task {
}
}
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
public TaskKey key;
/**
* The group will be computed separately from the initialization of the task
*/
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="group_")
public TaskGrouping group;
/**
* The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
* with any task.
*/
+ @ViewDebug.ExportedProperty(category="recents")
public int affiliationTaskId;
+ @ViewDebug.ExportedProperty(category="recents")
public int affiliationColor;
/**
@@ -124,15 +135,23 @@ public class Task {
*/
public Drawable icon;
public Bitmap thumbnail;
+ @ViewDebug.ExportedProperty(category="recents")
public String title;
+ @ViewDebug.ExportedProperty(category="recents")
public String contentDescription;
+ @ViewDebug.ExportedProperty(category="recents")
public String dismissDescription;
+ @ViewDebug.ExportedProperty(category="recents")
public int colorPrimary;
+ @ViewDebug.ExportedProperty(category="recents")
+ public int colorBackground;
+ @ViewDebug.ExportedProperty(category="recents")
public boolean useLightOnPrimaryColor;
/**
* The bounds of the task, used only if it is a freeform task.
*/
+ @ViewDebug.ExportedProperty(category="recents")
public Rect bounds;
/**
@@ -143,8 +162,14 @@ public class Task {
/**
* The state isLaunchTarget will be set for the correct task upon launching Recents.
*/
+ @ViewDebug.ExportedProperty(category="recents")
public boolean isLaunchTarget;
+ @ViewDebug.ExportedProperty(category="recents")
public boolean isHistorical;
+ @ViewDebug.ExportedProperty(category="recents")
+ public boolean isSystemApp;
+ @ViewDebug.ExportedProperty(category="recents")
+ public boolean isDockable;
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
@@ -154,9 +179,9 @@ public class Task {
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
Bitmap thumbnail, String title, String contentDescription,
- String dismissDescription, int colorPrimary, boolean isHistorical,
- boolean isLaunchTarget, Rect bounds,
- ActivityManager.TaskDescription taskDescription) {
+ String dismissDescription, int colorPrimary, int colorBackground,
+ boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp,
+ boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
this.key = key;
@@ -168,12 +193,15 @@ public class Task {
this.contentDescription = contentDescription;
this.dismissDescription = dismissDescription;
this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
+ this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
Color.WHITE) > 3f;
this.bounds = bounds;
this.taskDescription = taskDescription;
this.isLaunchTarget = isLaunchTarget;
this.isHistorical = isHistorical;
+ this.isSystemApp = isSystemApp;
+ this.isDockable = isDockable;
}
/** Copies the other task. */
@@ -188,10 +216,13 @@ public class Task {
this.contentDescription = o.contentDescription;
this.dismissDescription = o.dismissDescription;
this.colorPrimary = o.colorPrimary;
+ this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
this.bounds = o.bounds;
this.isLaunchTarget = o.isLaunchTarget;
this.isHistorical = o.isHistorical;
+ this.isSystemApp = o.isSystemApp;
+ this.isDockable = o.isDockable;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
index 67a6a9f1d514..d433b6c00269 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
@@ -96,6 +96,6 @@ public class TaskKeyLruCache<V> {
/** Trims the cache to a specific size */
final void trimToSize(int cacheSize) {
- mCache.resize(cacheSize);
+ mCache.trimToSize(cacheSize);
}
}
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 42ebfa95c662..0c48cf748316 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -18,6 +18,7 @@ package com.android.systemui.recents.tv;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
@@ -25,6 +26,7 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowManager;
+import android.widget.FrameLayout.LayoutParams;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -58,6 +60,7 @@ import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.tv.pip.PipManager;
import java.util.ArrayList;
+
/**
* The main TV recents activity started by the RecentsImpl.
*/
@@ -73,9 +76,31 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
private boolean mIgnoreAltTabRelease;
private RecentsTvView mRecentsView;
+ private View mPipView;
+ private View mPipShadeView;
private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+ private PipManager mPipManager;
+ private PipManager.Listener mPipListener = new PipManager.Listener() {
+ @Override
+ public void onPipActivityClosed() {
+ mPipView.setVisibility(View.GONE);
+ mPipShadeView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onShowPipMenu() { }
+
+ @Override
+ public void onMoveToFullscreen() { }
+
+ @Override
+ public void onPipResizeAboutToStart() { }
+
+ @Override
+ public void onMediaControllerChanged() { }
+ };
/**
* A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -212,6 +237,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
finish();
return;
}
+ mPipManager = PipManager.getInstance();
// Register this activity with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -226,7 +252,8 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-
+ mPipView = findViewById(R.id.pip);
+ mPipShadeView = findViewById(R.id.pip_shade);
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -265,6 +292,38 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
// Notify that recents is now visible
SystemServicesProxy ssp = Recents.getSystemServices();
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+
+ if (mPipManager.isPipShown()) {
+ // Place mPipView at the PIP bounds for fine tuned focus handling.
+ Rect pipBounds = mPipManager.getPipBounds();
+ LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
+ lp.width = pipBounds.width();
+ lp.height = pipBounds.height();
+ lp.leftMargin = pipBounds.left;
+ lp.topMargin = pipBounds.top;
+ mPipView.setLayoutParams(lp);
+
+ mPipView.setVisibility(View.VISIBLE);
+ mPipView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPipManager.resizePinnedStack(PipManager.STATE_PIP_MENU);
+ }
+ });
+ mPipView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPipManager.onPipViewFocusChangedInRecents(hasFocus);
+ mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+ mPipManager.addListener(mPipListener);
+ } else {
+ mPipView.setVisibility(View.GONE);
+ }
+ mPipManager.onRecentsStarted();
+ // Give focus to the recents row whenever its visible to an user.
+ mRecentsView.requestFocus();
}
@Override
@@ -277,6 +336,8 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
protected void onStop() {
super.onStop();
+ mPipManager.onRecentsStopped();
+ mPipManager.removeListener(mPipListener);
mIgnoreAltTabRelease = false;
// Notify that recents is now hidden
SystemServicesProxy ssp = Recents.getSystemServices();
@@ -316,18 +377,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_UP: {
- SystemServicesProxy ssp = Recents.getSystemServices();
- PipManager.getInstance().showPipMenu();
- ssp.focusPinnedStack();
- return true;
- }
- case KeyEvent.KEYCODE_DPAD_DOWN: {
- SystemServicesProxy ssp = Recents.getSystemServices();
- PipManager.getInstance().showPipOverlay(false);
- ssp.focusHomeStack();
- return true;
- }
case KeyEvent.KEYCODE_DEL:
case KeyEvent.KEYCODE_FORWARD_DEL: {
EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index 8028327efe2e..48a1904c03b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -47,7 +47,7 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
mTargetView.setOnFocusChangeListener(this);
TypedValue out = new TypedValue();
- res.getValue(R.raw.unselected_scale, out, true);
+ res.getValue(R.integer.unselected_scale, out, true);
mUnselectedScale = out.getFloat();
mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
mUnselectedScale;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index b175855c0d3d..8e768a27f7d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -200,19 +200,6 @@ public class RecentsTvView extends FrameLayout {
EventBus.getDefault().unregister(this);
}
- /**
- * This is called with the full size of the window since we are handling our own insets.
- */
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (mTaskStackHorizontalView != null && mTaskStackHorizontalView.getVisibility() != GONE) {
- mTaskStackHorizontalView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
- }
-
- // Layout the empty view
- mEmptyView.layout(left, top, right, bottom);
- }
-
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mSystemInsets.set(insets.getSystemWindowInsets());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
index 7b62f4e41079..f154331c4878 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -65,7 +65,7 @@ public class TaskStackHorizontalViewAdapter extends
}
public TaskStackHorizontalViewAdapter(List tasks) {
- mTaskList = new ArrayList<>(tasks);
+ mTaskList = new ArrayList<Task>(tasks);
}
public void setNewStackTasks(List tasks) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 584209510e45..253d06a5f5f8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -19,18 +19,28 @@ package com.android.systemui.recents.views;
import android.graphics.Outline;
import android.graphics.Rect;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
+import com.android.systemui.recents.misc.Utilities;
+
/* An outline provider that has a clip and outline that can be animated. */
public class AnimateableViewBounds extends ViewOutlineProvider {
+ private static final float MIN_ALPHA = 0.1f;
+ private static final float MAX_ALPHA = 0.8f;
+
View mSourceView;
+ @ViewDebug.ExportedProperty(category="recents")
Rect mClipRect = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mClipBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mLastClipBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
int mCornerRadius;
+ @ViewDebug.ExportedProperty(category="recents")
float mAlpha = 1f;
- final float mMinAlpha = 0.25f;
public AnimateableViewBounds(View source, int cornerRadius) {
mSourceView = source;
@@ -47,7 +57,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
@Override
public void getOutline(View view, Outline outline) {
- outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
+ outline.setAlpha(Utilities.mapRange(mAlpha, MIN_ALPHA, MAX_ALPHA));
if (mCornerRadius > 0) {
outline.setRoundRect(mClipRect.left, mClipRect.top,
mSourceView.getWidth() - mClipRect.right,
@@ -60,7 +70,9 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
}
}
- /** Sets the view outline alpha. */
+ /**
+ * Sets the view outline alpha.
+ */
void setAlpha(float alpha) {
if (Float.compare(alpha, mAlpha) != 0) {
mAlpha = alpha;
@@ -69,6 +81,13 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
}
}
+ /**
+ * @return the outline alpha.
+ */
+ public float getAlpha() {
+ return mAlpha;
+ }
+
/** Sets the top clip. */
public void setClipTop(int top) {
mClipRect.top = top;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
index 93878c52d6de..48e137028a7f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
@@ -49,6 +49,8 @@ public class AnimationProps {
public static final int ALPHA = 4;
public static final int SCALE = 5;
public static final int BOUNDS = 6;
+ public static final int DIM_ALPHA = 7;
+ public static final int FOCUS_STATE = 8;
private SparseLongArray mPropStartDelay;
private SparseLongArray mPropDuration;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 511aa3c9c001..43591013868a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -152,10 +152,11 @@ public class FreeformWorkspaceLayoutAlgorithm {
transformOut.scale = 1f;
transformOut.alpha = 1f;
transformOut.translationZ = stackLayout.mMaxTranslationZ;
+ transformOut.dimAlpha = 0f;
+ transformOut.viewOutlineAlpha = TaskStackLayoutAlgorithm.OUTLINE_ALPHA_MAX_VALUE;
transformOut.rect.set(ffRect);
transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
transformOut.visible = true;
- transformOut.p = 1f;
return transformOut;
}
return null;
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 6c1ff9b32a58..37b2859de411 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -49,6 +49,7 @@ import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
import java.util.List;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
@@ -99,8 +100,7 @@ public class RecentsTransitionHelper {
final ActivityOptions.OnAnimationStartedListener animStartedListener;
final IAppTransitionAnimationSpecsFuture transitionFuture;
- if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
- task.thumbnail.getHeight() > 0) {
+ if (taskView != null) {
transitionFuture = getAppTransitionFuture(task, stackView, destinationStack);
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@Override
@@ -266,7 +266,11 @@ public class RecentsTransitionHelper {
// If this is a full screen stack, the transition will be towards the single, full screen
// task. We only need the transition spec for this task.
List<AppTransitionAnimationSpec> specs = new ArrayList<>();
- if (targetStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+
+ // TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
+ // check for INVALID_STACK_ID
+ if (targetStackId == FULLSCREEN_WORKSPACE_STACK_ID || targetStackId == DOCKED_STACK_ID
+ || targetStackId == INVALID_STACK_ID) {
if (taskView == null) {
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index d4624f58f09c..5dde92698f78 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,6 +16,8 @@
package com.android.systemui.recents.views;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -32,6 +34,7 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
@@ -79,8 +82,6 @@ import com.android.systemui.statusbar.FlingAnimationUtils;
import java.util.ArrayList;
import java.util.List;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
/**
* This view is the the top level layout that contains TaskStacks (which are laid out according
* to their SpaceNode bounds.
@@ -103,6 +104,8 @@ public class RecentsView extends FrameLayout {
private boolean mAwaitingFirstLayout = true;
private boolean mLastTaskLaunchedWasFreeform;
+
+ @ViewDebug.ExportedProperty(category="recents")
private Rect mSystemInsets = new Rect();
private int mDividerSize;
@@ -110,6 +113,7 @@ public class RecentsView extends FrameLayout {
private Animator mBackgroundScrimAnimator;
private RecentsTransitionHelper mTransitionHelper;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
private RecentsViewTouchHandler mTouchHandler;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -139,21 +143,24 @@ public class RecentsView extends FrameLayout {
final float cornerRadius = context.getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
LayoutInflater inflater = LayoutInflater.from(context);
- mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
- mHistoryButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- EventBus.getDefault().send(new ToggleHistoryEvent());
- }
- });
- addView(mHistoryButton);
- mHistoryButton.setClipToOutline(true);
- mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
- }
- });
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this,
+ false);
+ mHistoryButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ EventBus.getDefault().send(new ToggleHistoryEvent());
+ }
+ });
+ addView(mHistoryButton);
+ mHistoryButton.setClipToOutline(true);
+ mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
+ }
+ });
+ }
mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
addView(mEmptyView);
@@ -248,13 +255,18 @@ public class RecentsView extends FrameLayout {
}
/** Launches the focused task from the first stack if possible */
- public boolean launchFocusedTask() {
+ public boolean launchFocusedTask(int logEvent) {
if (mTaskStackView != null) {
Task task = mTaskStackView.getFocusedTask();
if (task != null) {
TaskView taskView = mTaskStackView.getChildViewForTask(task);
EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
INVALID_STACK_ID, false));
+
+ if (logEvent != 0) {
+ MetricsLogger.action(getContext(), logEvent,
+ task.key.getComponent().toString());
+ }
return true;
}
}
@@ -322,7 +334,9 @@ public class RecentsView extends FrameLayout {
mTaskStackView.setVisibility(View.INVISIBLE);
mEmptyView.setVisibility(View.VISIBLE);
mEmptyView.bringToFront();
- mHistoryButton.bringToFront();
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ mHistoryButton.bringToFront();
+ }
}
/**
@@ -338,7 +352,9 @@ public class RecentsView extends FrameLayout {
if (mSearchBar != null) {
mSearchBar.bringToFront();
}
- mHistoryButton.bringToFront();
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ mHistoryButton.bringToFront();
+ }
}
@Override
@@ -388,21 +404,23 @@ public class RecentsView extends FrameLayout {
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
- // Measure the history view
- if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
- measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- }
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ // Measure the history view
+ if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+ measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
- // Measure the history button within the constraints of the space above the stack
- Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- measureChild(mHistoryButton,
- MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
- if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
- measureChild(mHistoryClearAllButton,
+ // Measure the history button within the constraints of the space above the stack
+ Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
+ measureChild(mHistoryButton,
+ MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+ if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+ measureChild(mHistoryClearAllButton,
MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+ }
}
setMeasuredDimension(width, height);
@@ -434,36 +452,39 @@ public class RecentsView extends FrameLayout {
mEmptyView.layout(left, top, right, bottom);
}
- // Layout the history view
- if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
- mHistoryView.layout(left, top, right, bottom);
- }
-
- // Layout the history button such that its drawable is start-aligned with the stack,
- // vertically centered in the available space above the stack
- Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- int historyLeft = isLayoutRtl()
- ? historyButtonRect.right + mHistoryButton.getPaddingStart()
- - mHistoryButton.getMeasuredWidth()
- : historyButtonRect.left - mHistoryButton.getPaddingStart();
- int historyTop = historyButtonRect.top +
- (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
- mHistoryButton.layout(historyLeft, historyTop,
- historyLeft + mHistoryButton.getMeasuredWidth(),
- historyTop + mHistoryButton.getMeasuredHeight());
-
- // Layout the history clear all button such that it is end-aligned with the stack,
- // vertically centered in the available space above the stack
- if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
- int clearAllLeft = isLayoutRtl()
- ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
- : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
- - mHistoryClearAllButton.getMeasuredWidth();
- int clearAllTop = historyButtonRect.top +
- (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) / 2;
- mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
- clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
- clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ // Layout the history view
+ if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+ mHistoryView.layout(left, top, right, bottom);
+ }
+
+ // Layout the history button such that its drawable is start-aligned with the stack,
+ // vertically centered in the available space above the stack
+ Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
+ int historyLeft = isLayoutRtl()
+ ? historyButtonRect.right + mHistoryButton.getPaddingStart()
+ - mHistoryButton.getMeasuredWidth()
+ : historyButtonRect.left - mHistoryButton.getPaddingStart();
+ int historyTop = historyButtonRect.top +
+ (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
+ mHistoryButton.layout(historyLeft, historyTop,
+ historyLeft + mHistoryButton.getMeasuredWidth(),
+ historyTop + mHistoryButton.getMeasuredHeight());
+
+ // Layout the history clear all button such that it is end-aligned with the stack,
+ // vertically centered in the available space above the stack
+ if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+ int clearAllLeft = isLayoutRtl()
+ ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
+ : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
+ - mHistoryClearAllButton.getMeasuredWidth();
+ int clearAllTop = historyButtonRect.top +
+ (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) /
+ 2;
+ mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
+ clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
+ clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+ }
}
if (mAwaitingFirstLayout) {
@@ -531,9 +552,11 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
- // Hide the history button
int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
- hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ // Hide the history button
+ hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+ }
animateBackgroundScrim(0f, taskViewExitToHomeDuration);
}
@@ -640,8 +663,10 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(TaskStackUpdatedEvent event) {
- mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
- mStack.createAffiliatedGroupings(getContext());
+ if (!event.inMultiWindow) {
+ mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+ mStack.createAffiliatedGroupings(getContext());
+ }
}
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
@@ -666,11 +691,17 @@ public class RecentsView extends FrameLayout {
// Reset the view state
mAwaitingFirstLayout = true;
mLastTaskLaunchedWasFreeform = false;
- hideHistoryButton(0, false /* translate */);
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ hideHistoryButton(0, false /* translate */);
+ }
}
}
public final void onBusEvent(ToggleHistoryEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
if (mHistoryView != null && mHistoryView.isVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
} else {
@@ -679,6 +710,10 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(ShowHistoryEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
if (mHistoryView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
@@ -737,6 +772,10 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(HideHistoryEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
// Animate the empty view in parallel with the history view (the task view animations are
// handled in TaskStackView)
Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
@@ -756,10 +795,18 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(ShowHistoryButtonEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
showHistoryButton(150, event.translate);
}
public final void onBusEvent(HideHistoryButtonEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
hideHistoryButton(100, true /* translate */);
}
@@ -767,6 +814,10 @@ public class RecentsView extends FrameLayout {
* Shows the history button.
*/
private void showHistoryButton(final int duration, final boolean translate) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
if (mHistoryButton.getVisibility() == View.INVISIBLE) {
mHistoryButton.setVisibility(View.VISIBLE);
@@ -799,6 +850,10 @@ public class RecentsView extends FrameLayout {
* Hides the history button.
*/
private void hideHistoryButton(int duration, boolean translate) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
hideHistoryButton(duration, translate, postAnimationTrigger);
postAnimationTrigger.flushLastDecrementRunnables();
@@ -809,6 +864,10 @@ public class RecentsView extends FrameLayout {
*/
private void hideHistoryButton(int duration, boolean translate,
final ReferenceCountedTrigger postAnimationTrigger) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
if (mHistoryButton.getVisibility() == View.VISIBLE) {
if (translate) {
mHistoryButton.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 346ce167cd17..079d7b9148f0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -20,7 +20,10 @@ import android.content.res.Configuration;
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
+import android.widget.Toast;
+import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
@@ -61,12 +64,18 @@ public class RecentsViewTouchHandler {
private RecentsView mRv;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="drag_task")
private Task mDragTask;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="drag_task_view_")
private TaskView mTaskView;
+ @ViewDebug.ExportedProperty(category="recents")
private Point mTaskViewOffset = new Point();
+ @ViewDebug.ExportedProperty(category="recents")
private Point mDownPos = new Point();
+ @ViewDebug.ExportedProperty(category="recents")
private boolean mDragRequested;
+ @ViewDebug.ExportedProperty(category="recents")
private boolean mIsDragging;
private float mDragSlop;
@@ -141,11 +150,16 @@ public class RecentsViewTouchHandler {
mVisibleDockStates.clear();
if (!ssp.hasDockedTask() && mRv.getTaskStack().getTaskCount() > 1) {
- // Add the dock state drop targets (these take priority)
- TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
- for (TaskStack.DockState dockState : dockStates) {
- registerDropTargetForCurrentDrag(dockState);
- mVisibleDockStates.add(dockState);
+ if (!event.task.isDockable) {
+ Toast.makeText(mRv.getContext(), R.string.recents_drag_non_dockable_task_message,
+ Toast.LENGTH_SHORT).show();
+ } else {
+ // Add the dock state drop targets (these take priority)
+ TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
+ for (TaskStack.DockState dockState : dockStates) {
+ registerDropTargetForCurrentDrag(dockState);
+ mVisibleDockStates.add(dockState);
+ }
}
}
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 7eaa1930f6a6..2cd0c19a4352 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -23,6 +23,7 @@ import android.content.res.Resources;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.View;
+import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.systemui.Interpolators;
@@ -34,6 +35,7 @@ import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -81,9 +83,18 @@ public class TaskStackAnimationHelper {
private static final PathInterpolator EXIT_TO_HOME_ALPHA_INTERPOLATOR =
new PathInterpolator(0.4f, 0, 1f, 1f);
+ private static final PathInterpolator FOCUS_NEXT_TASK_INTERPOLATOR =
+ new PathInterpolator(0.4f, 0, 0, 1f);
+ private static final PathInterpolator FOCUS_IN_FRONT_NEXT_TASK_INTERPOLATOR =
+ new PathInterpolator(0, 0, 0, 1f);
+ private static final PathInterpolator FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR =
+ new PathInterpolator(0.4f, 0, 0.2f, 1f);
+
private TaskStackView mStackView;
private TaskViewTransform mTmpTransform = new TaskViewTransform();
+ private ArrayList<TaskViewTransform> mTmpCurrentTaskTransforms = new ArrayList<>();
+ private ArrayList<TaskViewTransform> mTmpFinalTaskTransforms = new ArrayList<>();
public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
mStackView = stackView;
@@ -418,4 +429,95 @@ public class TaskStackAnimationHelper {
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
}
}
+
+ /**
+ * Starts the animation to focus the next {@link TaskView} when paging through recents.
+ *
+ * @return whether or not this will trigger a scroll in the stack
+ */
+ public boolean startScrollToFocusedTaskAnimation(Task newFocusedTask,
+ boolean requestViewFocus) {
+ TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
+ TaskStackViewScroller stackScroller = mStackView.getScroller();
+ TaskStack stack = mStackView.getStack();
+
+ final float newScroll = stackLayout.getStackScrollForTask(newFocusedTask);
+ boolean willScrollToFront = newScroll > stackScroller.getStackScroll();
+ boolean willScroll = Float.compare(newScroll, stackScroller.getStackScroll()) != 0;
+
+ // Get the current set of task transforms
+ ArrayList<Task> stackTasks = stack.getStackTasks();
+ mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
+
+ // Pick up the newly visible views after the scroll
+ mStackView.bindVisibleTaskViews(newScroll);
+
+ // Update the internal state
+ stackLayout.setFocusState(TaskStackLayoutAlgorithm.STATE_FOCUSED);
+ stackScroller.setStackScroll(newScroll, null /* animation */);
+ mStackView.cancelDeferredTaskViewLayoutAnimation();
+
+ // Get the final set of task transforms
+ mStackView.getLayoutTaskTransforms(newScroll, stackLayout.getFocusState(), stackTasks,
+ mTmpFinalTaskTransforms);
+
+ // Focus the task view
+ TaskView newFocusedTaskView = mStackView.getChildViewForTask(newFocusedTask);
+ newFocusedTaskView.setFocusedState(true, requestViewFocus);
+
+ // Setup the end listener to return all the hidden views to the view pool after the
+ // focus animation
+ ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
+ postAnimTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ mStackView.bindVisibleTaskViews(newScroll);
+ }
+ });
+
+ List<TaskView> taskViews = mStackView.getTaskViews();
+ int taskViewCount = taskViews.size();
+ int newFocusTaskViewIndex = taskViews.indexOf(newFocusedTaskView);
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ Task task = tv.getTask();
+
+ if (mStackView.isIgnoredTask(task)) {
+ continue;
+ }
+
+ int taskIndex = stackTasks.indexOf(task);
+ TaskViewTransform fromTransform = mTmpCurrentTaskTransforms.get(taskIndex);
+ TaskViewTransform toTransform = mTmpFinalTaskTransforms.get(taskIndex);
+
+ // Update the task to the initial state (for the newly picked up tasks)
+ mStackView.updateTaskViewToTransform(tv, fromTransform, AnimationProps.IMMEDIATE);
+
+ int duration;
+ Interpolator interpolator;
+ if (willScrollToFront) {
+ duration = Math.max(100, 100 + ((i - 1) * 50));
+ interpolator = FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR;
+ } else {
+ if (i < newFocusTaskViewIndex) {
+ duration = 150 + ((newFocusTaskViewIndex - i - 1) * 50);
+ interpolator = FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR;
+ } else if (i > newFocusTaskViewIndex) {
+ duration = Math.max(100, 150 - ((i - newFocusTaskViewIndex - 1) * 50));
+ interpolator = FOCUS_IN_FRONT_NEXT_TASK_INTERPOLATOR;
+ } else {
+ duration = 200;
+ interpolator = FOCUS_NEXT_TASK_INTERPOLATOR;
+ }
+ }
+
+ AnimationProps anim = new AnimationProps()
+ .setDuration(AnimationProps.BOUNDS, duration)
+ .setInterpolator(AnimationProps.BOUNDS, interpolator)
+ .setListener(postAnimTrigger.decrementOnAnimationEnd());
+ postAnimTrigger.increment();
+ mStackView.updateTaskViewToTransform(tv, toTransform, anim);
+ }
+ return willScroll;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index bd37c3bfd761..261b6f6ae645 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -16,22 +16,19 @@
package com.android.systemui.recents.views;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Path;
import android.graphics.Rect;
-import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.FloatProperty;
-import android.util.Property;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.ViewDebug;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.FreePathInterpolator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
@@ -103,15 +100,20 @@ class Range {
*/
public class TaskStackLayoutAlgorithm {
- // The scale factor to apply to the user movement in the stack to unfocus it
- private static final float UNFOCUS_MULTIPLIER = 0.8f;
+ // The distribution of view bounds alpha
+ // XXX: This is a hack because you can currently set the max alpha to be > 1f
+ public static final float OUTLINE_ALPHA_MIN_VALUE = 0f;
+ public static final float OUTLINE_ALPHA_MAX_VALUE = 2f;
+
+ // The maximum dim on the tasks
+ private static final float MAX_DIM = 0.25f;
// The various focus states
- public static final float STATE_FOCUSED = 1f;
- public static final float STATE_UNFOCUSED = 0f;
+ public static final int STATE_FOCUSED = 1;
+ public static final int STATE_UNFOCUSED = 0;
public interface TaskStackLayoutAlgorithmCallbacks {
- void onFocusStateChanged(float prevFocusState, float curFocusState);
+ void onFocusStateChanged(int prevFocusState, int curFocusState);
}
/**
@@ -181,24 +183,6 @@ public class TaskStackLayoutAlgorithm {
}
}
- /**
- * A Property wrapper around the <code>focusState</code> functionality handled by the
- * {@link TaskStackLayoutAlgorithm#setFocusState(float)} and
- * {@link TaskStackLayoutAlgorithm#getFocusState()} methods.
- */
- private static final Property<TaskStackLayoutAlgorithm, Float> FOCUS_STATE =
- new FloatProperty<TaskStackLayoutAlgorithm>("focusState") {
- @Override
- public void setValue(TaskStackLayoutAlgorithm object, float value) {
- object.setFocusState(value);
- }
-
- @Override
- public Float get(TaskStackLayoutAlgorithm object) {
- return object.getFocusState();
- }
- };
-
// A report of the visibility state of the stack
public class VisibilityReport {
public int numVisibleTasks;
@@ -216,15 +200,20 @@ public class TaskStackLayoutAlgorithm {
private TaskStackLayoutAlgorithmCallbacks mCb;
// The task bounds (untransformed) for layout. This rect is anchored at mTaskRoot.
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mTaskRect = new Rect();
// The freeform workspace bounds, inset from the top by the search bar, and is a fixed height
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mFreeformRect = new Rect();
// The stack bounds, inset from the top by the search bar, and runs to
// the bottom of the screen
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mStackRect = new Rect();
// This is the current system insets
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mSystemInsets = new Rect();
// This is the bounds of the history button above the stack rect
+ @ViewDebug.ExportedProperty(category="recents")
public Rect mHistoryButtonRect = new Rect();
// The visible ranges when the stack is focused and unfocused
@@ -232,14 +221,19 @@ public class TaskStackLayoutAlgorithm {
private Range mFocusedRange;
// The offset from the top when scrolled to the top of the stack
- private int mFocusedPeekHeight;
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mFocusedTopPeekHeight;
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mFocusedBottomTaskPeekHeight;
// The offset from the top of the stack to the top of the bounds when the stack is scrolled to
// the end
+ @ViewDebug.ExportedProperty(category="recents")
private int mStackTopOffset;
// The offset from the bottom of the stack to the bottom of the bounds when the stack is
// scrolled to the front
+ @ViewDebug.ExportedProperty(category="recents")
private int mStackBottomOffset;
// The paths defining the motion of the tasks when the stack is focused and unfocused
@@ -248,33 +242,47 @@ public class TaskStackLayoutAlgorithm {
private FreePathInterpolator mUnfocusedCurveInterpolator;
private FreePathInterpolator mFocusedCurveInterpolator;
+ // The paths defining the distribution of the dim to apply to tasks in the stack when focused
+ // and unfocused
+ private Path mUnfocusedDimCurve;
+ private Path mFocusedDimCurve;
+ private FreePathInterpolator mUnfocusedDimCurveInterpolator;
+ private FreePathInterpolator mFocusedDimCurveInterpolator;
+
// The state of the stack focus (0..1), which controls the transition of the stack from the
// focused to non-focused state
- private float mFocusState;
-
- // The animator used to reset the focused state
- private ObjectAnimator mFocusStateAnimator;
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mFocusState;
// The smallest scroll progress, at this value, the back most task will be visible
+ @ViewDebug.ExportedProperty(category="recents")
float mMinScrollP;
// The largest scroll progress, at this value, the front most task will be visible above the
// navigation bar
+ @ViewDebug.ExportedProperty(category="recents")
float mMaxScrollP;
// The initial progress that the scroller is set when you first enter recents
+ @ViewDebug.ExportedProperty(category="recents")
float mInitialScrollP;
// The task progress for the front-most task in the stack
+ @ViewDebug.ExportedProperty(category="recents")
float mFrontMostTaskP;
// The last computed task counts
+ @ViewDebug.ExportedProperty(category="recents")
int mNumStackTasks;
+ @ViewDebug.ExportedProperty(category="recents")
int mNumFreeformTasks;
// The min/max z translations
+ @ViewDebug.ExportedProperty(category="recents")
int mMinTranslationZ;
+ @ViewDebug.ExportedProperty(category="recents")
int mMaxTranslationZ;
// Optimization, allows for quick lookup of task -> index
- private ArrayMap<Task.TaskKey, Integer> mTaskIndexMap = new ArrayMap<>();
+ private SparseIntArray mTaskIndexMap = new SparseIntArray();
+ private SparseArray<Float> mTaskIndexOverrideMap = new SparseArray<>();
// The freeform workspace layout
FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
@@ -293,7 +301,10 @@ public class TaskStackLayoutAlgorithm {
mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min),
res.getFloat(R.integer.recents_layout_unfocused_range_max));
mFocusState = getDefaultFocusState();
- mFocusedPeekHeight = res.getDimensionPixelSize(R.dimen.recents_layout_focused_peek_size);
+ mFocusedTopPeekHeight =
+ res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
+ mFocusedBottomTaskPeekHeight =
+ res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_task_peek_size);
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
@@ -304,6 +315,7 @@ public class TaskStackLayoutAlgorithm {
* Resets this layout when the stack view is reset.
*/
public void reset() {
+ mTaskIndexOverrideMap.clear();
setFocusState(getDefaultFocusState());
}
@@ -317,8 +329,8 @@ public class TaskStackLayoutAlgorithm {
/**
* Sets the focused state.
*/
- public void setFocusState(float focusState) {
- float prevFocusState = mFocusState;
+ public void setFocusState(int focusState) {
+ int prevFocusState = mFocusState;
mFocusState = focusState;
updateFrontBackTransforms();
if (mCb != null) {
@@ -329,7 +341,7 @@ public class TaskStackLayoutAlgorithm {
/**
* Gets the focused state.
*/
- public float getFocusState() {
+ public int getFocusState() {
return mFocusState;
}
@@ -347,19 +359,19 @@ public class TaskStackLayoutAlgorithm {
// The freeform height is the visible height (not including system insets) - padding above
// freeform and below stack - gap between the freeform and stack
mState = state;
- mStackTopOffset = mFocusedPeekHeight + heightPadding;
+ mStackTopOffset = mFocusedTopPeekHeight + heightPadding;
mStackBottomOffset = mSystemInsets.bottom + heightPadding;
state.computeRects(mFreeformRect, mStackRect, taskStackBounds, widthPadding, heightPadding,
mStackBottomOffset);
// The history button will take the full un-padded header space above the stack
mHistoryButtonRect.set(mStackRect.left, mStackRect.top - heightPadding,
- mStackRect.right, mStackRect.top + mFocusedPeekHeight);
+ mStackRect.right, mStackRect.top + mFocusedTopPeekHeight);
// Anchor the task rect to the top-center of the non-freeform stack rect
float aspect = (float) (taskStackBounds.width() - mSystemInsets.left - mSystemInsets.right)
/ (taskStackBounds.height() - mSystemInsets.bottom);
int width = mStackRect.width();
- int minHeight = mStackRect.height() - mFocusedPeekHeight - mStackBottomOffset;
+ int minHeight = mStackRect.height() - mFocusedTopPeekHeight - mStackBottomOffset;
int height = (int) Math.min(width / aspect, minHeight);
mTaskRect.set(mStackRect.left, mStackRect.top,
mStackRect.left + width, mStackRect.top + height);
@@ -374,6 +386,11 @@ public class TaskStackLayoutAlgorithm {
mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve);
mFocusedCurve = constructFocusedCurve();
mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve);
+ mUnfocusedDimCurve = constructUnfocusedDimCurve();
+ mUnfocusedDimCurveInterpolator = new FreePathInterpolator(mUnfocusedDimCurve);
+ mFocusedDimCurve = constructFocusedDimCurve();
+ mFocusedDimCurveInterpolator = new FreePathInterpolator(mFocusedDimCurve);
+
updateFrontBackTransforms();
}
@@ -419,7 +436,7 @@ public class TaskStackLayoutAlgorithm {
int taskCount = stackTasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = stackTasks.get(i);
- mTaskIndexMap.put(task.key, i);
+ mTaskIndexMap.put(task.key.id, i);
}
// Calculate the min/max scroll
@@ -434,8 +451,8 @@ public class TaskStackLayoutAlgorithm {
mStackRect.height();
float normX = mUnfocusedCurveInterpolator.getX(bottomOffsetPct);
mMinScrollP = 0;
- mMaxScrollP = Math.max(mMinScrollP,
- (mNumStackTasks - 1) - Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
+ mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
+ Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
}
}
@@ -451,56 +468,72 @@ public class TaskStackLayoutAlgorithm {
mInitialScrollP = mMinScrollP;
} else if (getDefaultFocusState() > 0f) {
if (launchState.launchedFromHome) {
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, launchTaskIndex));
+ mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
} else {
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP,
- launchTaskIndex - 1));
+ mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP,
+ mMaxScrollP);
}
} else {
- float offsetPct = (float) (mTaskRect.height() / 2) / mStackRect.height();
+ float offsetPct = (float) (mTaskRect.height() / 3) / mStackRect.height();
float normX = mUnfocusedCurveInterpolator.getX(offsetPct);
- mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP,
- launchTaskIndex - mUnfocusedRange.getAbsoluteX(normX)));
+ mInitialScrollP = Utilities.clamp(launchTaskIndex -
+ mUnfocusedRange.getAbsoluteX(normX), mMinScrollP, mMaxScrollP);
}
}
}
/**
- * Updates this stack when a scroll happens.
+ * Adds and override task progress for the given task when transitioning from focused to
+ * unfocused state.
*/
- public void updateFocusStateOnScroll(int yMovement) {
- Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator);
- if (mFocusState > STATE_UNFOCUSED) {
- float delta = (float) yMovement / (UNFOCUS_MULTIPLIER * mStackRect.height());
- setFocusState(mFocusState - Math.min(mFocusState, Math.abs(delta)));
+ public void addUnfocusedTaskOverride(Task task, float stackScroll) {
+ if (mFocusState != STATE_UNFOCUSED) {
+ mFocusedRange.offset(stackScroll);
+ mUnfocusedRange.offset(stackScroll);
+ float focusedRangeX = mFocusedRange.getNormalizedX(mTaskIndexMap.get(task.key.id));
+ float focusedY = mFocusedCurveInterpolator.getInterpolation(focusedRangeX);
+ float unfocusedRangeX = mUnfocusedCurveInterpolator.getX(focusedY);
+ float unfocusedTaskProgress = stackScroll + mUnfocusedRange.getAbsoluteX(unfocusedRangeX);
+ if (Float.compare(focusedRangeX, unfocusedRangeX) != 0) {
+ mTaskIndexOverrideMap.put(task.key.id, unfocusedTaskProgress);
+ }
}
}
/**
- * Aniamtes the focused state back to its orginal state.
+ * Updates this stack when a scroll happens.
*/
- public void animateFocusState(float newState) {
- Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator);
- if (Float.compare(newState, getFocusState()) != 0) {
- mFocusStateAnimator = ObjectAnimator.ofFloat(this, FOCUS_STATE, getFocusState(),
- newState);
- mFocusStateAnimator.setDuration(mContext.getResources().getInteger(
- R.integer.recents_animate_task_stack_scroll_duration));
- mFocusStateAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- mFocusStateAnimator.start();
+ public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) {
+ for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) {
+ int taskId = mTaskIndexOverrideMap.keyAt(i);
+ float x = mTaskIndexMap.get(taskId);
+ float overrideX = mTaskIndexOverrideMap.get(taskId, 0f);
+ float newOverrideX = overrideX + deltaScroll;
+ mUnfocusedRange.offset(stackScroll);
+ boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f ||
+ mUnfocusedRange.getNormalizedX(newOverrideX) > 1f;
+ if (outOfBounds || (overrideX >= x && x >= newOverrideX) ||
+ (overrideX <= x && x <= newOverrideX)) {
+ // Remove the override once we reach the original task index
+ mTaskIndexOverrideMap.removeAt(i);
+ } else if ((overrideX >= x && deltaScroll <= 0f) ||
+ (overrideX <= x && deltaScroll >= 0f)) {
+ // Scrolling from override x towards x, then lock the task in place
+ mTaskIndexOverrideMap.put(taskId, newOverrideX);
+ } else {
+ // Scrolling override x away from x, we should still move the scroll towards x
+ float deltaX = overrideX - x;
+ newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - deltaScroll);
+ mTaskIndexOverrideMap.put(taskId, x + newOverrideX);
+ }
}
}
/**
* Returns the default focus state.
*/
- public float getDefaultFocusState() {
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (launchState.launchedWithAltTab || debugFlags.isInitialStatePaging()) {
- return STATE_FOCUSED;
- }
- return STATE_UNFOCUSED;
+ public int getDefaultFocusState() {
+ return STATE_FOCUSED;
}
/**
@@ -567,7 +600,7 @@ public class TaskStackLayoutAlgorithm {
boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
if (isFrontMostTaskInGroup) {
- getStackTransform(taskProgress, mInitialScrollP, tmpTransform, null,
+ getStackTransform(taskProgress, mInitialScrollP, mFocusState, tmpTransform, null,
false /* ignoreSingleTaskCase */, false /* forceUpdate */);
float screenY = tmpTransform.rect.top;
boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
@@ -601,22 +634,23 @@ public class TaskStackLayoutAlgorithm {
*/
public TaskViewTransform getStackTransform(Task task, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform frontTransform) {
- return getStackTransform(task, stackScroll, transformOut, frontTransform,
+ return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
false /* forceUpdate */);
}
- public TaskViewTransform getStackTransform(Task task, float stackScroll,
+ public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState,
TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) {
if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
return transformOut;
} else {
// Return early if we have an invalid index
- if (task == null || !mTaskIndexMap.containsKey(task.key)) {
+ if (task == null || mTaskIndexMap.get(task.key.id, -1) == -1) {
transformOut.reset();
return transformOut;
}
- getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut,
+ float taskProgress = getStackScrollForTask(task);
+ getStackTransform(taskProgress, stackScroll, focusState, transformOut,
frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
return transformOut;
}
@@ -642,27 +676,21 @@ public class TaskStackLayoutAlgorithm {
* internally to ensure that we can calculate the transform for any
* position in the stack.
*/
- public void getStackTransform(float taskProgress, float stackScroll,
+ public void getStackTransform(float taskProgress, float stackScroll, int focusState,
TaskViewTransform transformOut, TaskViewTransform frontTransform,
boolean ignoreSingleTaskCase, boolean forceUpdate) {
SystemServicesProxy ssp = Recents.getSystemServices();
// Compute the focused and unfocused offset
+ float boundedStackScroll = Utilities.clamp(stackScroll, mMinScrollP, mMaxScrollP);
+ mUnfocusedRange.offset(boundedStackScroll);
+ mFocusedRange.offset(boundedStackScroll);
+ float boundedScrollUnfocusedRangeX = mUnfocusedRange.getNormalizedX(taskProgress);
+ float boundedScrollFocusedRangeX = mFocusedRange.getNormalizedX(taskProgress);
mUnfocusedRange.offset(stackScroll);
- float p = mUnfocusedRange.getNormalizedX(taskProgress);
- float yp = mUnfocusedCurveInterpolator.getInterpolation(p);
- float unfocusedP = p;
- int unFocusedY = (int) (Math.max(0f, (1f - yp)) * mStackRect.height());
+ mFocusedRange.offset(stackScroll);
boolean unfocusedVisible = mUnfocusedRange.isInRange(taskProgress);
- int focusedY = 0;
- boolean focusedVisible = true;
- if (mFocusState > 0f) {
- mFocusedRange.offset(stackScroll);
- p = mFocusedRange.getNormalizedX(taskProgress);
- yp = mFocusedCurveInterpolator.getInterpolation(p);
- focusedY = (int) (Math.max(0f, (1f - yp)) * mStackRect.height());
- focusedVisible = mFocusedRange.isInRange(taskProgress);
- }
+ boolean focusedVisible = mFocusedRange.isInRange(taskProgress);
// Skip if the task is not visible
if (!forceUpdate && !unfocusedVisible && !focusedVisible) {
@@ -670,43 +698,56 @@ public class TaskStackLayoutAlgorithm {
return;
}
+ float unfocusedRangeX = mUnfocusedRange.getNormalizedX(taskProgress);
+ float focusedRangeX = mFocusedRange.getNormalizedX(taskProgress);
+
int x = (mStackRect.width() - mTaskRect.width()) / 2;
int y;
float z;
- float relP;
+ float dimAlpha;
+ float viewOutlineAlpha;
if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1 && !ignoreSingleTaskCase) {
// When there is exactly one task, then decouple the task from the stack and just move
// in screen space
- p = (mMinScrollP - stackScroll) / mNumStackTasks;
+ float tmpP = (mMinScrollP - stackScroll) / mNumStackTasks;
int centerYOffset = (mStackRect.top - mTaskRect.top) +
(mStackRect.height() - mTaskRect.height()) / 2;
- y = centerYOffset + getYForDeltaP(p, 0);
+ y = centerYOffset + getYForDeltaP(tmpP, 0);
z = mMaxTranslationZ;
- relP = 1f;
+ dimAlpha = 0f;
+ viewOutlineAlpha = (OUTLINE_ALPHA_MIN_VALUE + OUTLINE_ALPHA_MAX_VALUE) / 2f;
} else {
// Otherwise, update the task to the stack layout
- y = unFocusedY + (int) (mFocusState * (focusedY - unFocusedY));
- y += (mStackRect.top - mTaskRect.top);
- z = Math.max(mMinTranslationZ, Math.min(mMaxTranslationZ,
- mMinTranslationZ + (p * (mMaxTranslationZ - mMinTranslationZ))));
- if (mNumStackTasks == 1) {
- relP = 1f;
- } else {
- relP = Math.min(mMaxScrollP, unfocusedP);
- }
+ int unfocusedY = (int) ((1f - mUnfocusedCurveInterpolator.getInterpolation(
+ unfocusedRangeX)) * mStackRect.height());
+ int focusedY = (int) ((1f - mFocusedCurveInterpolator.getInterpolation(
+ focusedRangeX)) * mStackRect.height());
+ float unfocusedDim = mUnfocusedDimCurveInterpolator.getInterpolation(
+ boundedScrollUnfocusedRangeX);
+ float focusedDim = mFocusedDimCurveInterpolator.getInterpolation(
+ boundedScrollFocusedRangeX);
+
+ y = (mStackRect.top - mTaskRect.top) +
+ (int) Utilities.mapRange(focusState, unfocusedY, focusedY);
+ z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
+ mMinTranslationZ, mMaxTranslationZ);
+ dimAlpha = Utilities.mapRange(focusState, unfocusedDim, focusedDim);
+ viewOutlineAlpha = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
+ OUTLINE_ALPHA_MIN_VALUE, OUTLINE_ALPHA_MAX_VALUE);
}
// Fill out the transform
transformOut.scale = 1f;
transformOut.alpha = 1f;
transformOut.translationZ = z;
+ transformOut.dimAlpha = dimAlpha;
+ transformOut.viewOutlineAlpha = viewOutlineAlpha;
transformOut.rect.set(mTaskRect);
transformOut.rect.offset(x, y);
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
(frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
- transformOut.p = relP;
}
/**
@@ -721,8 +762,7 @@ public class TaskStackLayoutAlgorithm {
* stack.
*/
float getStackScrollForTask(Task t) {
- if (!mTaskIndexMap.containsKey(t.key)) return 0f;
- return mTaskIndexMap.get(t.key);
+ return mTaskIndexOverrideMap.get(t.key.id, (float) mTaskIndexMap.get(t.key.id, 0));
}
/**
@@ -750,18 +790,17 @@ public class TaskStackLayoutAlgorithm {
* Creates a new path for the focused curve.
*/
private Path constructFocusedCurve() {
- int taskBarHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.recents_task_bar_height);
-
// Initialize the focused curve. This curve is a piecewise curve composed of several
- // quadradic beziers that goes from (0,1) through (0.5, peek height offset),
- // (0.667, next task offset), (0.833, bottom task offset), and (1,0).
- float peekHeightPct = (float) mFocusedPeekHeight / mStackRect.height();
+ // linear pieces that goes from (0,1) through (0.5, peek height offset),
+ // (0.5, bottom task offsets), and (1,0).
+ float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
+ float bottomPeekHeightPct = Math.max(
+ mSystemInsets.bottom + mFocusedRange.relativeMax * mFocusedBottomTaskPeekHeight,
+ mStackBottomOffset + mFocusedBottomTaskPeekHeight) / mStackRect.height();
Path p = new Path();
p.moveTo(0f, 1f);
- p.lineTo(0.5f, 1f - peekHeightPct);
- p.lineTo(0.66666667f, (float) (taskBarHeight * 3) / mStackRect.height());
- p.lineTo(0.83333333f, (float) (taskBarHeight / 2) / mStackRect.height());
+ p.lineTo(0.5f, 1f - topPeekHeightPct);
+ p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct);
p.lineTo(1f, 0f);
return p;
}
@@ -778,7 +817,7 @@ public class TaskStackLayoutAlgorithm {
// there is a tangent at (0.5, peek height offset).
float cpoint1X = 0.4f;
float cpoint1Y = 1f;
- float peekHeightPct = (float) mFocusedPeekHeight / mStackRect.height();
+ float peekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
float slope = ((1f - peekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
float b = 1f - slope * cpoint1X;
float cpoint2X = 0.75f;
@@ -791,6 +830,34 @@ public class TaskStackLayoutAlgorithm {
}
/**
+ * Creates a new path for the focused dim curve.
+ */
+ private Path constructFocusedDimCurve() {
+ Path p = new Path();
+ // The focused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
+ // task), then goes back to max dim at the next task
+ p.moveTo(0f, MAX_DIM);
+ p.lineTo(0.5f, 0f);
+ p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), MAX_DIM);
+ p.lineTo(1f, MAX_DIM);
+ return p;
+ }
+
+ /**
+ * Creates a new path for the unfocused dim curve.
+ */
+ private Path constructUnfocusedDimCurve() {
+ Path p = new Path();
+ // The unfocused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
+ // task), then goes back to max dim towards the front of the stack
+ p.moveTo(0f, MAX_DIM);
+ p.cubicTo(0f, 0.1f, 0.4f, 0f, 0.5f, 0f);
+ p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM - 0.1f, 1f, MAX_DIM / 2f);
+ return p;
+ }
+
+
+ /**
* Updates the current transforms that would put a TaskView at the front and back of the stack.
*/
private void updateFrontBackTransforms() {
@@ -799,14 +866,14 @@ public class TaskStackLayoutAlgorithm {
return;
}
- float min = mUnfocusedRange.relativeMin +
- mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
- float max = mUnfocusedRange.relativeMax +
- mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax);
- getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */,
- true /* forceUpdate */);
- getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */,
- true /* forceUpdate */);
+ float min = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMin,
+ mFocusedRange.relativeMin);
+ float max = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMax,
+ mFocusedRange.relativeMax);
+ getStackTransform(min, 0f, mFocusState, mBackOfStackTransform, null,
+ true /* ignoreSingleTaskCase */, true /* forceUpdate */);
+ getStackTransform(max, 0f, mFocusState, mFrontOfStackTransform, null,
+ true /* ignoreSingleTaskCase */, true /* forceUpdate */);
mBackOfStackTransform.visible = true;
mFrontOfStackTransform.visible = true;
}
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 bb74de493f58..e1a81c8c15f2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -35,14 +35,18 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.MutableBoolean;
+import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -113,9 +117,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
+ LayoutInflater mInflater;
TaskStack mStack;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
TaskStackLayoutAlgorithm mLayoutAlgorithm;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
TaskStackViewScroller mStackScroller;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
TaskStackViewTouchHandler mTouchHandler;
TaskStackAnimationHelper mAnimationHelper;
GradientDrawable mFreeformWorkspaceBackground;
@@ -127,31 +135,40 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
AnimationProps mDeferredTaskViewLayoutAnimation = null;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="doze_")
DozeTrigger mUIDozeTrigger;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="focused_task_")
Task mFocusedTask;
int mTaskCornerRadiusPx;
private int mDividerSize;
private int mStartTimerIndicatorDuration;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTaskViewsClipDirty = true;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mAwaitingFirstLayout = true;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mInMeasureLayout = false;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mEnterAnimationComplete = false;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTouchExplorationEnabled;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mScreenPinningEnabled;
// The stable stack bounds are the full bounds that we were measured with from RecentsView
- Rect mStableStackBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
+ private Rect mStableStackBounds = new Rect();
// The current stack bounds are dynamic and may change as the user drags and drops
- Rect mStackBounds = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
+ private Rect mStackBounds = new Rect();
- int[] mTmpVisibleRange = new int[2];
- Rect mTmpRect = new Rect();
- ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
- List<TaskView> mTmpTaskViews = new ArrayList<>();
- TaskViewTransform mTmpTransform = new TaskViewTransform();
- LayoutInflater mInflater;
+ private Rect mTmpRect = new Rect();
+ private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
+ private List<TaskView> mTmpTaskViews = new ArrayList<>();
+ private TaskViewTransform mTmpTransform = new TaskViewTransform();
+ private int[] mTmpIntPair = new int[2];
// A convenience update listener to request updating clipping of tasks
private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
@@ -388,13 +405,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
* target stack scrolls will be returned.
* @param ignoreTasksSet The set of tasks to skip for purposes of calculaing the visible range.
* Transforms will still be calculated for the ignore tasks.
+ * @return the front and back most visible task indices (there may be non visible tasks in
+ * between this range)
*/
- boolean computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
+ int[] computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
- int[] visibleRangeOut, ArraySet<Task.TaskKey> ignoreTasksSet) {
+ ArraySet<Task.TaskKey> ignoreTasksSet) {
int taskCount = tasks.size();
- int frontMostVisibleIndex = -1;
- int backMostVisibleIndex = -1;
+ int[] visibleTaskRange = mTmpIntPair;
+ visibleTaskRange[0] = -1;
+ visibleTaskRange[1] = -1;
boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
// We can reuse the task transforms where possible to reduce object allocation
@@ -434,31 +454,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
continue;
}
+ frontTransform = transform;
+ frontTransformAtTarget = transformAtTarget;
if (transform.visible) {
- if (frontMostVisibleIndex < 0) {
- frontMostVisibleIndex = i;
- }
- backMostVisibleIndex = i;
- } else {
- if (backMostVisibleIndex != -1) {
- // We've reached the end of the visible range, so going down the rest of the
- // stack, we can just reset the transforms accordingly
- while (i >= 0) {
- taskTransforms.get(i).reset();
- i--;
- }
- break;
+ if (visibleTaskRange[0] < 0) {
+ visibleTaskRange[0] = i;
}
+ visibleTaskRange[1] = i;
}
-
- frontTransform = transform;
- frontTransformAtTarget = transformAtTarget;
- }
- if (visibleRangeOut != null) {
- visibleRangeOut[0] = frontMostVisibleIndex;
- visibleRangeOut[1] = backMostVisibleIndex;
}
- return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1;
+ return visibleTaskRange;
}
/**
@@ -484,13 +489,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
* {@link TaskView}s
*/
void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet) {
- final int[] visibleStackRange = mTmpVisibleRange;
-
// Get all the task transforms
- final ArrayList<Task> tasks = mStack.getStackTasks();
- final boolean isValidVisibleRange = computeVisibleTaskTransforms(mCurrentTaskTransforms,
- tasks, mStackScroller.getStackScroll(), targetStackScroll, visibleStackRange,
- ignoreTasksSet);
+ ArrayList<Task> tasks = mStack.getStackTasks();
+ int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
+ mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet);
// Return all the invisible children to the pool
mTmpTaskViewMap.clear();
@@ -501,14 +503,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
int taskIndex = mStack.indexOfStackTask(task);
+ TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
// Skip ignored tasks
if (ignoreTasksSet.contains(task.key)) {
continue;
}
- if (task.isFreeformTask() ||
- visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) {
+ if (task.isFreeformTask() || transform.visible) {
mTmpTaskViewMap.put(task.key, tv);
} else {
if (mTouchExplorationEnabled) {
@@ -520,8 +522,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
// Pick up all the newly visible children
- int lastVisStackIndex = isValidVisibleRange ? visibleStackRange[1] : 0;
- for (int i = tasks.size() - 1; i >= lastVisStackIndex; i--) {
+ for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
TaskViewTransform transform = mCurrentTaskTransforms.get(i);
@@ -531,7 +532,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
// Skip the invisible non-freeform stack tasks
- if (i > visibleStackRange[0] && !task.isFreeformTask()) {
+ if (!task.isFreeformTask() && !transform.visible) {
continue;
}
@@ -542,7 +543,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
tv.updateViewPropertiesToTaskTransform(transform, AnimationProps.IMMEDIATE,
mRequestUpdateClippingListener);
} else {
- if (Float.compare(transform.p, 0f) <= 0) {
+ if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
tv.updateViewPropertiesToTaskTransform(
mLayoutAlgorithm.getBackOfStackTransform(),
AnimationProps.IMMEDIATE, mRequestUpdateClippingListener);
@@ -566,11 +567,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Update the focus if the previous focused task was returned to the view pool
if (lastFocusedTaskIndex != -1) {
- if (lastFocusedTaskIndex < visibleStackRange[1]) {
- setFocusedTask(visibleStackRange[1], false /* scrollToTask */,
+ if (lastFocusedTaskIndex < visibleTaskRange[1]) {
+ setFocusedTask(visibleTaskRange[1], false /* scrollToTask */,
true /* requestViewFocus */);
} else {
- setFocusedTask(visibleStackRange[0], false /* scrollToTask */,
+ setFocusedTask(visibleTaskRange[0], false /* scrollToTask */,
true /* requestViewFocus */);
}
}
@@ -647,6 +648,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public void getCurrentTaskTransforms(ArrayList<Task> tasks,
ArrayList<TaskViewTransform> transformsOut) {
Utilities.matchTaskListSize(tasks, transformsOut);
+ int focusState = mLayoutAlgorithm.getFocusState();
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
TaskViewTransform transform = transformsOut.get(i);
@@ -655,7 +657,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
transform.fillIn(tv);
} else {
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
- transform, null, true /* forceUpdate */);
+ focusState, transform, null, true /* forceUpdate */);
}
transform.visible = true;
}
@@ -663,20 +665,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
/**
* Returns the task transforms for all the tasks in the stack if the stack was at the given
- * {@param stackScroll}.
+ * {@param stackScroll} and {@param focusState}.
*/
- public void getLayoutTaskTransforms(float stackScroll, ArrayList<Task> tasks,
+ public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks,
ArrayList<TaskViewTransform> transformsOut) {
Utilities.matchTaskListSize(tasks, transformsOut);
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
TaskViewTransform transform = transformsOut.get(i);
- mLayoutAlgorithm.getStackTransform(task, stackScroll, transform, null);
+ mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null,
+ true /* forceUpdate */);
transform.visible = true;
}
}
/**
+ * Cancels the next deferred task view layout.
+ */
+ void cancelDeferredTaskViewLayoutAnimation() {
+ mDeferredTaskViewLayoutAnimation = null;
+ }
+
+ /**
* Cancels all {@link TaskView} animations.
*
* @see #cancelAllTaskViewAnimations(ArraySet<Task.TaskKey>)
@@ -716,7 +726,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskView frontTv = null;
int clipBottom = 0;
- if (mIgnoreTasks.contains(tv.getTask().key)) {
+ if (isIgnoredTask(tv.getTask())) {
// For each of the ignore tasks, update the translationZ of its TaskView to be
// between the translationZ of the tasks immediately underneath it
if (prevVisibleTv != null) {
@@ -804,15 +814,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
/**
- * Sets the focused task to the provided (bounded taskIndex).
+ * Sets the focused task to the provided (bounded focusTaskIndex).
*
* @return whether or not the stack will scroll as a part of this focus change
*/
- private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
- final boolean requestViewFocus, final int timerIndicatorDuration) {
+ private boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
+ boolean requestViewFocus, int timerIndicatorDuration) {
// Find the next task to focus
int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
- Math.max(0, Math.min(mStack.getTaskCount() - 1, taskIndex)) : -1;
+ Utilities.clamp(focusTaskIndex, 0, mStack.getTaskCount() - 1) : -1;
final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
mStack.getStackTasks().get(newFocusedTaskIndex) : null;
@@ -830,7 +840,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
boolean willScroll = false;
-
mFocusedTask = newFocusedTask;
if (newFocusedTask != null) {
@@ -845,33 +854,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
}
- Runnable focusTaskRunnable = new Runnable() {
- @Override
- public void run() {
- final TaskView tv = getChildViewForTask(newFocusedTask);
- if (tv != null) {
- tv.setFocusedState(true, requestViewFocus);
- }
- }
- };
-
if (scrollToTask) {
// Cancel any running enter animations at this point when we scroll or change focus
if (!mEnterAnimationComplete) {
cancelAllTaskViewAnimations();
}
- // TODO: Center the newly focused task view, only if not freeform
- float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask);
- if (Float.compare(newScroll, mStackScroller.getStackScroll()) != 0) {
- mStackScroller.animateScroll(newScroll, focusTaskRunnable);
- willScroll = true;
- } else {
- focusTaskRunnable.run();
- }
- mLayoutAlgorithm.animateFocusState(TaskStackLayoutAlgorithm.STATE_FOCUSED);
+ willScroll = mAnimationHelper.startScrollToFocusedTaskAnimation(newFocusedTask,
+ requestViewFocus);
} else {
- focusTaskRunnable.run();
+ // Focus the task view
+ TaskView newFocusedTaskView = getChildViewForTask(newFocusedTask);
+ if (newFocusedTaskView != null) {
+ newFocusedTaskView.setFocusedState(true, requestViewFocus);
+ }
}
}
return willScroll;
@@ -951,10 +947,26 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
newIndex = (newIndex + (forward ? -1 : 1) + taskCount) % taskCount;
}
} else {
- // We don't have a focused task, so focus the first visible task view
- TaskView tv = getFrontMostTaskView(stackTasksOnly);
- if (tv != null) {
- newIndex = mStack.indexOfStackTask(tv.getTask());
+ // We don't have a focused task
+ float stackScroll = mStackScroller.getStackScroll();
+ ArrayList<Task> tasks = mStack.getStackTasks();
+ int taskCount = tasks.size();
+ if (forward) {
+ // Walk backwards and focus the next task smaller than the current stack scroll
+ for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
+ float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
+ if (Float.compare(taskP, stackScroll) <= 0) {
+ break;
+ }
+ }
+ } else {
+ // Walk forwards and focus the next task larger than the current stack scroll
+ for (newIndex = 0; newIndex < taskCount; newIndex++) {
+ float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
+ if (Float.compare(taskP, stackScroll) >= 0) {
+ break;
+ }
+ }
}
}
if (newIndex != -1) {
@@ -1026,7 +1038,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
protected Parcelable onSaveInstanceState() {
Bundle savedState = new Bundle();
savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
- savedState.putFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
+ savedState.putInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
return super.onSaveInstanceState();
}
@@ -1036,7 +1048,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
Bundle savedState = (Bundle) state;
super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
- mLayoutAlgorithm.setFocusState(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
+ mLayoutAlgorithm.setFocusState(savedState.getInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
}
@@ -1276,7 +1288,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
Task task = tasks.get(i);
// Ignore deleting tasks
- if (mIgnoreTasks.contains(task.key)) {
+ if (isIgnoredTask(task)) {
if (i == tasks.size() - 1) {
isFrontMostTask.value = true;
}
@@ -1390,7 +1402,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
@Override
- public void prepareViewToEnterPool(TaskView tv) {
+ public void onReturnViewToPool(TaskView tv) {
final Task task = tv.getTask();
// Report that this tasks's data is no longer being used
@@ -1411,7 +1423,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
@Override
- public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) {
+ public void onPickUpViewFromPool(TaskView tv, Task task, boolean isNewView) {
// Find the index where this task should be placed in the stack
int taskIndex = mStack.indexOfStackTask(task);
int insertIndex = findTaskViewInsertIndex(task, taskIndex);
@@ -1488,7 +1500,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
/**** TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks ****/
@Override
- public void onFocusStateChanged(float prevFocusState, float curFocusState) {
+ public void onFocusStateChanged(int prevFocusState, int curFocusState) {
if (mDeferredTaskViewLayoutAnimation == null) {
mUIDozeTrigger.poke();
relayoutTaskViewsOnNextFrame(AnimationProps.IMMEDIATE);
@@ -1498,11 +1510,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
/**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
@Override
- public void onScrollChanged(float prevScroll, float curScroll, AnimationProps animation) {
+ public void onStackScrollChanged(float prevScroll, float curScroll, AnimationProps animation) {
mUIDozeTrigger.poke();
if (animation != null) {
relayoutTaskViewsOnNextFrame(animation);
}
+ mLayoutAlgorithm.updateFocusStateOnScroll(curScroll, curScroll - prevScroll);
if (mEnterAnimationComplete) {
if (shouldShowHistoryButton() &&
@@ -1560,6 +1573,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+ launchTask.key.getComponent().toString());
}
}
@@ -1601,14 +1617,25 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public final void onBusEvent(TaskViewDismissedEvent event) {
removeTaskViewFromStack(event.taskView, event.task);
EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
+
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
+ event.task.key.getComponent().toString());
}
public final void onBusEvent(FocusNextTaskViewEvent event) {
+ // Stop any scrolling
+ mStackScroller.stopScroller();
+ mStackScroller.stopBoundScrollAnimation();
+
setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false,
event.timerIndicatorDuration);
}
public final void onBusEvent(FocusPreviousTaskViewEvent event) {
+ // Stop any scrolling
+ mStackScroller.stopScroller();
+ mStackScroller.stopBoundScrollAnimation();
+
setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
}
@@ -1739,10 +1766,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
removeIgnoreTask(event.task);
}
- public final void onBusEvent(StackViewScrolledEvent event) {
- mLayoutAlgorithm.updateFocusStateOnScroll(event.yMovement.value);
- }
-
public final void onBusEvent(IterateRecentsEvent event) {
if (!mEnterAnimationComplete) {
// Cancel the previous task's window transition before animating the focused state
@@ -1810,12 +1833,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
public final void onBusEvent(TaskStackUpdatedEvent event) {
- // Scroll the stack to the front after it has been updated
+ if (!event.inMultiWindow) {
+ // Scroll the stack to the front after it has been updated
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
+ null /* postScrollRunnable */);
+ }
+ });
+ }
+ // When the multi-window state changes, rebind all task view headers again to update their
+ // dockable state
event.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
- mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
- null /* postScrollRunnable */);
+ List<TaskView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
+ tv.mIsDisabledInSafeMode);
+ }
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index c641d75c7bc8..333df9dd5b11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
+import android.view.ViewDebug;
import android.widget.OverScroller;
import com.android.systemui.Interpolators;
@@ -38,7 +39,7 @@ public class TaskStackViewScroller {
private static final boolean DEBUG = false;
public interface TaskStackViewScrollerCallbacks {
- void onScrollChanged(float prevScroll, float curScroll, AnimationProps animation);
+ void onStackScrollChanged(float prevScroll, float curScroll, AnimationProps animation);
}
/**
@@ -63,6 +64,7 @@ public class TaskStackViewScroller {
TaskStackLayoutAlgorithm mLayoutAlgorithm;
TaskStackViewScrollerCallbacks mCb;
+ @ViewDebug.ExportedProperty(category="recents")
float mStackScrollP;
float mFlingDownScrollP;
int mFlingDownY;
@@ -104,7 +106,7 @@ public class TaskStackViewScroller {
float prevStackScroll = mStackScrollP;
mStackScrollP = s;
if (mCb != null) {
- mCb.onScrollChanged(prevStackScroll, mStackScrollP, animation);
+ mCb.onStackScrollChanged(prevStackScroll, mStackScrollP, animation);
}
}
@@ -150,8 +152,7 @@ public class TaskStackViewScroller {
/** Returns the bounded stack scroll */
float getBoundedStackScroll(float scroll) {
- return Math.max(mLayoutAlgorithm.mMinScrollP,
- Math.min(mLayoutAlgorithm.mMaxScrollP, scroll));
+ return Utilities.clamp(scroll, mLayoutAlgorithm.mMinScrollP, mLayoutAlgorithm.mMaxScrollP);
}
/** Returns the amount that the absolute value of how much the scroll is out of bounds. */
@@ -191,21 +192,27 @@ public class TaskStackViewScroller {
stopScroller();
stopBoundScrollAnimation();
- mFinalAnimatedScroll = newScroll;
- mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, getStackScroll(), newScroll);
- mScrollAnimator.setDuration(mContext.getResources().getInteger(
- R.integer.recents_animate_task_stack_scroll_duration));
- mScrollAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- mScrollAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (postRunnable != null) {
- postRunnable.run();
+ if (Float.compare(mStackScrollP, newScroll) != 0) {
+ mFinalAnimatedScroll = newScroll;
+ mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, getStackScroll(), newScroll);
+ mScrollAnimator.setDuration(mContext.getResources().getInteger(
+ R.integer.recents_animate_task_stack_scroll_duration));
+ mScrollAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ mScrollAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (postRunnable != null) {
+ postRunnable.run();
+ }
+ mScrollAnimator.removeAllListeners();
}
- mScrollAnimator.removeAllListeners();
+ });
+ mScrollAnimator.start();
+ } else {
+ if (postRunnable != null) {
+ postRunnable.run();
}
- });
- mScrollAnimator.start();
+ }
}
/** Aborts any current stack scrolls */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index d6680fdf23e2..20933ee3cf6f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -28,12 +28,13 @@ import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewDebug;
import android.view.ViewParent;
-import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
@@ -43,7 +44,6 @@ import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
-import com.android.systemui.recents.misc.RectFEvaluator;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -58,8 +58,6 @@ import java.util.List;
class TaskStackViewTouchHandler implements SwipeHelper.Callback {
private static final int INACTIVE_POINTER_ID = -1;
-
- private static final RectFEvaluator RECT_EVALUATOR = new RectFEvaluator();
private static final Interpolator STACK_TRANSFORM_INTERPOLATOR =
new PathInterpolator(0.73f, 0.33f, 0.42f, 0.85f);
@@ -70,6 +68,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
FlingAnimationUtils mFlingAnimUtils;
ValueAnimator mScrollFlingAnimator;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mIsScrolling;
float mDownScrollP;
int mDownX, mDownY;
@@ -224,12 +223,21 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
int xDiff = Math.abs(x - mDownX);
if (Math.abs(y - mDownY) > mScrollTouchSlop && yDiff > xDiff) {
mIsScrolling = true;
+ float stackScroll = mScroller.getStackScroll();
+ List<TaskView> taskViews = mSv.getTaskViews();
+ for (int i = taskViews.size() - 1; i >= 0; i--) {
+ layoutAlgorithm.addUnfocusedTaskOverride(taskViews.get(i).getTask(),
+ stackScroll);
+ }
+ layoutAlgorithm.setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
// Disallow parents from intercepting touch events
final ViewParent parent = mSv.getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
+
+ MetricsLogger.action(mSv.getContext(), MetricsEvent.OVERVIEW_SCROLL);
}
}
if (mIsScrolling) {
@@ -279,6 +287,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mOverscrollSize);
mSv.invalidate();
}
+
+ // Reset the focused task after the user has scrolled
+ mSv.resetFocusedTask(mSv.getFocusedTask());
} else if (mActiveTaskView == null) {
// This tap didn't start on a task.
maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY());
@@ -400,6 +411,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mCurrentTasks = mSv.getStack().getStackTasks();
MutableBoolean isFrontMostTask = new MutableBoolean(false);
Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask);
+ TaskStackLayoutAlgorithm layoutAlgorithm = mSv.getStackAlgorithm();
TaskStackViewScroller stackScroller = mSv.getScroller();
if (anchorTask != null) {
// Get the current set of task transforms
@@ -410,7 +422,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
float prevAnchorTaskScroll = 0;
boolean pullStackForward = mCurrentTasks.size() > 0;
if (pullStackForward) {
- prevAnchorTaskScroll = mSv.getStackAlgorithm().getStackScrollForTask(anchorTask);
+ prevAnchorTaskScroll = layoutAlgorithm.getStackScrollForTask(anchorTask);
}
// Calculate where the views would be without the deleting tasks
@@ -422,10 +434,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
newStackScroll = stackScroller.getBoundedStackScroll(newStackScroll);
} else if (pullStackForward) {
// Otherwise, offset the scroll by the movement of the anchor task
- float anchorTaskScroll = mSv.getStackAlgorithm().getStackScrollForTask(anchorTask);
+ float anchorTaskScroll = layoutAlgorithm.getStackScrollForTask(anchorTask);
float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
- if (mSv.getStackAlgorithm().getFocusState() !=
- TaskStackLayoutAlgorithm.STATE_FOCUSED) {
+ if (layoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED) {
// If we are focused, we don't want the front task to move, but otherwise, we
// allow the back task to move up, and the front task to move back
stackScrollOffset /= 2;
@@ -438,7 +449,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mSv.bindVisibleTaskViews(newStackScroll);
// Get the final set of task transforms (with task removed)
- mSv.getLayoutTaskTransforms(newStackScroll, mCurrentTasks, mFinalTaskTransforms);
+ mSv.getLayoutTaskTransforms(newStackScroll, TaskStackLayoutAlgorithm.STATE_UNFOCUSED,
+ mCurrentTasks, mFinalTaskTransforms);
// Set the target to scroll towards upon dismissal
mTargetStackScroll = newStackScroll;
@@ -447,7 +459,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
* Post condition: All views that will be visible as a part of the gesture are retrieved
* and at their initial positions. The stack is still at the current
* scroll, but the layout is updated without the task currently being
- * dismissed.
+ * dismissed. The final layout is in the unfocused stack state, which
+ * will be applied when the current task is dismissed.
*/
}
}
@@ -471,6 +484,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
tv.setTouchEnabled(true);
// Update the scroll to the final scroll position from onBeginDrag()
mSv.getScroller().setStackScroll(mTargetStackScroll, null);
+ // Update the focus state to the final focus state
+ mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
// Remove the task view from the stack
EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
// Stop tracking this deletion animation
@@ -485,7 +500,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
* onChildDismissed() calls.
*/
@Override
- public void onChildSnappedBack(View v) {
+ public void onChildSnappedBack(View v, float targetLeft) {
TaskView tv = (TaskView) v;
// Re-enable clipping with the stack
@@ -508,11 +523,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
}
@Override
- public View getChildContentView(View v) {
- return v;
- }
-
- @Override
public boolean isAntiFalsingNeeded() {
return false;
}
@@ -542,9 +552,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mTmpTransform.copyFrom(fromTransform);
// We only really need to interpolate the bounds, progress and translation
- mTmpTransform.rect.set(RECT_EVALUATOR.evaluate(dismissFraction, fromTransform.rect,
- toTransform.rect));
- mTmpTransform.p = fromTransform.p + (toTransform.p - fromTransform.p) * dismissFraction;
+ mTmpTransform.rect.set(Utilities.RECTF_EVALUATOR.evaluate(dismissFraction,
+ fromTransform.rect, toTransform.rect));
+ mTmpTransform.dimAlpha = fromTransform.dimAlpha + (toTransform.dimAlpha -
+ fromTransform.dimAlpha) * dismissFraction;
+ mTmpTransform.viewOutlineAlpha = fromTransform.viewOutlineAlpha +
+ (toTransform.viewOutlineAlpha - fromTransform.viewOutlineAlpha) *
+ dismissFraction;
mTmpTransform.translationZ = fromTransform.translationZ +
(toTransform.translationZ - fromTransform.translationZ) * dismissFraction;
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 439d96f7d27b..0c78e6aa0063 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -31,13 +31,15 @@ import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatProperty;
-import android.util.IntProperty;
import android.util.Property;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
-import android.view.animation.AccelerateInterpolator;
+import android.widget.Toast;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -77,57 +79,71 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
* The dim overlay is generally calculated from the task progress, but occasionally (like when
* launching) needs to be animated independently of the task progress.
*/
- public static final Property<TaskView, Integer> DIM =
- new IntProperty<TaskView>("dim") {
+ public static final Property<TaskView, Float> DIM_ALPHA =
+ new FloatProperty<TaskView>("dimAlpha") {
@Override
- public void setValue(TaskView tv, int dim) {
- tv.setDim(dim);
+ public void setValue(TaskView tv, float dimAlpha) {
+ tv.setDimAlpha(dimAlpha);
}
@Override
- public Integer get(TaskView tv) {
- return tv.getDim();
+ public Float get(TaskView tv) {
+ return tv.getDimAlpha();
}
};
- public static final Property<TaskView, Float> TASK_PROGRESS =
- new FloatProperty<TaskView>("taskProgress") {
+ /**
+ * The dim overlay is generally calculated from the task progress, but occasionally (like when
+ * launching) needs to be animated independently of the task progress.
+ */
+ public static final Property<TaskView, Float> VIEW_OUTLINE_ALPHA =
+ new FloatProperty<TaskView>("viewOutlineAlpha") {
@Override
- public void setValue(TaskView tv, float p) {
- tv.setTaskProgress(p);
+ public void setValue(TaskView tv, float alpha) {
+ tv.getViewBounds().setAlpha(alpha);
}
@Override
public Float get(TaskView tv) {
- return tv.getTaskProgress();
+ return tv.getViewBounds().getAlpha();
}
};
- float mTaskProgress;
- float mMaxDimScale;
- int mDimAlpha;
- AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
+ @ViewDebug.ExportedProperty(category="recents")
+ float mDimAlpha;
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
Paint mDimLayerPaint = new Paint();
float mActionButtonTranslationZ;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
Task mTask;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTaskDataLoaded;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mClipViewInStack = true;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mTouchExplorationEnabled;
+ @ViewDebug.ExportedProperty(category="recents")
+ boolean mIsDisabledInSafeMode;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="view_bounds_")
AnimateableViewBounds mViewBounds;
private AnimatorSet mTransformAnimation;
private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
View mContent;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
TaskViewThumbnail mThumbnailView;
+ @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
TaskViewHeader mHeaderView;
View mActionButtonView;
TaskViewCallbacks mCb;
+ @ViewDebug.ExportedProperty(category="recents")
Point mDownTouchPos = new Point();
+ private Toast mDisabledAppToast;
+
public TaskView(Context context) {
this(context, null);
}
@@ -144,9 +160,8 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
super(context, attrs, defStyleAttr, defStyleRes);
RecentsConfiguration config = Recents.getConfiguration();
Resources res = context.getResources();
- mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
- R.dimen.recents_task_view_rounded_corners_radius));
+ R.dimen.recents_task_view_shadow_rounded_corners_radius));
if (config.fakeShadows) {
setBackground(new FakeShadowDrawable(res, config));
}
@@ -250,8 +265,11 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
mTmpAnimators.clear();
toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, !config.fakeShadows);
if (toAnimation.isImmediate()) {
- if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
- setTaskProgress(toTransform.p);
+ if (Float.compare(getDimAlpha(), toTransform.dimAlpha) != 0) {
+ setDimAlpha(toTransform.dimAlpha);
+ }
+ if (Float.compare(mViewBounds.getAlpha(), toTransform.viewOutlineAlpha) != 0) {
+ mViewBounds.setAlpha(toTransform.viewOutlineAlpha);
}
// Manually call back to the animator listener and update callback
if (toAnimation.getListener() != null) {
@@ -262,9 +280,14 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
} else {
// Both the progress and the update are a function of the bounds movement of the task
- if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
- toTransform.p);
+ if (Float.compare(getDimAlpha(), toTransform.dimAlpha) != 0) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, DIM_ALPHA, getDimAlpha(),
+ toTransform.dimAlpha);
+ mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim));
+ }
+ if (Float.compare(mViewBounds.getAlpha(), toTransform.viewOutlineAlpha) != 0) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, VIEW_OUTLINE_ALPHA,
+ mViewBounds.getAlpha(), toTransform.viewOutlineAlpha);
mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim));
}
if (updateCallback != null) {
@@ -282,7 +305,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
/** Resets this view's properties */
void resetViewProperties() {
cancelTransformAnimation();
- setDim(0);
+ setDimAlpha(0);
setVisibility(View.VISIBLE);
getViewBounds().reset();
getHeaderView().reset();
@@ -357,76 +380,57 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
}
- /** Sets the current task progress. */
- public void setTaskProgress(float p) {
- mTaskProgress = p;
- mViewBounds.setAlpha(p);
- updateDimFromTaskProgress();
- }
-
public TaskViewHeader getHeaderView() {
return mHeaderView;
}
- /** Returns the current task progress. */
- public float getTaskProgress() {
- return mTaskProgress;
- }
-
- /** Returns the current dim. */
- public void setDim(int dim) {
+ /**
+ * Sets the current dim.
+ */
+ public void setDimAlpha(float dimAlpha) {
RecentsConfiguration config = Recents.getConfiguration();
- mDimAlpha = dim;
+ int dimAlphaInt = (int) (dimAlpha * 255);
+ mDimAlpha = dimAlpha;
if (config.useHardwareLayers) {
// Defer setting hardware layers if we have not yet measured, or there is no dim to draw
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
- mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
+ mDimColorFilter.setColor(Color.argb(dimAlphaInt, 0, 0, 0));
mDimLayerPaint.setColorFilter(mDimColorFilter);
mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
}
} else {
- float dimAlpha = mDimAlpha / 255.0f;
mThumbnailView.setDimAlpha(dimAlpha);
mHeaderView.setDimAlpha(dimAlpha);
}
}
- /** Returns the current dim. */
- public int getDim() {
+ /**
+ * Returns the current dim.
+ */
+ public float getDimAlpha() {
return mDimAlpha;
}
- /** Animates the dim to the task progress. */
- void animateDimToProgress(int duration, Animator.AnimatorListener animListener) {
+ /**
+ * Animates the dim to the given value.
+ */
+ void animateDimAlpha(float toDimAlpha, AnimationProps animation) {
// Animate the dim into view as well
- int toDim = getDimFromTaskProgress();
- if (toDim != getDim()) {
- ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), toDim);
- anim.setDuration(duration);
- if (animListener != null) {
- anim.addListener(animListener);
+ if (Float.compare(toDimAlpha, getDimAlpha()) != 0) {
+ Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+ DIM_ALPHA, getDimAlpha(), toDimAlpha));
+ if (animation.getListener() != null) {
+ anim.addListener(animation.getListener());
}
anim.start();
} else {
- animListener.onAnimationEnd(null);
+ if (animation.getListener() != null) {
+ animation.getListener().onAnimationEnd(null);
+ }
}
}
- /** Compute the dim as a function of the scale of this view. */
- int getDimFromTaskProgress() {
- float x = mTaskProgress < 0
- ? 1f
- : mDimInterpolator.getInterpolation(1f - mTaskProgress);
- float dim = mMaxDimScale * x;
- return (int) (dim * 255);
- }
-
- /** Update the dim as a function of the scale of this view. */
- void updateDimFromTaskProgress() {
- setDim(getDimFromTaskProgress());
- }
-
/**
* Explicitly sets the focused state of this task.
*/
@@ -513,15 +517,18 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
@Override
public void onPrepareLaunchTargetForEnterAnimation() {
// These values will be animated in when onStartLaunchTargetEnterAnimation() is called
- setDim(0);
+ setDimAlpha(0);
mActionButtonView.setAlpha(0f);
}
@Override
public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
ReferenceCountedTrigger postAnimationTrigger) {
+ // Un-dim the view before/while launching the target
+ AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT)
+ .setListener(postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
- animateDimToProgress(duration, postAnimationTrigger.decrementOnAnimationEnd());
+ animateDimAlpha(0, animation);
if (screenPinningEnabled) {
showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
@@ -531,12 +538,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
@Override
public void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
ReferenceCountedTrigger postAnimationTrigger) {
- if (mDimAlpha > 0) {
- ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
- anim.setDuration(duration);
- anim.setInterpolator(Interpolators.ALPHA_OUT);
- anim.start();
- }
+ // Un-dim the view before/while launching the target
+ AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
+ animateDimAlpha(0, animation);
postAnimationTrigger.increment();
hideActionButton(true /* fadeOut */, duration,
@@ -547,15 +551,17 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
/**** TaskCallbacks Implementation ****/
public void onTaskBound(Task t) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
mTask.addCallback(this);
+ mIsDisabledInSafeMode = !mTask.isSystemApp && ssp.isInSafeMode();
}
@Override
public void onTaskDataLoaded(Task task) {
// Bind each of the views to the new task data
- mThumbnailView.rebindToTask(mTask);
- mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
+ mThumbnailView.rebindToTask(mTask, mIsDisabledInSafeMode);
+ mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
mTaskDataLoaded = true;
}
@@ -570,13 +576,24 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
@Override
public void onTaskStackIdChanged() {
- mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled);
+ mHeaderView.rebindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
}
/**** View.OnClickListener Implementation ****/
@Override
public void onClick(final View v) {
+ if (mIsDisabledInSafeMode) {
+ Context context = getContext();
+ String msg = context.getString(R.string.recents_launch_disabled_message, mTask.title);
+ if (mDisabledAppToast != null) {
+ mDisabledAppToast.cancel();
+ }
+ mDisabledAppToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
+ mDisabledAppToast.show();
+ return;
+ }
+
boolean screenPinningRequested = false;
if (v == mActionButtonView) {
// Reset the translation of the action button before we animate it out
@@ -585,6 +602,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
screenPinningRequested));
+
+ MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
+ mTask.key.getComponent().toString());
}
/**** View.OnLongClickListener Implementation ****/
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 c91a833e943a..05a85278db16 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -36,6 +36,7 @@ import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewAnimationUtils;
+import android.view.ViewDebug;
import android.view.ViewStub;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -62,7 +63,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
public class TaskViewHeader extends FrameLayout
implements View.OnClickListener, View.OnLongClickListener {
- private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.125f;
+ private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.075f;
private static final float OVERLAY_LIGHTNESS_INCREMENT = -0.0625f;
private static final int OVERLAY_REVEAL_DURATION = 250;
private static final long FOCUS_INDICATOR_INTERVAL_MS = 30;
@@ -74,6 +75,8 @@ public class TaskViewHeader extends FrameLayout
private Paint mHighlightPaint = new Paint();
private Paint mBackgroundPaint = new Paint();
+ private int mColor;
+ private float mDimAlpha;
public HighlightColorDrawable() {
mBackgroundPaint.setColor(Color.argb(255, 0, 0, 0));
@@ -83,15 +86,19 @@ public class TaskViewHeader extends FrameLayout
}
public void setColorAndDim(int color, float dimAlpha) {
- mBackgroundPaint.setColor(color);
-
- ColorUtils.colorToHSL(color, mTmpHSL);
- // TODO: Consider using the saturation of the color to adjust the lightness as well
- mTmpHSL[2] = Math.min(1f,
- mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
- mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
-
- invalidateSelf();
+ if (mColor != color || Float.compare(mDimAlpha, dimAlpha) != 0) {
+ mColor = color;
+ mDimAlpha = dimAlpha;
+ mBackgroundPaint.setColor(color);
+
+ ColorUtils.colorToHSL(color, mTmpHSL);
+ // TODO: Consider using the saturation of the color to adjust the lightness as well
+ mTmpHSL[2] = Math.min(1f,
+ mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
+ mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
+
+ invalidateSelf();
+ }
}
@Override
@@ -121,6 +128,10 @@ public class TaskViewHeader extends FrameLayout
public int getOpacity() {
return PixelFormat.OPAQUE;
}
+
+ public int getColor() {
+ return mColor;
+ }
}
Task mTask;
@@ -128,6 +139,7 @@ public class TaskViewHeader extends FrameLayout
// Header views
ImageView mIconView;
TextView mTitleView;
+ TextView mSubTitleView;
ImageView mMoveTaskButton;
ImageView mDismissButton;
ViewStub mAppOverlayViewStub;
@@ -139,9 +151,11 @@ public class TaskViewHeader extends FrameLayout
ProgressBar mFocusTimerIndicator;
// Header drawables
+ @ViewDebug.ExportedProperty(category="recents")
Rect mTaskViewRect = new Rect();
int mCornerRadius;
int mHighlightHeight;
+ @ViewDebug.ExportedProperty(category="recents")
float mDimAlpha;
Drawable mLightDismissDrawable;
Drawable mDarkDismissDrawable;
@@ -153,6 +167,7 @@ public class TaskViewHeader extends FrameLayout
Drawable mDarkInfoIcon;
int mTaskBarViewLightTextColor;
int mTaskBarViewDarkTextColor;
+ int mDisabledTaskBarBackgroundColor;
int mMoveTaskTargetStackId = INVALID_STACK_ID;
// Header background
@@ -195,6 +210,8 @@ public class TaskViewHeader extends FrameLayout
mDarkFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_dark);
mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
+ mDisabledTaskBarBackgroundColor =
+ context.getColor(R.color.recents_task_bar_disabled_background_color);
// Configure the background and dim
mBackground = new HighlightColorDrawable();
@@ -221,6 +238,7 @@ public class TaskViewHeader extends FrameLayout
mIconView.setClickable(false);
mIconView.setOnLongClickListener(this);
mTitleView = (TextView) findViewById(R.id.title);
+ mSubTitleView = (TextView) findViewById(R.id.sub_title);
mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
if (ssp.hasFreeformWorkspaceSupport()) {
mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
@@ -331,17 +349,17 @@ public class TaskViewHeader extends FrameLayout
*/
void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
- updateBackgroundColor(dimAlpha);
+ updateBackgroundColor(mBackground.getColor(), dimAlpha);
}
/**
* Updates the background and highlight colors for this header.
*/
- private void updateBackgroundColor(float dimAlpha) {
+ private void updateBackgroundColor(int color, float dimAlpha) {
if (mTask != null) {
- mBackground.setColorAndDim(mTask.colorPrimary, dimAlpha);
+ mBackground.setColorAndDim(color, dimAlpha);
// TODO: Consider using the saturation of the color to adjust the lightness as well
- ColorUtils.colorToHSL(mTask.colorPrimary, mTmpHSL);
+ ColorUtils.colorToHSL(color, mTmpHSL);
mTmpHSL[2] = Math.min(1f, mTmpHSL[2] + OVERLAY_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
mOverlayBackground.setColorAndDim(ColorUtils.HSLToColor(mTmpHSL), dimAlpha);
mDimLayerPaint.setAlpha((int) (dimAlpha * 255));
@@ -350,12 +368,16 @@ public class TaskViewHeader extends FrameLayout
}
/** Binds the bar view to the task */
- public void rebindToTask(Task t, boolean touchExplorationEnabled) {
+ public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
// otherwise, we fall back to the application icon
- updateBackgroundColor(mDimAlpha);
+ int primaryColor = disabledInSafeMode
+ ? mDisabledTaskBarBackgroundColor
+ : t.colorPrimary;
+ updateBackgroundColor(primaryColor, mDimAlpha);
if (t.icon != null) {
mIconView.setImageDrawable(t.icon);
}
@@ -365,6 +387,13 @@ public class TaskViewHeader extends FrameLayout
mTitleView.setContentDescription(t.contentDescription);
mTitleView.setTextColor(t.useLightOnPrimaryColor ?
mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+ if (!t.isDockable && ssp.hasDockedTask()) {
+ mSubTitleView.setVisibility(View.VISIBLE);
+ mSubTitleView.setTextColor(t.useLightOnPrimaryColor ?
+ mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+ } else {
+ mSubTitleView.setVisibility(View.GONE);
+ }
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(t.dismissDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index f90951e4ccd1..e46708e61a2c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -21,13 +21,17 @@ import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewDebug;
import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
@@ -39,27 +43,40 @@ import com.android.systemui.recents.model.Task;
*/
public class TaskViewThumbnail extends View {
+
+ private static final ColorMatrix TMP_FILTER_COLOR_MATRIX = new ColorMatrix();
+ private static final ColorMatrix TMP_BRIGHTNESS_COLOR_MATRIX = new ColorMatrix();
+
private Task mTask;
// Drawing
+ @ViewDebug.ExportedProperty(category="recents")
Rect mThumbnailRect = new Rect();
+ @ViewDebug.ExportedProperty(category="recents")
Rect mTaskViewRect = new Rect();
int mCornerRadius;
+ @ViewDebug.ExportedProperty(category="recents")
float mDimAlpha;
Matrix mScaleMatrix = new Matrix();
Paint mDrawPaint = new Paint();
+ Paint mBgFillPaint = new Paint();
BitmapShader mBitmapShader;
LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
// Task bar clipping, the top of this thumbnail can be clipped against the opaque header
// bar that overlaps this thumbnail
View mTaskBar;
+ @ViewDebug.ExportedProperty(category="recents")
Rect mClipRect = new Rect();
// Visibility optimization, if the thumbnail height is less than the height of the header
// bar for the task view, then just mark this thumbnail view as invisible
+ @ViewDebug.ExportedProperty(category="recents")
boolean mInvisible;
+ @ViewDebug.ExportedProperty(category="recents")
+ boolean mDisabledInSafeMode;
+
public TaskViewThumbnail(Context context) {
this(context, null);
}
@@ -79,6 +96,7 @@ public class TaskViewThumbnail extends View {
mDrawPaint.setAntiAlias(true);
mCornerRadius = getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
+ mBgFillPaint.setColor(Color.WHITE);
}
/**
@@ -100,10 +118,39 @@ public class TaskViewThumbnail extends View {
if (mInvisible) {
return;
}
- // Draw the thumbnail with the rounded corners
- canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
- mCornerRadius,
- mCornerRadius, mDrawPaint);
+
+ int thumbnailHeight = (int) (((float) mTaskViewRect.width() / mThumbnailRect.width()) *
+ mThumbnailRect.height());
+ if (thumbnailHeight >= mTaskViewRect.height()) {
+ // The thumbnail fills the full task view bounds, so just draw it
+ canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
+ mCornerRadius, mCornerRadius, mDrawPaint);
+ } else {
+ int count = 0;
+ if (thumbnailHeight > 0) {
+ // The thumbnail only covers part of the task view bounds, so fill in the
+ // non-thumbnail space with the default background color. This is the equivalent of
+ // the GL border texture mode.
+ count = canvas.save();
+
+ // Since we only want the top corners to be rounded, draw slightly beyond the
+ // thumbnail height, but clip to the thumbnail height
+ canvas.clipRect(0, 0, mTaskViewRect.width(), thumbnailHeight, Region.Op.REPLACE);
+ canvas.drawRoundRect(0, 0, mTaskViewRect.width(), thumbnailHeight + mCornerRadius,
+ mCornerRadius, mCornerRadius, mDrawPaint);
+ }
+
+ // In the remaining space, draw the background color
+ canvas.clipRect(0, thumbnailHeight, mTaskViewRect.width(), mTaskViewRect.height(),
+ Region.Op.REPLACE);
+ canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+ mTaskViewRect.width(), mTaskViewRect.height(), mCornerRadius, mCornerRadius,
+ mBgFillPaint);
+
+ if (thumbnailHeight > 0) {
+ canvas.restoreToCount(count);
+ }
+ }
}
/** Sets the thumbnail to a given bitmap. */
@@ -128,9 +175,27 @@ public class TaskViewThumbnail extends View {
}
int mul = (int) ((1.0f - mDimAlpha) * 255);
if (mBitmapShader != null) {
- mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
- mDrawPaint.setColorFilter(mLightingColorFilter);
- mDrawPaint.setColor(0xffffffff);
+ if (mDisabledInSafeMode) {
+ // Brightness: C-new = C-old*(1-amount) + amount
+ TMP_FILTER_COLOR_MATRIX.setSaturation(0);
+ float scale = 1f - mDimAlpha;
+ float[] mat = TMP_BRIGHTNESS_COLOR_MATRIX.getArray();
+ mat[0] = scale;
+ mat[6] = scale;
+ mat[12] = scale;
+ mat[4] = mDimAlpha * 255f;
+ mat[9] = mDimAlpha * 255f;
+ mat[14] = mDimAlpha * 255f;
+ TMP_FILTER_COLOR_MATRIX.preConcat(TMP_BRIGHTNESS_COLOR_MATRIX);
+ ColorMatrixColorFilter filter = new ColorMatrixColorFilter(TMP_FILTER_COLOR_MATRIX);
+ mDrawPaint.setColorFilter(filter);
+ mBgFillPaint.setColorFilter(filter);
+ } else {
+ mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
+ mDrawPaint.setColorFilter(mLightingColorFilter);
+ mDrawPaint.setColor(0xFFffffff);
+ mBgFillPaint.setColorFilter(mLightingColorFilter);
+ }
} else {
int grey = mul;
mDrawPaint.setColorFilter(null);
@@ -196,10 +261,14 @@ public class TaskViewThumbnail extends View {
}
/** Binds the thumbnail view to the task */
- void rebindToTask(Task t) {
+ void rebindToTask(Task t, boolean disabledInSafeMode) {
mTask = t;
+ mDisabledInSafeMode = disabledInSafeMode;
if (t.thumbnail != null) {
setThumbnail(t.thumbnail);
+ if (t.colorBackground != 0) {
+ mBgFillPaint.setColor(t.colorBackground);
+ }
} else {
setThumbnail(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 32878b0afcb7..0d16a79735fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -86,13 +86,11 @@ public class TaskViewTransform {
public float translationZ = 0;
public float scale = 1f;
public float alpha = 1f;
+ public float dimAlpha = 0f;
+ public float viewOutlineAlpha = 0f;
public boolean visible = false;
- // This is the relative task progress of this task, relative to the stack scroll at which this
- // transform was computed
- public float p = 0f;
-
// This is a window-space rect used for positioning the task in the stack and freeform workspace
public RectF rect = new RectF();
@@ -104,7 +102,8 @@ public class TaskViewTransform {
scale = tv.getScaleX();
alpha = tv.getAlpha();
visible = true;
- p = tv.getTaskProgress();
+ dimAlpha = tv.getDimAlpha();
+ viewOutlineAlpha = tv.getViewBounds().getAlpha();
rect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
}
@@ -116,7 +115,8 @@ public class TaskViewTransform {
scale = other.scale;
alpha = other.alpha;
visible = other.visible;
- p = other.p;
+ dimAlpha = other.dimAlpha;
+ viewOutlineAlpha = other.viewOutlineAlpha;
rect.set(other.rect);
}
@@ -127,9 +127,10 @@ public class TaskViewTransform {
translationZ = 0;
scale = 1f;
alpha = 1f;
+ dimAlpha = 0f;
+ viewOutlineAlpha = 0f;
visible = false;
rect.setEmpty();
- p = 0f;
}
/** Convenience functions to compare against current property values */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
index 31fbd3e15705..a287fe642002 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
@@ -29,8 +29,8 @@ public class ViewPool<V, T> {
/* An interface to the consumer of a view pool */
public interface ViewPoolConsumer<V, T> {
public V createView(Context context);
- public void prepareViewToEnterPool(V v);
- public void prepareViewToLeavePool(V v, T prepareData, boolean isNewView);
+ public void onReturnViewToPool(V v);
+ public void onPickUpViewFromPool(V v, T prepareData, boolean isNewView);
public boolean hasPreferredData(V v, T preferredData);
}
@@ -46,7 +46,7 @@ public class ViewPool<V, T> {
/** Returns a view into the pool */
void returnViewToPool(V v) {
- mViewCreator.prepareViewToEnterPool(v);
+ mViewCreator.onReturnViewToPool(v);
mPool.push(v);
}
@@ -73,7 +73,7 @@ public class ViewPool<V, T> {
v = mPool.pop();
}
}
- mViewCreator.prepareViewToLeavePool(v, prepareData, isNewView);
+ mViewCreator.onPickUpViewFromPool(v, prepareData, isNewView);
return v;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index e6a291c49e73..a06700d88c15 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -75,9 +75,9 @@ class SaveImageInBackgroundData {
Uri imageUri;
Runnable finisher;
int iconSize;
- int result;
int previewWidth;
int previewheight;
+ int errorMsgResId;
void clearImage() {
image = null;
@@ -94,13 +94,11 @@ class SaveImageInBackgroundData {
*/
class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
SaveImageInBackgroundData> {
- private static final String TAG = "SaveImageInBackgroundTask";
private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
- private final int mNotificationId;
private final NotificationManager mNotificationManager;
private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder;
private final File mScreenshotDir;
@@ -119,7 +117,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
private static boolean mTickerAddSpace;
SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,
- NotificationManager nManager, int nId) {
+ NotificationManager nManager) {
Resources r = context.getResources();
// Prepare all the output metadata
@@ -166,25 +164,14 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
// Show the intermediate notification
mTickerAddSpace = !mTickerAddSpace;
- mNotificationId = nId;
mNotificationManager = nManager;
final long now = System.currentTimeMillis();
- mNotificationBuilder = new Notification.Builder(context)
- .setTicker(r.getString(R.string.screenshot_saving_ticker)
- + (mTickerAddSpace ? " " : ""))
- .setContentTitle(r.getString(R.string.screenshot_saving_title))
- .setContentText(r.getString(R.string.screenshot_saving_text))
- .setSmallIcon(R.drawable.stat_notify_image)
- .setWhen(now)
- .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color));
-
+ // Setup the notification
mNotificationStyle = new Notification.BigPictureStyle()
- .bigPicture(picture.createAshmemBitmap());
- mNotificationBuilder.setStyle(mNotificationStyle);
+ .bigPicture(picture.createAshmemBitmap());
- // For "public" situations we want to show all the same info but
- // omit the actual screenshot image.
+ // 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))
@@ -194,11 +181,24 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
.setColor(r.getColor(
com.android.internal.R.color.system_notification_accent_color));
- mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
+ mNotificationBuilder = new Notification.Builder(context)
+ .setTicker(r.getString(R.string.screenshot_saving_ticker)
+ + (mTickerAddSpace ? " " : ""))
+ .setContentTitle(r.getString(R.string.screenshot_saving_title))
+ .setContentText(r.getString(R.string.screenshot_saving_text))
+ .setSmallIcon(R.drawable.stat_notify_image)
+ .setWhen(now)
+ .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color))
+ .setStyle(mNotificationStyle)
+ .setPublicVersion(mPublicNotificationBuilder.build());
+ mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
+
+ mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
- Notification n = mNotificationBuilder.build();
- n.flags |= Notification.FLAG_NO_CLEAR;
- mNotificationManager.notify(nId, n);
+ /**
+ * NOTE: The following code prepares the notification builder for updating the notification
+ * after the screenshot has been written to disk.
+ */
// On the tablet, the large icon makes the notification appear as if it is clickable (and
// on small devices, the large icon is not shown) so defer showing the large icon until
@@ -210,11 +210,8 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
@Override
protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
- if (params.length != 1) return null;
if (isCancelled()) {
- params[0].clearImage();
- params[0].clearContext();
- return null;
+ return params[0];
}
// By default, AsyncTask sets the worker thread to have background thread priority, so bump
@@ -263,36 +260,37 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
// Create a share action for the notification
- final PendingIntent callback = PendingIntent.getBroadcast(context, 0,
- new Intent(context, GlobalScreenshot.TargetChosenReceiver.class)
- .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId),
+ PendingIntent chooseAction = PendingIntent.getBroadcast(context, 0,
+ new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
Intent chooserIntent = Intent.createChooser(sharingIntent, null,
- callback.getIntentSender());
- chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- mNotificationBuilder.addAction(R.drawable.ic_screenshot_share,
- r.getString(com.android.internal.R.string.share),
- PendingIntent.getActivity(context, 0, chooserIntent,
- PendingIntent.FLAG_CANCEL_CURRENT));
+ chooseAction.getIntentSender())
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ PendingIntent shareAction = PendingIntent.getActivity(context, 0, chooserIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
+ R.drawable.ic_screenshot_share,
+ r.getString(com.android.internal.R.string.share), shareAction);
+ mNotificationBuilder.addAction(shareActionBuilder.build());
// Create a delete action for the notification
- final PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
+ PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
- .putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId)
.putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
- mNotificationBuilder.addAction(R.drawable.ic_screenshot_delete,
+ Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
+ R.drawable.ic_screenshot_delete,
r.getString(com.android.internal.R.string.delete), deleteAction);
+ mNotificationBuilder.addAction(deleteActionBuilder.build());
params[0].imageUri = uri;
params[0].image = null;
- params[0].result = 0;
+ params[0].errorMsgResId = 0;
} catch (Exception e) {
// IOException/UnsupportedOperationException may be thrown if external storage is not
// mounted
params[0].clearImage();
- params[0].result = 1;
+ params[0].errorMsgResId = R.string.screenshot_failed_to_save_text;
}
// Recycle the bitmap data
@@ -305,19 +303,14 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
@Override
protected void onPostExecute(SaveImageInBackgroundData params) {
- if (isCancelled()) {
- params.finisher.run();
- params.clearImage();
- params.clearContext();
- return;
- }
-
- if (params.result > 0) {
+ if (params.errorMsgResId != 0) {
// Show a message that we've failed to save the image to disk
- GlobalScreenshot.notifyScreenshotError(params.context, mNotificationManager);
+ GlobalScreenshot.notifyScreenshotError(params.context, mNotificationManager,
+ params.errorMsgResId);
} else {
// Show the final notification to indicate screenshot saved
- Resources r = params.context.getResources();
+ Context context = params.context;
+ Resources r = context.getResources();
// Create the intent to show the screenshot in gallery
Intent launchIntent = new Intent(Intent.ACTION_VIEW);
@@ -326,34 +319,41 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
final long now = System.currentTimeMillis();
- mNotificationBuilder
- .setContentTitle(r.getString(R.string.screenshot_saved_title))
- .setContentText(r.getString(R.string.screenshot_saved_text))
- .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
- .setWhen(now)
- .setAutoCancel(true)
- .setColor(r.getColor(
- com.android.internal.R.color.system_notification_accent_color));;
-
- // Update the text in the public version as well
+ // Update the text and the icon for the existing notification
mPublicNotificationBuilder
+ .setContentTitle(r.getString(R.string.screenshot_saved_title))
+ .setContentText(r.getString(R.string.screenshot_saved_text))
+ .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
+ .setWhen(now)
+ .setAutoCancel(true)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+ mNotificationBuilder
.setContentTitle(r.getString(R.string.screenshot_saved_title))
.setContentText(r.getString(R.string.screenshot_saved_text))
.setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0))
.setWhen(now)
.setAutoCancel(true)
- .setColor(r.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setPublicVersion(mPublicNotificationBuilder.build())
+ .setFlag(Notification.FLAG_NO_CLEAR, false);
- mNotificationBuilder.setPublicVersion(mPublicNotificationBuilder.build());
-
- Notification n = mNotificationBuilder.build();
- n.flags &= ~Notification.FLAG_NO_CLEAR;
- mNotificationManager.notify(mNotificationId, n);
+ mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
}
params.finisher.run();
params.clearContext();
}
+
+ @Override
+ protected void onCancelled(SaveImageInBackgroundData params) {
+ params.finisher.run();
+ params.clearImage();
+ params.clearContext();
+
+ // Cancel the posted notification
+ mNotificationManager.cancel(R.id.notification_screenshot);
+ }
}
/**
@@ -379,16 +379,7 @@ class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> {
}
}
-/**
- * TODO:
- * - Performance when over gl surfaces? Ie. Gallery
- * - what do we say in the Toast? Which icon do we get if the user uses another
- * type of gallery?
- */
class GlobalScreenshot {
- private static final String TAG = "GlobalScreenshot";
-
- static final String CANCEL_ID = "android:cancel_id";
static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
@@ -512,8 +503,8 @@ class GlobalScreenshot {
if (mSaveInBgTask != null) {
mSaveInBgTask.cancel(false);
}
- mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager,
- R.id.notification_screenshot).execute(data);
+ mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager)
+ .execute(data);
}
/**
@@ -553,7 +544,8 @@ class GlobalScreenshot {
// Take the screenshot
mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
if (mScreenBitmap == null) {
- notifyScreenshotError(mContext, mNotificationManager);
+ notifyScreenshotError(mContext, mNotificationManager,
+ R.string.screenshot_failed_to_capture_text);
finisher.run();
return;
}
@@ -763,14 +755,15 @@ class GlobalScreenshot {
return anim;
}
- static void notifyScreenshotError(Context context, NotificationManager nManager) {
+ static void notifyScreenshotError(Context context, NotificationManager nManager, int msgResId) {
Resources r = context.getResources();
+ String errorMsg = r.getString(msgResId);
- // Clear all existing notification, compose the new notification and show it
+ // Repurpose the existing notification to notify the user of the error
Notification.Builder b = new Notification.Builder(context)
.setTicker(r.getString(R.string.screenshot_failed_title))
.setContentTitle(r.getString(R.string.screenshot_failed_title))
- .setContentText(r.getString(R.string.screenshot_failed_text))
+ .setContentText(errorMsg)
.setSmallIcon(R.drawable.stat_notify_image_error)
.setWhen(System.currentTimeMillis())
.setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
@@ -778,9 +771,9 @@ class GlobalScreenshot {
.setAutoCancel(true)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color));
- Notification n =
- new Notification.BigTextStyle(b)
- .bigText(r.getString(R.string.screenshot_failed_text))
+
+ Notification n = new Notification.BigTextStyle(b)
+ .bigText(errorMsg)
.build();
nManager.notify(R.id.notification_screenshot, n);
}
@@ -791,15 +784,10 @@ class GlobalScreenshot {
public static class TargetChosenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!intent.hasExtra(CANCEL_ID)) {
- return;
- }
-
// Clear the notification
final NotificationManager nm =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- final int id = intent.getIntExtra(CANCEL_ID, 0);
- nm.cancel(id);
+ nm.cancel(R.id.notification_screenshot);
}
}
@@ -809,16 +797,15 @@ class GlobalScreenshot {
public static class DeleteScreenshotReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!intent.hasExtra(CANCEL_ID) || !intent.hasExtra(SCREENSHOT_URI_ID)) {
+ if (!intent.hasExtra(SCREENSHOT_URI_ID)) {
return;
}
// Clear the notification
final NotificationManager nm =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- final int id = intent.getIntExtra(CANCEL_ID, 0);
final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
- nm.cancel(id);
+ nm.cancel(R.id.notification_screenshot);
// And delete the image from the media store
new DeleteImageInBackgroundTask(context).execute(uri);
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
new file mode 100644
index 000000000000..8f8683b4ea23
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -0,0 +1,69 @@
+/*
+ * 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.shortcut;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.KeyEvent;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Dispatches shortcut to System UI components
+ */
+public class ShortcutKeyDispatcher extends SystemUI
+ implements ShortcutKeyServiceProxy.Callbacks {
+
+ private static final String TAG = "ShortcutKeyDispatcher";
+
+ private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
+ private IWindowManager windowManagerService = WindowManagerGlobal.getWindowManagerService();
+
+ protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE;
+ protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
+ protected final long CTRL_MASK = ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
+ protected final long SHIFT_MASK = ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
+
+ /**
+ * Registers a shortcut key to window manager.
+ * @param shortcutCode packed representation of shortcut key code and meta information
+ */
+ public void registerShortcutKey(long shortcutCode) {
+ try {
+ windowManagerService.registerShortcutKey(shortcutCode, mShortcutKeyServiceProxy);
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ }
+
+ @Override
+ public void onShortcutKeyPressed(long shortcutCode) {}
+
+ @Override
+ public void start() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java
new file mode 100644
index 000000000000..8ec862e1fdec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyServiceProxy.java
@@ -0,0 +1,58 @@
+/*
+ * 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.shortcut;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import com.android.internal.policy.IShortcutService;
+
+/**
+ * This class takes functions from IShortcutService that come in binder pool threads and
+ * post them onto shortcut handlers.
+ */
+public class ShortcutKeyServiceProxy extends IShortcutService.Stub {
+ private static final int MSG_SHORTCUT_RECEIVED = 1;
+
+ private final Object mLock = new Object();
+ private Callbacks mCallbacks;
+ private final Handler mHandler = new H();
+
+ public interface Callbacks {
+ void onShortcutKeyPressed(long shortcutCode);
+ }
+
+ public ShortcutKeyServiceProxy(Callbacks callbacks) { mCallbacks = callbacks; }
+
+ @Override
+ public void notifyShortcutKeyPressed(long shortcutCode) throws RemoteException {
+ synchronized (mLock) {
+ mHandler.obtainMessage(MSG_SHORTCUT_RECEIVED, shortcutCode).sendToTarget();
+ }
+ }
+
+ private final class H extends Handler {
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+ switch (what) {
+ case MSG_SHORTCUT_RECEIVED:
+ mCallbacks.onShortcutKeyPressed((Long)msg.obj);
+ break;
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 189e651b7dca..dd59face9ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -40,6 +40,7 @@ public class Divider extends SystemUI {
private DividerView mView;
private DockDividerVisibilityListener mDockDividerVisibilityListener;
private boolean mVisible = false;
+ private boolean mMinimized = false;
@Override
public void start() {
@@ -81,6 +82,10 @@ public class Divider extends SystemUI {
private void update(Configuration configuration) {
removeDivider();
addDivider(configuration);
+ if (mMinimized) {
+ mView.setMinimizedDockStack(true);
+ mWindowManager.setTouchable(false);
+ }
}
private void updateVisibility(final boolean visible) {
@@ -95,6 +100,23 @@ public class Divider extends SystemUI {
});
}
+ private void updateMinimizedDockedStack(final boolean minimized, final long animDuration) {
+ mView.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mMinimized != minimized) {
+ mMinimized = minimized;
+ mWindowManager.setTouchable(!minimized);
+ if (animDuration > 0) {
+ mView.setMinimizedDockStack(minimized, animDuration);
+ } else {
+ mView.setMinimizedDockStack(minimized);
+ }
+ }
+ }
+ });
+ }
+
class DockDividerVisibilityListener extends IDockedStackListener.Stub {
@Override
@@ -105,5 +127,11 @@ public class Divider extends SystemUI {
@Override
public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
}
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
+ throws RemoteException {
+ updateMinimizedDockedStack(minimized, animDuration);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index 36cfac8dd092..d5f7b39b8e61 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -26,7 +26,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Property;
-import android.widget.ImageButton;
+import android.view.View;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -34,7 +34,7 @@ import com.android.systemui.R;
/**
* View for the handle in the docked stack divider.
*/
-public class DividerHandleView extends ImageButton {
+public class DividerHandleView extends View {
private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
= new Property<DividerHandleView, Integer>(Integer.class, "width") {
@@ -140,4 +140,9 @@ public class DividerHandleView extends ImageButton {
canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight,
radius, radius, mPaint);
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1bdf5a1e698d..da5cbe7a9003 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -27,6 +27,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.Display;
import android.view.DisplayInfo;
@@ -40,7 +41,8 @@ import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
@@ -86,6 +88,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
*/
private static final float BOTTOM_RIGHT_SWITCH_BIGGER_FRACTION = 0.2f;
+ /**
+ * How much the background gets scaled when we are in the minimized dock state.
+ */
+ private static final float MINIMIZE_DOCK_SCALE = 0.375f;
+
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
private static final PathInterpolator DIM_INTERPOLATOR =
@@ -126,6 +133,43 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private boolean mAnimateAfterRecentsDrawn;
private boolean mGrowAfterRecentsDrawn;
private boolean mGrowRecents;
+ private Animator mCurrentAnimator;
+
+ private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (isHorizontalDivision()) {
+ info.addAction(new AccessibilityAction(R.id.action_move_up,
+ mContext.getString(R.string.accessibility_action_divider_move_up)));
+ info.addAction(new AccessibilityAction(R.id.action_move_down,
+ mContext.getString(R.string.accessibility_action_divider_move_down)));
+ } else {
+ info.addAction(new AccessibilityAction(R.id.action_move_left,
+ mContext.getString(R.string.accessibility_action_divider_move_left)));
+ info.addAction(new AccessibilityAction(R.id.action_move_right,
+ mContext.getString(R.string.accessibility_action_divider_move_right)));
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (action == R.id.action_move_up || action == R.id.action_move_down
+ || action == R.id.action_move_left || action == R.id.action_move_right) {
+ int position = getCurrentPosition();
+ SnapTarget currentTarget = mSnapAlgorithm.calculateSnapTarget(
+ position, 0 /* velocity */);
+ SnapTarget nextTarget =
+ action == R.id.action_move_up || action == R.id.action_move_left
+ ? mSnapAlgorithm.getPreviousTarget(currentTarget)
+ : mSnapAlgorithm.getNextTarget(currentTarget);
+ startDragging(true /* animate */, false /* touching */);
+ stopDragging(getCurrentPosition(), nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN);
+ return true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ };
public DividerView(Context context) {
super(context);
@@ -166,6 +210,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW));
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ mHandle.setAccessibilityDelegate(mHandleDelegate);
}
@Override
@@ -205,6 +250,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public boolean startDragging(boolean animate, boolean touching) {
+ cancelFlingAnimation();
if (touching) {
mHandle.setTouching(true, animate);
}
@@ -364,11 +410,19 @@ public class DividerView extends FrameLayout implements OnTouchListener,
commitSnapFlags(snapTarget);
mWindowManagerProxy.setResizing(false);
mDockSide = WindowManager.DOCKED_INVALID;
+ mCurrentAnimator = null;
}
});
+ mCurrentAnimator = anim;
return anim;
}
+ private void cancelFlingAnimation() {
+ if (mCurrentAnimator != null) {
+ mCurrentAnimator.cancel();
+ }
+ }
+
private void commitSnapFlags(SnapTarget target) {
if (target.flag == SnapTarget.FLAG_NONE) {
return;
@@ -433,6 +487,47 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mBackgroundLifted = false;
}
+
+ public void setMinimizedDockStack(boolean minimized) {
+ updateDockSide();
+ mHandle.setAlpha(minimized ? 0f : 1f);
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.setScaleY(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.setScaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ }
+ }
+
+ public void setMinimizedDockStack(boolean minimized, long animDuration) {
+ 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);
+ }
+ mBackground.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(animDuration)
+ .start();
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 2294d40d318d..3db03d0abf11 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -22,6 +22,7 @@ import android.view.View;
import android.view.WindowManager;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
@@ -79,4 +80,18 @@ public class DividerWindowManager {
mWindowManager.updateViewLayout(mView, mLp);
}
}
+
+ public void setTouchable(boolean touchable) {
+ boolean changed = false;
+ if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
+ mLp.flags |= FLAG_NOT_TOUCHABLE;
+ changed = true;
+ } else if (touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) != 0) {
+ mLp.flags &= ~FLAG_NOT_TOUCHABLE;
+ changed = true;
+ }
+ if (changed) {
+ mWindowManager.updateViewLayout(mView, mLp);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 874defad3f7d..effe581ac9ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -35,6 +35,7 @@ import android.view.animation.PathInterpolator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
/**
@@ -155,6 +156,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
};
private float mShadowAlpha = 1.0f;
+ private FakeShadowView mFakeShadow;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -180,6 +182,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
protected void onFinishInflate() {
super.onFinishInflate();
mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
+ mFakeShadow = (FakeShadowView) findViewById(R.id.fake_shadow);
mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
@@ -208,6 +211,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return false;
}
+ protected boolean handleSlideBack() {
+ return false;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result;
@@ -260,6 +267,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
break;
case MotionEvent.ACTION_UP:
if (isWithinTouchSlop(event)) {
+ if (handleSlideBack()) {
+ return true;
+ }
if (!mActivated) {
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
@@ -845,6 +855,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
+ @Override
+ public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
+ int outlineTranslation) {
+ mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
+ + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
+ outlineTranslation);
+ }
+
public interface OnActivatedListener {
void onActivated(ActivatableNotificationView view);
void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7d37ad22223f..d0358f4cda60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -38,6 +38,7 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.AsyncTask;
@@ -102,21 +103,22 @@ 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.NotificationStackScrollLayout.GearDisplayedListener;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
- ExpandableNotificationRow.OnExpandClickListener {
+ ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener {
public static final String TAG = "StatusBar";
- public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_REMOTE_INPUT =
@@ -194,6 +196,7 @@ public abstract class BaseStatusBar extends SystemUI implements
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
private UserManager mUserManager;
+ private int mDensity;
// UI-specific methods
@@ -218,6 +221,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// which notification is currently being longpress-examined by the user
private NotificationGuts mNotificationGutsExposed;
+ private ExpandableNotificationRow mNotificationGearDisplayed;
private KeyboardShortcuts mKeyboardShortcuts;
@@ -227,6 +231,7 @@ public abstract class BaseStatusBar extends SystemUI implements
protected int mState;
protected boolean mBouncerShowing;
protected boolean mShowLockscreenNotifications;
+ protected boolean mAllowLockscreenRemoteInput;
protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
protected DismissView mDismissView;
@@ -398,11 +403,26 @@ public abstract class BaseStatusBar extends SystemUI implements
}
p = p.getParent();
}
+ ExpandableNotificationRow row = null;
+ while (p != null) {
+ if (p instanceof ExpandableNotificationRow) {
+ row = (ExpandableNotificationRow) p;
+ break;
+ }
+ p = p.getParent();
+ }
- if (riv == null) {
+ if (riv == null || row == null) {
return false;
}
+ row.setUserExpanded(true);
+
+ if (isLockscreenPublicMode() && !mAllowLockscreenRemoteInput) {
+ onLockedRemoteInput(row, view);
+ return true;
+ }
+
riv.setVisibility(View.VISIBLE);
int cx = view.getLeft() + view.getWidth() / 2;
int cy = view.getTop() + view.getHeight() / 2;
@@ -617,6 +637,10 @@ public abstract class BaseStatusBar extends SystemUI implements
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
mSettingsObserver,
UserHandle.USER_ALL);
+ 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),
@@ -633,18 +657,22 @@ public abstract class BaseStatusBar extends SystemUI implements
mLocale = currentConfig.locale;
mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
mFontScale = currentConfig.fontScale;
+ mDensity = currentConfig.densityDpi;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
// Connect in to the status bar manager service
mCommandQueue = new CommandQueue(this);
- int[] switches = new int[8];
+ 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);
+ mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
+ fullscreenStackBounds, dockedStackBounds);
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
@@ -653,7 +681,8 @@ public abstract class BaseStatusBar extends SystemUI implements
mSettingsObserver.onChange(false); // set up
disable(switches[0], switches[6], false /* animate */);
- setSystemUiVisibility(switches[1], 0xffffffff);
+ 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);
@@ -813,8 +842,13 @@ public abstract class BaseStatusBar extends SystemUI implements
final Locale locale = mContext.getResources().getConfiguration().locale;
final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
final float fontScale = newConfig.fontScale;
-
- if (! locale.equals(mLocale) || ld != mLayoutDirection || fontScale != mFontScale) {
+ final int density = newConfig.densityDpi;
+ if (density != mDensity || mFontScale != fontScale) {
+ reInflateViews();
+ mDensity = density;
+ mFontScale = fontScale;
+ }
+ if (! locale.equals(mLocale) || ld != mLayoutDirection) {
if (DEBUG) {
Log.v(TAG, String.format(
"config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
@@ -826,6 +860,21 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
+ protected void reInflateViews() {
+ 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);
+ }
+ entry.cacheContentViews(mContext, null /* updatedNotification */);
+ inflateViews(entry, mStackScroller);
+ }
+ }
+
protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
final String _pkg = n.getPackageName();
@@ -910,7 +959,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}, false /* afterKeyguardGone */);
}
- private void bindGuts(ExpandableNotificationRow row) {
+ private void bindGuts(final ExpandableNotificationRow row) {
row.inflateGuts();
final StatusBarNotification sbn = row.getStatusBarNotification();
PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
@@ -954,11 +1003,25 @@ public abstract class BaseStatusBar extends SystemUI implements
@Override
public void onClick(View v) {
guts.saveImportance(sbn);
- dismissPopups();
+
+ int[] rowLocation = new int[2];
+ int[] doneLocation = new int[2];
+ row.getLocationOnScreen(rowLocation);
+ v.getLocationOnScreen(doneLocation);
+
+ final int centerX = v.getWidth() / 2;
+ final int centerY = v.getHeight() / 2;
+ final int x = doneLocation[0] - rowLocation[0] + centerX;
+ final int y = doneLocation[1] - rowLocation[1] + centerY;
+ dismissPopups(x, y);
}
});
- guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
+ guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey()));
+ }
+
+ protected GearDisplayedListener getGearDisplayedListener() {
+ return this;
}
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
@@ -973,7 +1036,7 @@ public abstract class BaseStatusBar extends SystemUI implements
return false;
}
- ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
bindGuts(row);
// Assume we are a status_bar_notification_row
@@ -991,12 +1054,12 @@ public abstract class BaseStatusBar extends SystemUI implements
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
- // ensure that it's layouted but not visible until actually laid out
+ // ensure that it's laid but not visible until actually laid out
guts.setVisibility(View.INVISIBLE);
- // Post to ensure the the guts are properly layed out.
+ // Post to ensure the the guts are properly laid out.
guts.post(new Runnable() {
public void run() {
- dismissPopups();
+ dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */);
guts.setVisibility(View.VISIBLE);
final double horz = Math.max(guts.getWidth() - x, x);
final double vert = Math.max(guts.getHeight() - y, y);
@@ -1005,6 +1068,14 @@ public abstract class BaseStatusBar extends SystemUI implements
= 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);
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
@@ -1016,11 +1087,20 @@ public abstract class BaseStatusBar extends SystemUI implements
};
}
+ @Override
+ public void onGearDisplayed(ExpandableNotificationRow row) {
+ mNotificationGearDisplayed = row;
+ }
+
public void dismissPopups() {
- dismissPopups(-1, -1);
+ dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */);
}
private void dismissPopups(int x, int y) {
+ dismissPopups(x, y, true /* resetGear */);
+ }
+
+ public void dismissPopups(int x, int y, boolean resetGear) {
if (mNotificationGutsExposed != null) {
final NotificationGuts v = mNotificationGutsExposed;
mNotificationGutsExposed = null;
@@ -1048,6 +1128,10 @@ public abstract class BaseStatusBar extends SystemUI implements
v.setExposed(false);
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
}
+ if (resetGear && mNotificationGearDisplayed != null) {
+ mNotificationGearDisplayed.resetTranslation();
+ mNotificationGearDisplayed = null;
+ }
}
@Override
@@ -1071,6 +1155,11 @@ public abstract class BaseStatusBar extends SystemUI implements
}
@Override
+ public void toggleSplitScreen() {
+ toggleSplitScreenMode();
+ }
+
+ @Override
public void preloadRecentApps() {
int msg = MSG_PRELOAD_RECENT_APPS;
mHandler.removeMessages(msg);
@@ -1140,6 +1229,13 @@ public abstract class BaseStatusBar extends SystemUI implements
}
};
+ /**
+ * Toggle docking the app window
+ *
+ * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
+ */
+ protected abstract boolean toggleSplitScreenMode();
+
/** Proxy for RecentsComponent */
protected void showRecents(boolean triggeredFromAltTab) {
@@ -1273,6 +1369,8 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
+ protected void onLockedRemoteInput(ExpandableNotificationRow row, View clickedView) {}
+
@Override
public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
}
@@ -1584,6 +1682,12 @@ public abstract class BaseStatusBar extends SystemUI implements
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
@@ -1793,7 +1897,7 @@ public abstract class BaseStatusBar extends SystemUI implements
return entry;
}
- protected StatusBarIconView createIcon(StatusBarNotification sbn) {
+ public StatusBarIconView createIcon(StatusBarNotification sbn) {
// Construct the icon.
Notification n = sbn.getNotification();
final StatusBarIconView iconView = new StatusBarIconView(mContext,
@@ -1909,6 +2013,10 @@ public abstract class BaseStatusBar extends SystemUI implements
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,
@@ -1918,7 +2026,14 @@ public abstract class BaseStatusBar extends SystemUI implements
null /* admin */, mCurrentUserId);
final boolean allowedByDpm = (dpmFlags
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
+
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+
setShowLockscreenNotifications(show && allowedByDpm);
+ setLockScreenAllowRemoteInput(remoteInput);
}
protected abstract void setAreThereNotifications();
@@ -2049,15 +2164,21 @@ public abstract class BaseStatusBar extends SystemUI implements
protected void updatePublicContentView(Entry entry,
StatusBarNotification sbn) {
final RemoteViews publicContentView = entry.cachedPublicContentView;
- if (publicContentView != null && entry.getPublicContentView() != null) {
+ View inflatedView = entry.getPublicContentView();
+ if (entry.autoRedacted && publicContentView != null && inflatedView != null) {
final boolean disabledByPolicy =
!adminAllowsUnredactedNotifications(entry.notification.getUserId());
- publicContentView.setTextViewText(android.R.id.title,
- mContext.getString(disabledByPolicy
- ? com.android.internal.R.string.notification_hidden_by_policy_text
- : com.android.internal.R.string.notification_hidden_text));
- publicContentView.reapply(sbn.getPackageContext(mContext),
- entry.getPublicContentView(), mOnClickHandler);
+ 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);
+ }
}
}
@@ -2080,44 +2201,53 @@ public abstract class BaseStatusBar extends SystemUI implements
return false;
}
- if (isSnoozedPackage(sbn)) {
- if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
- return false;
+ boolean inUse = mPowerManager.isScreenOn()
+ && (!mStatusBarKeyguardViewManager.isShowing()
+ || mStatusBarKeyguardViewManager.isOccluded())
+ && !mStatusBarKeyguardViewManager.isInputRestricted();
+ try {
+ inUse = inUse && !mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.d(TAG, "failed to query dream manager", e);
}
- if (entry.hasJustLaunchedFullScreenIntent()) {
- if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
+ if (!inUse) {
+ if (DEBUG) {
+ Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
+ }
return false;
}
- if (sbn.getNotification().fullScreenIntent != null
- && mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
+ 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 (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
- if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+ if (isSnoozedPackage(sbn)) {
+ if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
return false;
}
- if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_MAX) {
+ if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
return false;
}
- boolean inUse = mPowerManager.isScreenOn()
- && (!mStatusBarKeyguardViewManager.isShowing()
- || mStatusBarKeyguardViewManager.isOccluded())
- && !mStatusBarKeyguardViewManager.isInputRestricted();
- try {
- inUse = inUse && !mDreamManager.isDreaming();
- } catch (RemoteException e) {
- Log.d(TAG, "failed to query dream manager", e);
+ if (sbn.getNotification().fullScreenIntent != null) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
+ return false;
+ } else {
+ return true;
+ }
}
- if (DEBUG) Log.d(TAG, "peek if device in use: " + inUse);
- return inUse;
+
+ return true;
}
protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 71347c4ba611..6a984887931d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -17,12 +17,14 @@
package com.android.systemui.statusbar;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Pair;
+import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
@@ -70,6 +72,7 @@ public class CommandQueue extends IStatusBar.Stub {
private static final int MSG_ADD_QS_TILE = 27 << MSG_SHIFT;
private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT;
private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT;
+ private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -94,13 +97,15 @@ public class CommandQueue extends IStatusBar.Stub {
public void animateExpandNotificationsPanel();
public void animateCollapsePanels(int flags);
public void animateExpandSettingsPanel(String obj);
- public void setSystemUiVisibility(int vis, int mask);
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds);
public void topAppWindowChanged(boolean visible);
public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
public void showRecentApps(boolean triggeredFromAltTab);
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
public void toggleRecentApps();
+ public void toggleSplitScreen();
public void preloadRecentApps();
public void toggleKeyboardShortcutsMenu();
public void cancelPreloadRecentApps();
@@ -169,11 +174,19 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void setSystemUiVisibility(int vis, int mask) {
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
synchronized (mLock) {
// Don't coalesce these, since it might have one time flags set such as
// STATUS_BAR_UNHIDE which might get lost.
- mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = vis;
+ args.argi2 = fullscreenStackVis;
+ args.argi3 = dockedStackVis;
+ args.argi4 = mask;
+ args.arg1 = fullscreenStackBounds;
+ args.arg2 = dockedStackBounds;
+ mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget();
}
}
@@ -212,6 +225,13 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
+ public void toggleSplitScreen() {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_TOGGLE_APP_SPLIT_SCREEN);
+ mHandler.obtainMessage(MSG_TOGGLE_APP_SPLIT_SCREEN, 0, 0, null).sendToTarget();
+ }
+ }
+
public void toggleRecentApps() {
synchronized (mLock) {
mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
@@ -377,7 +397,10 @@ public class CommandQueue extends IStatusBar.Stub {
mCallbacks.animateExpandSettingsPanel((String) msg.obj);
break;
case MSG_SET_SYSTEMUI_VISIBILITY:
- mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
+ SomeArgs args = (SomeArgs) msg.obj;
+ mCallbacks.setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
+ args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+ args.recycle();
break;
case MSG_TOP_APP_WINDOW_CHANGED:
mCallbacks.topAppWindowChanged(msg.arg1 != 0);
@@ -450,6 +473,9 @@ public class CommandQueue extends IStatusBar.Stub {
case MSG_CLICK_QS_TILE:
mCallbacks.clickTile((ComponentName) msg.obj);
break;
+ case MSG_TOGGLE_APP_SPLIT_SCREEN:
+ mCallbacks.toggleSplitScreen();
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 212d290a3cf4..123dc699e593 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar;
import android.view.View;
import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* A helper to fade views in and out.
@@ -44,7 +45,34 @@ public class CrossFadeHelper {
if (view.hasOverlappingRendering()) {
view.animate().withLayer();
}
+ }
+
+ public static void fadeOut(View view, float fadeOutAmount) {
+ view.animate().cancel();
+ if (fadeOutAmount == 1.0f) {
+ view.setVisibility(View.INVISIBLE);
+ } else if (view.getVisibility() == View.INVISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+ fadeOutAmount = mapToFadeDuration(fadeOutAmount);
+ float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
+ view.setAlpha(alpha);
+ updateLayerType(view, alpha);
+ }
+ private static float mapToFadeDuration(float fadeOutAmount) {
+ // Assuming a linear interpolator, we can easily map it to our new duration
+ float endPoint = (float) ANIMATION_DURATION_LENGTH
+ / (float) StackStateAnimator.ANIMATION_DURATION_STANDARD;
+ return Math.min(fadeOutAmount / endPoint, 1.0f);
+ }
+
+ private static void updateLayerType(View view, float alpha) {
+ if (view.hasOverlappingRendering() && alpha > 0.0f && alpha < 1.0f) {
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) {
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
}
public static void fadeIn(final View view) {
@@ -62,4 +90,15 @@ public class CrossFadeHelper {
view.animate().withLayer();
}
}
+
+ public static void fadeIn(View view, float fadeInAmount) {
+ view.animate().cancel();
+ if (view.getVisibility() == View.INVISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+ fadeInAmount = mapToFadeDuration(fadeInAmount);
+ float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
+ view.setAlpha(alpha);
+ updateLayerType(view, alpha);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7f1316fe2de7..e109b0901532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,6 +16,12 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Notification;
import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -25,6 +31,7 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -44,17 +51,18 @@ import com.android.systemui.statusbar.stack.StackScrollState;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
+import java.util.ArrayList;
import java.util.List;
public class ExpandableNotificationRow extends ActivatableNotificationView {
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
- private final int mNotificationMinHeightLegacy;
- private final int mMaxHeadsUpHeightLegacy;
- private final int mMaxHeadsUpHeight;
- private final int mNotificationMinHeight;
- private final int mNotificationMaxHeight;
+ private int mNotificationMinHeightLegacy;
+ private int mMaxHeadsUpHeightLegacy;
+ private int mMaxHeadsUpHeight;
+ private int mNotificationMinHeight;
+ private int mNotificationMaxHeight;
/** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable;
@@ -72,6 +80,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
/** Are we showing the "public" version */
private boolean mShowingPublic;
private boolean mSensitive;
+ private boolean mSensitiveHiddenInGeneral;
private boolean mShowingPublicInitialized;
private boolean mHideSensitiveForIntrinsicHeight;
@@ -86,6 +95,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
private boolean mOnKeyguard;
+ private AnimatorSet mTranslateAnim;
+ private ArrayList<View> mTranslateableViews;
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private int mMaxExpandHeight;
@@ -95,6 +106,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private ExpansionLogger mLogger;
private String mLoggingKey;
private boolean mWasReset;
+ private NotificationSettingsIconRow mSettingsIconRow;
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
@@ -107,6 +119,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mChildrenExpanded;
private boolean mIsSummaryWithChildren;
private NotificationChildrenContainer mChildrenContainer;
+ private ViewStub mSettingsIconRowStub;
private ViewStub mGutsStub;
private boolean mIsSystemChildExpanded;
private boolean mIsPinned;
@@ -239,7 +252,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
!= com.android.internal.R.id.status_bar_latest_event_content;
int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
: mMaxHeadsUpHeight;
- mMaxViewHeight = mNotificationMaxHeight;
mPrivateLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
mPublicLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
}
@@ -328,6 +340,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
@Override
+ protected boolean handleSlideBack() {
+ if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
+ animateTranslateNotification(0 /* targetLeft */);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
protected boolean shouldHideBackground() {
return super.shouldHideBackground() || mShowNoBackground;
}
@@ -499,6 +520,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mPrivateLayout.getNotificationHeader();
}
+ private NotificationHeaderView getVisibleNotificationHeader() {
+ if (mNotificationHeader != null) {
+ return mNotificationHeader;
+ }
+ return getShowingLayout().getVisibleNotificationHeader();
+ }
+
public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
mOnExpandClickListener = onExpandClickListener;
}
@@ -507,6 +535,40 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mHeadsUpManager = headsUpManager;
}
+ public void reInflateViews() {
+ initDimens();
+ if (mIsSummaryWithChildren) {
+ removeView(mNotificationHeader);
+ mNotificationHeader = null;
+ recreateNotificationHeader();
+ if (mChildrenContainer != null) {
+ mChildrenContainer.reInflateViews();
+ }
+ }
+ if (mGuts != null) {
+ View oldGuts = mGuts;
+ int index = indexOfChild(oldGuts);
+ removeView(oldGuts);
+ mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_guts, this, false);
+ 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.setVisibility(oldSettings.getVisibility());
+ addView(mSettingsIconRow, settingsIndex);
+
+ }
+ mPrivateLayout.reInflateViews();
+ mPublicLayout.reInflateViews();
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -514,16 +576,27 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
mFalsingManager = FalsingManager.getInstance(context);
- mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
- R.dimen.notification_min_height_legacy);
- mNotificationMinHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_min_height);
- mNotificationMaxHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_max_height);
- mMaxHeadsUpHeightLegacy = getResources().getDimensionPixelSize(
+ initDimens();
+ }
+
+ private void initDimens() {
+ mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
+ mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
+ mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
+ mMaxHeadsUpHeightLegacy = getFontScaledHeight(
R.dimen.notification_max_heads_up_height_legacy);
- mMaxHeadsUpHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_max_heads_up_height);
+ mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
+ }
+
+ /**
+ * @param dimenId the dimen to look up
+ * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
+ */
+ private int getFontScaledHeight(int dimenId) {
+ int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
+ float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
+ getResources().getDisplayMetrics().density);
+ return (int) (dimensionPixelSize * factor);
}
/**
@@ -533,7 +606,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void reset() {
super.reset();
final boolean wasExpanded = isExpanded();
- mMaxViewHeight = 0;
mExpandable = false;
mHasUserChangedExpansion = false;
mUserLocked = false;
@@ -545,6 +617,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPublicLayout.reset(mIsHeadsUp);
mPrivateLayout.reset(mIsHeadsUp);
resetHeight();
+ resetTranslation();
logExpansionEvent(false, wasExpanded);
}
@@ -568,6 +641,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPrivateLayout.setExpandClickListener(mExpandClickListener);
mPrivateLayout.setContainingNotification(this);
mPublicLayout.setExpandClickListener(mExpandClickListener);
+ mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
+ mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+ @Override
+ public void onInflate(ViewStub stub, View inflated) {
+ mSettingsIconRow = (NotificationSettingsIconRow) inflated;
+ mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ }
+ });
mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
@@ -585,9 +666,89 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void onInflate(ViewStub stub, View inflated) {
mChildrenContainer = (NotificationChildrenContainer) inflated;
mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
+ mTranslateableViews.add(mChildrenContainer);
}
});
mVetoButton = findViewById(R.id.veto);
+
+ // Add the views that we translate to reveal the gear
+ mTranslateableViews = new ArrayList<View>();
+ for (int i = 0; i < getChildCount(); i++) {
+ mTranslateableViews.add(getChildAt(i));
+ }
+ // Remove views that don't translate
+ mTranslateableViews.remove(mVetoButton);
+ mTranslateableViews.remove(mSettingsIconRowStub);
+ mTranslateableViews.remove(mChildrenContainerStub);
+ mTranslateableViews.remove(mGutsStub);
+ }
+
+ public void setTranslationForOutline(float translationX) {
+ setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
+ }
+
+ public void resetTranslation() {
+ if (mTranslateableViews != null) {
+ for (int i = 0; i < mTranslateableViews.size(); i++) {
+ mTranslateableViews.get(i).setTranslationX(0);
+ }
+ setTranslationForOutline(0);
+ }
+ if (mSettingsIconRow != null) {
+ mSettingsIconRow.resetState();
+ }
+ }
+
+ public void animateTranslateNotification(final float leftTarget) {
+ if (mTranslateAnim != null) {
+ mTranslateAnim.cancel();
+ }
+ AnimatorSet set = new AnimatorSet();
+ if (mTranslateableViews != null) {
+ for (int i = 0; i < mTranslateableViews.size(); i++) {
+ final View animView = mTranslateableViews.get(i);
+ final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
+ animView, "translationX", leftTarget);
+ if (i == 0) {
+ translateAnim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setTranslationForOutline((float) animation.getAnimatedValue());
+ }
+ });
+ }
+ translateAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ if (mSettingsIconRow != null && leftTarget == 0) {
+ mSettingsIconRow.resetState();
+ }
+ mTranslateAnim = null;
+ }
+ });
+ set.play(translateAnim);
+ }
+ }
+ mTranslateAnim = set;
+ set.start();
+ }
+
+ public float getSpaceForGear() {
+ if (mSettingsIconRow != null) {
+ return mSettingsIconRow.getSpaceForGear();
+ }
+ return 0;
+ }
+
+ public NotificationSettingsIconRow getSettingsRow() {
+ if (mSettingsIconRow == null) {
+ mSettingsIconRowStub.inflate();
+ }
+ return mSettingsIconRow;
+ }
+
+ public ArrayList<View> getContentViews() {
+ return mTranslateableViews;
}
public void inflateGuts() {
@@ -706,6 +867,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setUserLocked(boolean userLocked) {
mUserLocked = userLocked;
+ mPrivateLayout.setUserExpanding(userLocked);
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setUserLocked(userLocked);
+ }
}
/**
@@ -744,7 +909,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mIsSummaryWithChildren) {
mChildrenContainer.updateGroupOverflow();
}
- notifyHeightChanged(false /* needsAnimation */);
+ notifyHeightChanged(false /* needsAnimation */);
}
}
}
@@ -880,8 +1045,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
}
- public void setSensitive(boolean sensitive) {
+ public void setSensitive(boolean sensitive, boolean hideSensitive) {
mSensitive = sensitive;
+ mSensitiveHiddenInGeneral = hideSensitive;
}
public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
@@ -947,9 +1113,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ public boolean mustStayOnScreen() {
+ return mIsHeadsUp;
+ }
+
private void updateClearability() {
// public versions cannot be dismissed
- mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
+ mVetoButton.setVisibility(isClearable() && (!mShowingPublic
+ || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
}
public void setChildrenExpanded(boolean expanded, boolean animate) {
@@ -1003,13 +1174,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public void setActualHeight(int height, boolean notifyListeners) {
super.setActualHeight(height, notifyListeners);
+ if (mGuts != null && mGuts.areGutsExposed()) {
+ mGuts.setActualHeight(height);
+ return;
+ }
int contentHeight = Math.max(getMinHeight(), height);
mPrivateLayout.setContentHeight(contentHeight);
mPublicLayout.setContentHeight(contentHeight);
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setActualHeight(height);
+ }
if (mGuts != null) {
mGuts.setActualHeight(height);
}
- invalidate();
}
@Override
@@ -1065,6 +1242,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
mNotificationHeader);
addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
+ mTranslateableViews.add(mNotificationHeader);
} else {
header.reapply(getContext(), mNotificationHeader);
mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
@@ -1090,7 +1268,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return mMaxExpandHeight != 0;
}
- private NotificationContentView getShowingLayout() {
+ public NotificationContentView getShowingLayout() {
return mShowingPublic ? mPublicLayout : mPrivateLayout;
}
@@ -1126,15 +1304,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
@Override
- public boolean needsIncreasedPadding() {
- return mIsSummaryWithChildren && isGroupExpanded();
+ public float getIncreasedPaddingAmount() {
+ if (mIsSummaryWithChildren) {
+ if (isGroupExpanded()) {
+ return 1.0f;
+ } else if (isUserLocked()) {
+ return mChildrenContainer.getChildExpandFraction();
+ }
+ }
+ return 0.0f;
}
@Override
protected boolean disallowSingleClick(MotionEvent event) {
float x = event.getX();
float y = event.getY();
- NotificationHeaderView header = getNotificationHeader();
+ NotificationHeaderView header = getVisibleNotificationHeader();
if (header != null) {
return header.isInTouchRect(x, y);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 44c6a5d36c64..f98e87d4848c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -70,6 +70,11 @@ public abstract class ExpandableOutlineView extends ExpandableView {
}
}
+ @Override
+ public float getOutlineAlpha() {
+ return mOutlineAlpha;
+ }
+
protected void setOutlineRect(RectF rect) {
if (rect != null) {
setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
@@ -80,9 +85,19 @@ public abstract class ExpandableOutlineView extends ExpandableView {
}
}
+ @Override
+ public int getOutlineTranslation() {
+ return mCustomOutline ? mOutlineRect.left : 0;
+ }
+
protected void setOutlineRect(float left, float top, float right, float bottom) {
+ setOutlineRect(true, left, top, right, bottom);
+ }
+
+ protected void setOutlineRect(boolean clipToOutline, float left, float top, float right,
+ float bottom) {
mCustomOutline = true;
- setClipToOutline(true);
+ setClipToOutline(clipToOutline);
mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index a0fb34aecbf9..1ff87f551186 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -24,7 +24,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import com.android.systemui.R;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
@@ -35,7 +34,6 @@ import java.util.ArrayList;
public abstract class ExpandableView extends FrameLayout {
protected OnHeightChangedListener mOnHeightChangedListener;
- protected int mMaxViewHeight;
private int mActualHeight;
protected int mClipTopAmount;
private boolean mActualHeightInitialized;
@@ -49,8 +47,6 @@ public abstract class ExpandableView extends FrameLayout {
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
- mMaxViewHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_max_height);
}
@Override
@@ -395,10 +391,29 @@ public abstract class ExpandableView extends FrameLayout {
public void setShadowAlpha(float shadowAlpha) {
}
- public boolean needsIncreasedPadding() {
+ /**
+ * @return an amount between 0 and 1 of increased padding that this child needs
+ */
+ public float getIncreasedPaddingAmount() {
+ return 0.0f;
+ }
+
+ public boolean mustStayOnScreen() {
return false;
}
+ public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
+ int outlineTranslation) {
+ }
+
+ public float getOutlineAlpha() {
+ return 0.0f;
+ }
+
+ public int getOutlineTranslation() {
+ return 0;
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 76e522e336ca..7c1116170ec3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -48,6 +48,7 @@ public class NotificationContentView extends FrameLayout {
private static final int VISIBLE_TYPE_EXPANDED = 1;
private static final int VISIBLE_TYPE_HEADSUP = 2;
private static final int VISIBLE_TYPE_SINGLELINE = 3;
+ private static final int UNDEFINED = -1;
private final Rect mClipBounds = new Rect();
private final int mMinContractedHeight;
@@ -102,6 +103,8 @@ public class NotificationContentView extends FrameLayout {
private boolean mExpandable;
private boolean mClipToActualHeight = true;
private ExpandableNotificationRow mContainingNotification;
+ private int mTransformationStartVisibleType;
+ private boolean mUserExpanding;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -144,11 +147,11 @@ public class NotificationContentView extends FrameLayout {
}
if (mContractedChild != null) {
int heightSpec;
+ int size = Math.min(maxSize, mSmallHeight);
if (shouldContractedBeFixedSize()) {
- int size = Math.min(maxSize, mSmallHeight);
heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
} else {
- heightSpec = MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST);
+ heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
}
mContractedChild.measure(widthMeasureSpec, heightSpec);
int measuredHeight = mContractedChild.getMeasuredHeight();
@@ -248,14 +251,16 @@ public class NotificationContentView extends FrameLayout {
public void reset(boolean resetActualHeight) {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
+ removeView(mContractedChild);
}
if (mExpandedChild != null) {
mExpandedChild.animate().cancel();
+ removeView(mExpandedChild);
}
if (mHeadsUpChild != null) {
mHeadsUpChild.animate().cancel();
+ removeView(mHeadsUpChild);
}
- removeAllViews();
mContractedChild = null;
mExpandedChild = null;
mHeadsUpChild = null;
@@ -347,6 +352,41 @@ public class NotificationContentView extends FrameLayout {
invalidateOutline();
}
+ private void updateContentTransformation() {
+ int visibleType = calculateVisibleType();
+ if (visibleType != mVisibleType) {
+ // A new transformation starts
+ mTransformationStartVisibleType = mVisibleType;
+ final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
+ final TransformableView hiddenView = getTransformableViewForVisibleType(
+ mTransformationStartVisibleType);
+ shownView.transformFrom(hiddenView, 0.0f);
+ getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
+ hiddenView.transformTo(shownView, 0.0f);
+ mVisibleType = visibleType;
+ }
+ if (mTransformationStartVisibleType != UNDEFINED
+ && mVisibleType != mTransformationStartVisibleType) {
+ final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
+ final TransformableView hiddenView = getTransformableViewForVisibleType(
+ mTransformationStartVisibleType);
+ float transformationAmount = calculateTransformationAmount();
+ shownView.transformFrom(hiddenView, transformationAmount);
+ hiddenView.transformTo(shownView, transformationAmount);
+ } else {
+ updateViewVisibilities(visibleType);
+ }
+ }
+
+ private float calculateTransformationAmount() {
+ int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
+ int endHeight = getViewForVisibleType(mVisibleType).getHeight();
+ int progress = Math.abs(mContentHeight - startHeight);
+ int totalDistance = Math.abs(endHeight - startHeight);
+ float amount = (float) progress / (float) totalDistance;
+ return Math.min(1.0f, amount);
+ }
+
public int getContentHeight() {
return mContentHeight;
}
@@ -361,10 +401,14 @@ public class NotificationContentView extends FrameLayout {
}
public int getMinHeight() {
- if (mIsChildInGroup && !isGroupExpanded()) {
- return mSingleLineView.getHeight();
- } else {
+ return getMinHeight(false /* likeGroupExpanded */);
+ }
+
+ public int getMinHeight(boolean likeGroupExpanded) {
+ if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
return mContractedChild.getHeight();
+ } else {
+ return mSingleLineView.getHeight();
}
}
@@ -395,6 +439,10 @@ public class NotificationContentView extends FrameLayout {
if (mContractedChild == null) {
return;
}
+ if (mUserExpanding) {
+ updateContentTransformation();
+ return;
+ }
int visibleType = calculateVisibleType();
if (visibleType != mVisibleType || force) {
if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
@@ -473,17 +521,45 @@ public class NotificationContentView extends FrameLayout {
}
}
+ private NotificationViewWrapper getCurrentVisibleWrapper() {
+ switch (mVisibleType) {
+ case VISIBLE_TYPE_EXPANDED:
+ return mExpandedWrapper;
+ case VISIBLE_TYPE_HEADSUP:
+ return mHeadsUpWrapper;
+ case VISIBLE_TYPE_CONTRACTED:
+ return mContractedWrapper;
+ default:
+ return null;
+ }
+ }
+
/**
* @return one of the static enum types in this view, calculated form the current state
*/
private int calculateVisibleType() {
- boolean noExpandedChild = mExpandedChild == null;
-
+ if (mUserExpanding) {
+ int height = !mIsChildInGroup || isGroupExpanded()
+ || mContainingNotification.isExpanded()
+ ? mContainingNotification.getMaxContentHeight()
+ : mContainingNotification.getShowingLayout().getMinHeight();
+ int expandedVisualType = getVisualTypeForHeight(height);
+ int collapsedVisualType = getVisualTypeForHeight(
+ mContainingNotification.getMinExpandHeight());
+ return mTransformationStartVisibleType == collapsedVisualType
+ ? expandedVisualType
+ : collapsedVisualType;
+ }
int viewHeight = Math.min(mContentHeight, mContainingNotification.getIntrinsicHeight());
+ return getVisualTypeForHeight(viewHeight);
+ }
+
+ private int getVisualTypeForHeight(float viewHeight) {
+ boolean noExpandedChild = mExpandedChild == null;
if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
return VISIBLE_TYPE_EXPANDED;
}
- if (mIsChildInGroup && !isGroupExpanded()) {
+ if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
return VISIBLE_TYPE_SINGLELINE;
}
@@ -494,7 +570,8 @@ public class NotificationContentView extends FrameLayout {
return VISIBLE_TYPE_EXPANDED;
}
} else {
- if (viewHeight <= mContractedChild.getHeight() || noExpandedChild) {
+ if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
+ && (!mIsChildInGroup || !mContainingNotification.isExpanded()))) {
return VISIBLE_TYPE_CONTRACTED;
} else {
return VISIBLE_TYPE_EXPANDED;
@@ -507,7 +584,9 @@ public class NotificationContentView extends FrameLayout {
}
public void setDark(boolean dark, boolean fade, long delay) {
- if (mDark == dark || mContractedChild == null) return;
+ if (mContractedChild == null) {
+ return;
+ }
mDark = dark;
dark = dark && !mShowingLegacyBackground;
if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
@@ -555,7 +634,6 @@ public class NotificationContentView extends FrameLayout {
selectLayout(false /* animate */, true /* force */);
if (mContractedChild != null) {
mContractedWrapper.notifyContentUpdated(entry.notification);
- mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
}
if (mExpandedChild != null) {
mExpandedWrapper.notifyContentUpdated(entry.notification);
@@ -563,12 +641,16 @@ public class NotificationContentView extends FrameLayout {
if (mHeadsUpChild != null) {
mHeadsUpWrapper.notifyContentUpdated(entry.notification);
}
+ setDark(mDark, false /* animate */, 0 /* delay */);
}
private void updateSingleLineView() {
if (mIsChildInGroup) {
mSingleLineView = mHybridViewManager.bindFromNotification(
mSingleLineView, mStatusBarNotification.getNotification());
+ } else if (mSingleLineView != null) {
+ removeView(mSingleLineView);
+ mSingleLineView = null;
}
}
@@ -678,6 +760,11 @@ public class NotificationContentView extends FrameLayout {
return header;
}
+ public NotificationHeaderView getVisibleNotificationHeader() {
+ NotificationViewWrapper wrapper = getCurrentVisibleWrapper();
+ return wrapper == null ? null : wrapper.getNotificationHeader();
+ }
+
public void setContainingNotification(ExpandableNotificationRow containingNotification) {
mContainingNotification = containingNotification;
}
@@ -685,4 +772,23 @@ public class NotificationContentView extends FrameLayout {
public void requestSelectLayout(boolean needsAnimation) {
selectLayout(needsAnimation, false);
}
+
+ public void reInflateViews() {
+ if (mIsChildInGroup && mSingleLineView != null) {
+ removeView(mSingleLineView);
+ mSingleLineView = null;
+ updateSingleLineView();
+ }
+ }
+
+ public void setUserExpanding(boolean userExpanding) {
+ mUserExpanding = userExpanding;
+ if (userExpanding) {
+ mTransformationStartVisibleType = mVisibleType;
+ } else {
+ mTransformationStartVisibleType = UNDEFINED;
+ mVisibleType = calculateVisibleType();
+ updateViewVisibilities(mVisibleType);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 2cacb8aedd65..7cb91279b00a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -34,6 +34,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Objects;
/**
* The list of currently displaying notifications.
@@ -110,18 +111,24 @@ public class NotificationData {
if (updatedNotification != null) {
final Notification.Builder updatedNotificationBuilder
= Notification.Builder.recoverBuilder(ctx, updatedNotification);
- final RemoteViews newContentView = updatedNotificationBuilder.makeContentView();
+ final RemoteViews newContentView = updatedNotificationBuilder.createContentView();
final RemoteViews newBigContentView =
- updatedNotificationBuilder.makeBigContentView();
+ updatedNotificationBuilder.createBigContentView();
final RemoteViews newHeadsUpContentView =
- updatedNotificationBuilder.makeHeadsUpContentView();
+ updatedNotificationBuilder.createHeadsUpContentView();
final RemoteViews newPublicNotification
= updatedNotificationBuilder.makePublicContentView();
+ boolean sameCustomView = Objects.equals(
+ notification.getNotification().extras.getBoolean(
+ Notification.EXTRA_CONTAINS_CUSTOM_VIEW),
+ updatedNotification.extras.getBoolean(
+ Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
applyInPlace = compareRemoteViews(cachedContentView, newContentView)
&& compareRemoteViews(cachedBigContentView, newBigContentView)
&& compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
- && compareRemoteViews(cachedPublicContentView, newPublicNotification);
+ && compareRemoteViews(cachedPublicContentView, newPublicNotification)
+ && sameCustomView;
cachedPublicContentView = newPublicNotification;
cachedHeadsUpContentView = newHeadsUpContentView;
cachedBigContentView = newBigContentView;
@@ -130,9 +137,9 @@ public class NotificationData {
final Notification.Builder builder
= Notification.Builder.recoverBuilder(ctx, notification.getNotification());
- cachedContentView = builder.makeContentView();
- cachedBigContentView = builder.makeBigContentView();
- cachedHeadsUpContentView = builder.makeHeadsUpContentView();
+ cachedContentView = builder.createContentView();
+ cachedBigContentView = builder.createBigContentView();
+ cachedHeadsUpContentView = builder.createHeadsUpContentView();
cachedPublicContentView = builder.makePublicContentView();
applyInPlace = false;
@@ -196,11 +203,11 @@ public class NotificationData {
String mediaNotification = mEnvironment.getCurrentMediaNotificationKey();
- // PRIORITY_MIN media streams are allowed to drift to the bottom
+ // IMPORTANCE_MIN media streams are allowed to drift to the bottom
final boolean aMedia = a.key.equals(mediaNotification)
- && aImportance > Ranking.IMPORTANCE_LOW;
+ && aImportance > Ranking.IMPORTANCE_MIN;
final boolean bMedia = b.key.equals(mediaNotification)
- && bImportance > Ranking.IMPORTANCE_LOW;
+ && bImportance > Ranking.IMPORTANCE_MIN;
boolean aSystemMax = aImportance >= Ranking.IMPORTANCE_MAX &&
isSystemNotification(na);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 5abd1d5c4b03..1c16bdc0d7bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar;
import android.app.INotificationManager;
-import android.app.Notification;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -35,26 +34,35 @@ import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
/**
* The guts of a notification revealed when performing a long press.
*/
-public class NotificationGuts extends LinearLayout {
+public class NotificationGuts extends LinearLayout implements TunerService.Tunable {
+ public static final String SHOW_SLIDER = "show_importance_slider";
private Drawable mBackground;
private int mClipTopAmount;
private int mActualHeight;
private boolean mExposed;
- private RadioButton mApplyToTopic;
- private SeekBar mSeekBar;
- private Notification.Topic mTopic;
private INotificationManager mINotificationManager;
+ private int mStartingImportance;
+ private boolean mShowSlider;
+
+ private SeekBar mSeekBar;
+ private RadioButton mBlock;
+ private RadioButton mSilent;
+ private RadioButton mReset;
public NotificationGuts(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
+ TunerService.get(mContext).addTunable(this, SHOW_SLIDER);
}
@Override
@@ -101,45 +109,81 @@ public class NotificationGuts extends LinearLayout {
}
}
- void bindImportance(final StatusBarNotification sbn, final ExpandableNotificationRow row,
- final int importance) {
+ void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
+ final ExpandableNotificationRow row, final int importance) {
+ mStartingImportance = importance;
mINotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- mTopic = sbn.getNotification().getTopic() == null
- ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
- com.android.internal.R.string.default_notification_topic_label))
- : sbn.getNotification().getTopic();
- boolean doesAppUseTopics = false;
- try {
- doesAppUseTopics =
- mINotificationManager.doesAppUseTopics(sbn.getPackageName(), sbn.getUid());
- } catch (RemoteException e) {}
- final boolean appUsesTopics = doesAppUseTopics;
-
- mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
- if (appUsesTopics) {
- mApplyToTopic.setChecked(true);
- }
- final View applyToApp = row.findViewById(R.id.apply_to_app);
- final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
- final TextView topicTitle = ((TextView) row.findViewById(R.id.title));
- mSeekBar = (SeekBar) row.findViewById(R.id.seekbar);
boolean systemApp = false;
try {
- final PackageManager pm = BaseStatusBar.getPackageManagerForUser(
- getContext(), sbn.getUser().getIdentifier());
final PackageInfo info =
pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
systemApp = Utils.isSystemPackage(pm, info);
} catch (PackageManager.NameNotFoundException e) {
// unlikely.
}
+
+ final View importanceSlider = row.findViewById(R.id.importance_slider);
+ final View importanceButtons = row.findViewById(R.id.importance_buttons);
+ if (mShowSlider) {
+ bindSlider(importanceSlider, sbn, systemApp);
+ importanceSlider.setVisibility(View.VISIBLE);
+ importanceButtons.setVisibility(View.GONE);
+ } else {
+ bindToggles(importanceButtons, sbn, systemApp);
+ importanceButtons.setVisibility(View.VISIBLE);
+ importanceSlider.setVisibility(View.GONE);
+ }
+ }
+
+ void saveImportance(final StatusBarNotification sbn) {
+ int progress;
+ if (mSeekBar!= null && mSeekBar.isShown()) {
+ progress = mSeekBar.getProgress();
+ } else {
+ if (mBlock.isChecked()) {
+ progress = NotificationListenerService.Ranking.IMPORTANCE_NONE;
+ } else if (mSilent.isChecked()) {
+ progress = NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
+ } else {
+ progress = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ }
+ }
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
+ progress - mStartingImportance);
+ try {
+ mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress);
+ } catch (RemoteException e) {
+ // :(
+ }
+ }
+
+ private void bindToggles(final View importanceButtons, final StatusBarNotification sbn,
+ final boolean systemApp) {
+ mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
+ mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
+ mReset = (RadioButton) importanceButtons.findViewById(R.id.reset_importance);
if (systemApp) {
- ((ImageView) row.findViewById(R.id.low_importance)).getDrawable().setTint(
+ mBlock.setVisibility(View.GONE);
+ mReset.setText(mContext.getString(R.string.do_not_silence));
+ } else {
+ mReset.setText(mContext.getString(R.string.do_not_silence_block));
+ }
+ mReset.setChecked(true);
+ }
+
+ private void bindSlider(final View importanceSlider, final StatusBarNotification sbn,
+ final boolean systemApp) {
+ final TextView importanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary));
+ final TextView importanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
+ mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar);
+
+ if (systemApp) {
+ ((ImageView) importanceSlider.findViewById(R.id.low_importance)).getDrawable().setTint(
mContext.getColor(R.color.notification_guts_disabled_icon_tint));
}
final int minProgress = systemApp ?
- NotificationListenerService.Ranking.IMPORTANCE_LOW
+ NotificationListenerService.Ranking.IMPORTANCE_MIN
: NotificationListenerService.Ranking.IMPORTANCE_NONE;
mSeekBar.setMax(NotificationListenerService.Ranking.IMPORTANCE_MAX);
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -151,12 +195,7 @@ public class NotificationGuts extends LinearLayout {
}
updateTitleAndSummary(progress);
if (fromUser) {
- if (appUsesTopics) {
- mApplyToTopic.setVisibility(View.VISIBLE);
- mApplyToTopic.setText(
- mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
- applyToApp.setVisibility(View.VISIBLE);
- }
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_MODIFY_IMPORTANCE_SLIDER);
}
}
@@ -173,44 +212,39 @@ public class NotificationGuts extends LinearLayout {
private void updateTitleAndSummary(int progress) {
switch (progress) {
case NotificationListenerService.Ranking.IMPORTANCE_NONE:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_blocked));
- topicTitle.setText(mContext.getString(R.string.blocked_importance));
+ importanceTitle.setText(mContext.getString(R.string.blocked_importance));
+ break;
+ case NotificationListenerService.Ranking.IMPORTANCE_MIN:
+ importanceSummary.setText(mContext.getString(
+ R.string.notification_importance_min));
+ importanceTitle.setText(mContext.getString(R.string.min_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_LOW:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_low));
- topicTitle.setText(mContext.getString(R.string.low_importance));
+ importanceTitle.setText(mContext.getString(R.string.low_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_default));
- topicTitle.setText(mContext.getString(R.string.default_importance));
+ importanceTitle.setText(mContext.getString(R.string.default_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_high));
- topicTitle.setText(mContext.getString(R.string.high_importance));
+ importanceTitle.setText(mContext.getString(R.string.high_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_MAX:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_max));
- topicTitle.setText(mContext.getString(R.string.max_importance));
+ importanceTitle.setText(mContext.getString(R.string.max_importance));
break;
}
}
});
- mSeekBar.setProgress(importance);
- }
-
- void saveImportance(final StatusBarNotification sbn) {
- int progress = mSeekBar.getProgress();
- try {
- mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(),
- mApplyToTopic.isChecked() ? mTopic : null, progress);
- } catch (RemoteException e) {
- // :(
- }
+ mSeekBar.setProgress(mStartingImportance);
}
public void setActualHeight(int actualHeight) {
@@ -241,4 +275,11 @@ public class NotificationGuts extends LinearLayout {
public boolean areGutsExposed() {
return mExposed;
}
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (SHOW_SLIDER.equals(key)) {
+ mShowSlider = newValue != null && Integer.parseInt(newValue) != 0;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
new file mode 100644
index 000000000000..476e146d1859
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -0,0 +1,220 @@
+/*
+ * 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.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 {
+
+ public interface SettingsIconRowListener {
+ /**
+ * Called when the gear behind a notification is touched.
+ */
+ public void onGearTouched(ExpandableNotificationRow row, int x, int y);
+ }
+
+ 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 int[] mGearLocation = new int[2];
+ private int[] mParentLocation = new int[2];
+
+ 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);
+ resetState();
+ }
+
+ public void resetState() {
+ setGearAlpha(0f);
+ mAnimating = false;
+ setIconLocation(true /* on left */);
+ }
+
+ public void setGearListener(SettingsIconRowListener listener) {
+ mListener = listener;
+ }
+
+ public void setNotificationRowParent(ExpandableNotificationRow parent) {
+ mParent = parent;
+ }
+
+ public ExpandableNotificationRow getNotificationParent() {
+ return mParent;
+ }
+
+ private void setGearAlpha(float alpha) {
+ if (alpha == 0) {
+ mSettingsFadedIn = false; // Can fade in again once it's gone.
+ mGearIcon.setVisibility(View.INVISIBLE);
+ } else {
+ if (alpha == 1) {
+ mSettingsFadedIn = true;
+ }
+ mGearIcon.setVisibility(View.VISIBLE);
+ }
+ mGearIcon.setAlpha(alpha);
+ }
+
+ /**
+ * 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 mSettingsFadedIn;
+ }
+
+ public void cancelFadeAnimator() {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ }
+
+ public void updateSettingsIcons(final float transX, final float size) {
+ if (mAnimating || (mGearIcon.getAlpha() == 0)) {
+ // Don't adjust when animating or settings aren't visible
+ return;
+ }
+ setIconLocation(transX > 0 /* fromLeft */);
+ final float fadeThreshold = size * 0.3f;
+ final float absTrans = Math.abs(transX);
+ float desiredAlpha = 0;
+
+ 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) {
+ 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 onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mAnimating = false;
+ mSettingsFadedIn = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mAnimating = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mAnimating = false;
+ mSettingsFadedIn = true;
+ }
+ });
+ mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mFadeAnimator.setDuration(200);
+ mFadeAnimator.start();
+ }
+
+ private void setIconLocation(boolean onLeft) {
+ if (onLeft == mOnLeft) {
+ // Same side? Do nothing.
+ return;
+ }
+
+ setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
+ mOnLeft = onLeft;
+ }
+
+ @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);
+ // Top / bottom padding are not equal, need to subtract them to get center of gear.
+ final int centerY = (int) (mGearIcon.getHeight() - mGearIcon.getPaddingTop()
+ - mGearIcon.getPaddingBottom()) / 2 + mGearIcon.getPaddingTop();
+ 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/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 6801e5f1017d..c892b11e33fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -21,7 +21,9 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
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.telephony.SubscriptionInfo;
import android.util.ArraySet;
@@ -80,6 +82,7 @@ public class SignalClusterView
private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
private int mIconTint = Color.WHITE;
private float mDarkIntensity;
+ private final Rect mTintArea = new Rect();
ViewGroup mEthernetGroup, mWifiGroup;
View mNoSimsCombo;
@@ -88,6 +91,8 @@ public class SignalClusterView
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
+ private final int mMobileSignalGroupEndPadding;
+ private final int mMobileDataIconStartPadding;
private final int mWideTypeIconStartPadding;
private final int mSecondaryTelephonyPadding;
private final int mEndPadding;
@@ -111,6 +116,10 @@ public class SignalClusterView
super(context, attrs, defStyle);
Resources res = getResources();
+ mMobileSignalGroupEndPadding =
+ res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding);
+ mMobileDataIconStartPadding =
+ res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding);
mWideTypeIconStartPadding = res.getDimensionPixelSize(R.dimen.wide_type_icon_start_padding);
mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding);
mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding);
@@ -204,6 +213,10 @@ public class SignalClusterView
for (PhoneState state : mPhoneStates) {
mMobileSignalGroup.addView(state.mMobileGroup);
}
+
+ int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
+ mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0);
+
TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
apply();
@@ -490,23 +503,31 @@ public class SignalClusterView
}
}
- public void setIconTint(int tint, float darkIntensity) {
- boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity;
+ public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+ boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
+ || !mTintArea.equals(tintArea);
mIconTint = tint;
mDarkIntensity = darkIntensity;
+ mTintArea.set(tintArea);
if (changed && isAttachedToWindow()) {
applyIconTint();
}
}
private void applyIconTint() {
- setTint(mVpn, mIconTint);
- setTint(mAirplane, mIconTint);
- applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
- applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
- applyDarkIntensity(mDarkIntensity, mEthernet, mEthernetDark);
+ setTint(mVpn, StatusBarIconController.getTint(mTintArea, mVpn, mIconTint));
+ setTint(mAirplane, StatusBarIconController.getTint(mTintArea, mAirplane, mIconTint));
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
+ mNoSims, mNoSimsDark);
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
+ mWifi, mWifiDark);
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
+ mEthernet, mEthernetDark);
for (int i = 0; i < mPhoneStates.size(); i++) {
- mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
+ mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
}
}
@@ -567,9 +588,11 @@ public class SignalClusterView
// When this isn't next to wifi, give it some extra padding between the signals.
mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
0, 0, 0);
- mMobile.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+ mMobile.setPaddingRelative(
+ mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
0, 0, 0);
- mMobileDark.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+ mMobileDark.setPaddingRelative(
+ mIsMobileTypeIconWide ? mWideTypeIconStartPadding : mMobileDataIconStartPadding,
0, 0, 0);
if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
@@ -582,12 +605,19 @@ public class SignalClusterView
private void updateAnimatableIcon(ImageView view, int resId) {
maybeStopAnimatableDrawable(view);
- view.setImageResource(resId);
+ setIconForView(view, resId);
maybeStartAnimatableDrawable(view);
}
private void maybeStopAnimatableDrawable(ImageView view) {
Drawable drawable = view.getDrawable();
+
+ // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
+ // wrapper.
+ if (drawable instanceof ScalingDrawableWrapper) {
+ drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
+ }
+
if (drawable instanceof Animatable) {
Animatable ad = (Animatable) drawable;
if (ad.isRunning()) {
@@ -598,8 +628,18 @@ public class SignalClusterView
private void maybeStartAnimatableDrawable(ImageView view) {
Drawable drawable = view.getDrawable();
+
+ // Check if the icon has been scaled. If it has retrieve the actual drawable out of the
+ // wrapper.
+ if (drawable instanceof ScalingDrawableWrapper) {
+ drawable = ((ScalingDrawableWrapper) drawable).getDrawable();
+ }
+
if (drawable instanceof Animatable) {
Animatable ad = (Animatable) drawable;
+ if (ad instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) ad).forceAnimationOnUI();
+ }
if (!ad.isRunning()) {
ad.start();
}
@@ -613,9 +653,11 @@ public class SignalClusterView
}
}
- public void setIconTint(int tint, float darkIntensity) {
- applyDarkIntensity(darkIntensity, mMobile, mMobileDark);
- setTint(mMobileType, tint);
+ public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+ applyDarkIntensity(
+ StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
+ mMobile, mMobileDark);
+ setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
index 38b649746c6d..dd7c4c7a6a03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
@@ -27,9 +27,11 @@ public interface TransformableView {
int TRANSFORMING_VIEW_TEXT = 2;
int TRANSFORMING_VIEW_IMAGE = 3;
int TRANSFORMING_VIEW_PROGRESS = 4;
+ int TRANSFORMING_VIEW_ACTIONS = 5;
/**
* Get the current state of a view in a transform animation
+ *
* @param fadingView which view we are interested in
* @return the current transform state of this viewtype
*/
@@ -37,18 +39,37 @@ public interface TransformableView {
/**
* Transform to the given view
+ *
* @param notification the view to transform to
*/
void transformTo(TransformableView notification, Runnable endRunnable);
/**
+ * Transform to the given view by a specified amount.
+ *
+ * @param notification the view to transform to
+ * @param transformationAmount how much transformation should be done
+ */
+ void transformTo(TransformableView notification, float transformationAmount);
+
+ /**
* Transform to this view from the given view
+ *
* @param notification the view to transform from
*/
void transformFrom(TransformableView notification);
/**
+ * Transform to this view from the given view by a specified amount.
+ *
+ * @param notification the view to transform from
+ * @param transformationAmount how much transformation should be done
+ */
+ void transformFrom(TransformableView notification, float transformationAmount);
+
+ /**
* Set this view to be fully visible or gone
+ *
* @param visible
*/
void setVisible(boolean visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 63ff5aa06a1a..bf05d1d7d882 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -16,13 +16,17 @@
package com.android.systemui.statusbar;
-import android.os.Handler;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.TransformState;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.Stack;
@@ -33,9 +37,9 @@ public class ViewTransformationHelper implements TransformableView {
private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view;
- private final Handler mHandler = new Handler();
private ArrayMap<Integer, View> mTransformedViews = new ArrayMap<>();
private ArrayMap<Integer, CustomTransformation> mCustomTransformations = new ArrayMap<>();
+ private ValueAnimator mViewTransformationAnimation;
public void addTransformedView(int key, View transformedView) {
mTransformedViews.put(key, transformedView);
@@ -59,61 +63,123 @@ public class ViewTransformationHelper implements TransformableView {
}
@Override
- public void transformTo(TransformableView notification, Runnable endRunnable) {
- Runnable runnable = endRunnable;
+ public void transformTo(final TransformableView notification, final Runnable endRunnable) {
+ if (mViewTransformationAnimation != null) {
+ mViewTransformationAnimation.cancel();
+ }
+ mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ transformTo(notification, animation.getAnimatedFraction());
+ }
+ });
+ mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
+ mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ if (endRunnable != null) {
+ mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
+ public boolean mCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endRunnable.run();
+ if (!mCancelled) {
+ setVisible(false);
+ } else {
+ abortTransformations();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+ });
+ }
+ mViewTransformationAnimation.start();
+ }
+
+ @Override
+ public void transformTo(TransformableView notification, float transformationAmount) {
for (Integer viewType : mTransformedViews.keySet()) {
TransformState ownState = getCurrentState(viewType);
if (ownState != null) {
CustomTransformation customTransformation = mCustomTransformations.get(viewType);
if (customTransformation != null && customTransformation.transformTo(
- ownState, notification, runnable)) {
+ ownState, notification, transformationAmount)) {
ownState.recycle();
- runnable = null;
continue;
}
TransformState otherState = notification.getCurrentState(viewType);
if (otherState != null) {
- boolean run = ownState.transformViewTo(otherState, runnable);
+ ownState.transformViewTo(otherState, transformationAmount);
otherState.recycle();
- if (run) {
- runnable = null;
- }
} else {
// there's no other view available
- CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), runnable);
- runnable = null;
+ CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount);
}
ownState.recycle();
}
}
- if (runnable != null) {
- // We need to post, since the visible type is only set after the transformation is
- // started
- mHandler.post(runnable);
+ }
+
+ @Override
+ public void transformFrom(final TransformableView notification) {
+ if (mViewTransformationAnimation != null) {
+ mViewTransformationAnimation.cancel();
}
+ mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ transformFrom(notification, animation.getAnimatedFraction());
+ }
+ });
+ mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
+ public boolean mCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled) {
+ setVisible(true);
+ } else {
+ abortTransformations();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+ });
+ mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
+ mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ mViewTransformationAnimation.start();
}
@Override
- public void transformFrom(TransformableView notification) {
+ public void transformFrom(TransformableView notification, float transformationAmount) {
for (Integer viewType : mTransformedViews.keySet()) {
TransformState ownState = getCurrentState(viewType);
if (ownState != null) {
CustomTransformation customTransformation = mCustomTransformations.get(viewType);
if (customTransformation != null && customTransformation.transformFrom(
- ownState, notification)) {
+ ownState, notification, transformationAmount)) {
ownState.recycle();
continue;
}
TransformState otherState = notification.getCurrentState(viewType);
if (otherState != null) {
- ownState.transformViewFrom(otherState);
+ ownState.transformViewFrom(otherState, transformationAmount);
otherState.recycle();
} else {
// There's no other view, lets fade us in
// Certain views need to prepare the fade in and make sure its children are
// completely visible. An example is the notification header.
- ownState.prepareFadeIn();
- CrossFadeHelper.fadeIn(mTransformedViews.get(viewType));
+ if (transformationAmount == 0.0f) {
+ ownState.prepareFadeIn();
+ }
+ CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount);
}
ownState.recycle();
}
@@ -131,6 +197,16 @@ public class ViewTransformationHelper implements TransformableView {
}
}
+ private void abortTransformations() {
+ for (Integer viewType : mTransformedViews.keySet()) {
+ TransformState ownState = getCurrentState(viewType);
+ if (ownState != null) {
+ ownState.abortTransformation();
+ ownState.recycle();
+ }
+ }
+ }
+
/**
* Add the remaining transformation views such that all views are being transformed correctly
* @param viewRoot the root below which all elements need to be transformed
@@ -173,22 +249,44 @@ public class ViewTransformationHelper implements TransformableView {
}
}
- public interface CustomTransformation {
+ public static abstract class CustomTransformation {
/**
* Transform a state to the given view
* @param ownState the state to transform
* @param notification the view to transform to
+ * @param transformationAmount how much transformation should be done
* @return whether a custom transformation is performed
*/
- boolean transformTo(TransformState ownState, TransformableView notification,
- Runnable endRunnable);
+ public abstract boolean transformTo(TransformState ownState,
+ TransformableView notification,
+ float transformationAmount);
/**
* Transform to this state from the given view
* @param ownState the state to transform to
* @param notification the view to transform from
+ * @param transformationAmount how much transformation should be done
* @return whether a custom transformation is performed
*/
- boolean transformFrom(TransformState ownState, TransformableView notification);
+ public abstract boolean transformFrom(TransformState ownState,
+ TransformableView notification,
+ float transformationAmount);
+
+ /**
+ * Perform a custom initialisation before transforming.
+ *
+ * @param ownState our own state
+ * @param otherState the other state
+ * @return whether a custom initialization is done
+ */
+ public boolean initTransformation(TransformState ownState,
+ TransformState otherState) {
+ return false;
+ }
+
+ public boolean customTransformTarget(TransformState ownState,
+ TransformState otherState) {
+ return false;
+ }
}
}
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 a58fa86a477a..8a93c5b0d1c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -23,6 +23,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.v4.util.SimpleArrayMap;
+import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.LinearLayout;
@@ -71,6 +72,7 @@ class CarNavigationBarController {
private int mCurrentFacetIndex;
private String mCurrentPackageName;
+ private SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
public CarNavigationBarController(Context context,
CarNavigationBarView navBar,
@@ -96,6 +98,21 @@ class CarNavigationBarController {
}
}
+ public void onPackageChange(String packageName) {
+ if (mFacetPackageMap.containsKey(packageName)) {
+ int index = mFacetPackageMap.get(packageName);
+ mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
+ // No need to check categories because we've already refreshed the cache.
+ return;
+ }
+
+ String category = getPackageCategory(packageName);
+ if (mFacetCategoryMap.containsKey(category)) {
+ int index = mFacetCategoryMap.get(packageName);
+ mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
+ }
+ }
+
private void bind() {
// Read up arrays_car.xml and populate the navigation bar here.
Resources r = mContext.getResources();
@@ -138,6 +155,7 @@ class CarNavigationBarController {
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);
}
@@ -229,7 +247,7 @@ class CarNavigationBarController {
if (mNavButtons.get(index) != null) {
mNavButtons.get(index).setSelected(true /* selected */,
- facetHasMultiplePackages(index) /* showMoreIcon */);
+ mFacetHasMultipleAppsCache.get(index) /* showMoreIcon */);
}
mCurrentFacetIndex = index;
}
@@ -268,7 +286,7 @@ class CarNavigationBarController {
private void startActivity(Intent intent) {
if (mActivityStarter != null && intent != null) {
- mActivityStarter.startActivity(intent, true);
+ mActivityStarter.startActivity(intent, false);
}
}
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 e20936b7dec4..c32ef0e9daf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -18,7 +18,10 @@ package com.android.systemui.statusbar.car;
import android.app.ActivityManager;
import android.app.ITaskStackListener;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
@@ -52,6 +55,7 @@ public class CarStatusBar extends PhoneStatusBar {
mTaskStackListener = new TaskStackListenerImpl(mHandler);
mSystemServicesProxy = new SystemServicesProxy(mContext);
mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+ registerPackageChangeReceivers();
}
@Override
@@ -81,6 +85,26 @@ public class CarStatusBar extends PhoneStatusBar {
mController = new CarNavigationBarController(context, mCarNavigationBar,
this /* ActivityStarter*/);
mNavigationBarView = mCarNavigationBar;
+
+ }
+
+ private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getData() == null || mController == null) {
+ return;
+ }
+ String packageName = intent.getData().getSchemeSpecificPart();
+ mController.onPackageChange(packageName);
+ }
+ };
+
+ private void registerPackageChangeReceivers() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mPackageChangeReceiver, filter);
}
@Override
@@ -109,6 +133,10 @@ public class CarStatusBar extends PhoneStatusBar {
}
@Override
+ public void onPinnedStackAnimationEnded() {
+ }
+
+ @Override
public void onTaskStackChanged() {
mHandler.removeCallbacks(this);
mHandler.post(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java
new file mode 100644
index 000000000000..32c26ba8ba13
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/FakeShadowView.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.LinearLayout;
+
+import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
+
+/**
+ * A view used to cast a shadow of a certain size on another view
+ */
+public class FakeShadowView extends AlphaOptimizedFrameLayout {
+ public static final float SHADOW_SIBLING_TRESHOLD = 0.1f;
+
+ private View mFakeShadow;
+ private float mOutlineAlpha;
+
+ public FakeShadowView(Context context) {
+ this(context, null);
+ }
+
+ public FakeShadowView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FakeShadowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public FakeShadowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mFakeShadow = new View(context);
+ mFakeShadow.setVisibility(INVISIBLE);
+ mFakeShadow.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ (int) (48 * getResources().getDisplayMetrics().density)));
+ mFakeShadow.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRect(0, 0, getWidth(), mFakeShadow.getHeight());
+ outline.setAlpha(mOutlineAlpha);
+ }
+ });
+ addView(mFakeShadow);
+ }
+
+ public void setFakeShadowTranslationZ(float fakeShadowTranslationZ, float outlineAlpha,
+ int shadowYEnd, int outlineTranslation) {
+ if (fakeShadowTranslationZ == 0.0f) {
+ mFakeShadow.setVisibility(INVISIBLE);
+ } else {
+ mFakeShadow.setVisibility(VISIBLE);
+ mFakeShadow.setTranslationZ(fakeShadowTranslationZ);
+ mFakeShadow.setTranslationX(outlineTranslation);
+ mFakeShadow.setTranslationY(shadowYEnd - mFakeShadow.getHeight());
+ if (outlineAlpha != mOutlineAlpha) {
+ mOutlineAlpha = outlineAlpha;
+ mFakeShadow.invalidateOutline();
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
index 81483c67fd8a..b66e9f313e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
@@ -46,7 +46,7 @@ public class HeaderTransformState extends TransformState {
}
@Override
- public boolean transformViewTo(TransformState otherState, Runnable endRunnable) {
+ 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)) {
@@ -62,14 +62,14 @@ public class HeaderTransformState extends TransformState {
if (headerChild != mExpandButton) {
headerChild.setVisibility(View.INVISIBLE);
} else {
- CrossFadeHelper.fadeOut(mExpandButton, endRunnable);
+ CrossFadeHelper.fadeOut(mExpandButton, transformationAmount);
}
}
return true;
}
@Override
- public void transformViewFrom(TransformState otherState) {
+ 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)) {
@@ -85,12 +85,13 @@ public class HeaderTransformState extends TransformState {
continue;
}
if (headerChild == mExpandButton) {
- CrossFadeHelper.fadeIn(mExpandButton);
+ CrossFadeHelper.fadeIn(mExpandButton, transformationAmount);
} else {
headerChild.setVisibility(View.VISIBLE);
if (headerChild == mWorkProfileIcon) {
- mWorkProfileState.animateViewFrom(
- ((HeaderTransformState) otherState).mWorkProfileState);
+ mWorkProfileState.transformViewFullyFrom(
+ ((HeaderTransformState) otherState).mWorkProfileState,
+ transformationAmount);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index 81144d553685..c80cad836f48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -71,13 +71,13 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout
new ViewTransformationHelper.CustomTransformation() {
@Override
public boolean transformTo(TransformState ownState, TransformableView notification,
- Runnable endRunnable) {
+ float transformationAmount) {
// We want to transform to the same y location as the title
TransformState otherState = notification.getCurrentState(
TRANSFORMING_VIEW_TITLE);
- CrossFadeHelper.fadeOut(mTextView, endRunnable);
+ CrossFadeHelper.fadeOut(mTextView, transformationAmount);
if (otherState != null) {
- ownState.animateViewVerticalTo(otherState, endRunnable);
+ ownState.transformViewVerticalTo(otherState, transformationAmount);
otherState.recycle();
}
return true;
@@ -85,13 +85,13 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout
@Override
public boolean transformFrom(TransformState ownState,
- TransformableView notification) {
+ TransformableView notification, float transformationAmount) {
// We want to transform from the same y location as the title
TransformState otherState = notification.getCurrentState(
TRANSFORMING_VIEW_TITLE);
- CrossFadeHelper.fadeIn(mTextView);
+ CrossFadeHelper.fadeIn(mTextView, transformationAmount);
if (otherState != null) {
- ownState.animateViewVerticalFrom(otherState);
+ ownState.transformViewVerticalFrom(otherState, transformationAmount);
otherState.recycle();
}
return true;
@@ -133,11 +133,21 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout
}
@Override
+ public void transformTo(TransformableView notification, float transformationAmount) {
+ mTransformationHelper.transformTo(notification, transformationAmount);
+ }
+
+ @Override
public void transformFrom(TransformableView notification) {
mTransformationHelper.transformFrom(notification);
}
@Override
+ public void transformFrom(TransformableView notification, float transformationAmount) {
+ mTransformationHelper.transformFrom(notification, transformationAmount);
+ }
+
+ @Override
public void setVisible(boolean visible) {
setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mTransformationHelper.setVisible(visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index e891a977abce..45027c0dba7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -62,7 +62,7 @@ public class ImageTransformState extends TransformState {
}
@Override
- protected boolean animateScale() {
+ protected boolean transformScale() {
return true;
}
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 60c191126116..7f8f20f7a8f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -35,7 +35,7 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
@Override
public void setDark(boolean dark, boolean fade, long delay) {
- if (dark == mDark) {
+ if (dark == mDark && mDarkInitialized) {
return;
}
super.setDark(dark, fade, delay);
@@ -45,4 +45,10 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
mInvertHelper.update(dark);
}
}
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ mView.setAlpha(visible ? 1.0f : 0.0f);
+ }
}
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 5a71cafb1dd1..842bd22cf4cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -142,12 +142,13 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
protected void updateTransformedTypes() {
mTransformationHelper.reset();
- mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER, mNotificationHeader);
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER,
+ mNotificationHeader);
}
@Override
public void setDark(boolean dark, boolean fade, long delay) {
- if (dark == mDark) {
+ if (dark == mDark && mDarkInitialized) {
return;
}
super.setDark(dark, fade, delay);
@@ -299,11 +300,21 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
+ public void transformTo(TransformableView notification, float transformationAmount) {
+ mTransformationHelper.transformTo(notification, transformationAmount);
+ }
+
+ @Override
public void transformFrom(TransformableView notification) {
mTransformationHelper.transformFrom(notification);
}
@Override
+ public void transformFrom(TransformableView notification, float transformationAmount) {
+ mTransformationHelper.transformFrom(notification, transformationAmount);
+ }
+
+ @Override
public void setVisible(boolean visible) {
super.setVisible(visible);
mTransformationHelper.setVisible(visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
new file mode 100644
index 000000000000..30698e109178
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -0,0 +1,57 @@
+/*
+ * 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.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+import com.android.systemui.statusbar.TransformableView;
+
+/**
+ * Wraps a notification containing a media template
+ */
+public class NotificationMediaTemplateViewWrapper extends NotificationTemplateViewWrapper {
+
+ protected NotificationMediaTemplateViewWrapper(Context ctx, View view) {
+ super(ctx, view);
+ }
+
+ View mActions;
+
+ private void resolveViews(StatusBarNotification notification) {
+ mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+ }
+
+ @Override
+ public void notifyContentUpdated(StatusBarNotification notification) {
+ // 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);
+ }
+
+ @Override
+ protected void updateTransformedTypes() {
+ // This also clears the existing types
+ super.updateTransformedTypes();
+ if (mActions != null) {
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+ mActions);
+ }
+ }
+}
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 0c21f0b2c962..78e23fce1a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -49,76 +49,65 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
new ViewTransformationHelper.CustomTransformation() {
@Override
public boolean transformTo(TransformState ownState,
- TransformableView notification, final Runnable endRunnable) {
+ TransformableView notification, final float transformationAmount) {
if (!(notification instanceof HybridNotificationView)) {
return false;
}
TransformState otherState = notification.getCurrentState(
TRANSFORMING_VIEW_TITLE);
final View text = ownState.getTransformedView();
- CrossFadeHelper.fadeOut(text, endRunnable);
+ CrossFadeHelper.fadeOut(text, transformationAmount);
if (otherState != null) {
- int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
- int[] ownPosition = ownState.getLaidOutLocationOnScreen();
- text.animate()
- .translationY((otherStablePosition[1]
- + otherState.getTransformedView().getHeight()
- - ownPosition[1]) * 0.33f)
- .setDuration(
- StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- if (endRunnable != null) {
- endRunnable.run();
- }
- TransformState.setClippingDeactivated(text,
- false);
- }
- });
- TransformState.setClippingDeactivated(text, true);
+ ownState.transformViewVerticalTo(otherState, this,
+ transformationAmount);
otherState.recycle();
}
return true;
}
@Override
+ public boolean customTransformTarget(TransformState ownState,
+ TransformState otherState) {
+ float endY = getTransformationY(ownState, otherState);
+ ownState.setTransformationEndY(endY);
+ return true;
+ }
+
+ @Override
public boolean transformFrom(TransformState ownState,
- TransformableView notification) {
+ TransformableView notification, float transformationAmount) {
if (!(notification instanceof HybridNotificationView)) {
return false;
}
TransformState otherState = notification.getCurrentState(
TRANSFORMING_VIEW_TITLE);
final View text = ownState.getTransformedView();
- boolean isVisible = text.getVisibility() == View.VISIBLE;
- CrossFadeHelper.fadeIn(text);
+ CrossFadeHelper.fadeIn(text, transformationAmount);
if (otherState != null) {
- int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
- int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
- if (!isVisible) {
- text.setTranslationY((otherStablePosition[1]
- + otherState.getTransformedView().getHeight()
- - ownStablePosition[1]) * 0.33f);
- }
- text.animate()
- .translationY(0)
- .setDuration(
- StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- TransformState.setClippingDeactivated(text,
- false);
- }
- });
- TransformState.setClippingDeactivated(text, true);
+ ownState.transformViewVerticalFrom(otherState, this,
+ transformationAmount);
otherState.recycle();
}
return true;
}
+
+ @Override
+ public boolean initTransformation(TransformState ownState,
+ TransformState otherState) {
+ float startY = getTransformationY(ownState, otherState);
+ ownState.setTransformationStartY(startY);
+ return true;
+ }
+
+ private float getTransformationY(TransformState ownState,
+ TransformState otherState) {
+ int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
+ int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
+ return (otherStablePosition[1]
+ + otherState.getTransformedView().getHeight()
+ - ownStablePosition[1]) * 0.33f;
+ }
+
}, TRANSFORMING_VIEW_TEXT);
}
@@ -174,7 +163,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
@Override
public void setDark(boolean dark, boolean fade, long delay) {
- if (dark == mDark) {
+ if (dark == mDark && mDarkInitialized) {
return;
}
super.setDark(dark, fade, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 7089b7811e88..47386575de4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -34,4 +34,8 @@ public class NotificationUtils {
v.setTag(R.id.icon_is_grayscale, grayscale);
return grayscale;
}
+
+ public static float interpolate(float start, float end, float amount) {
+ return start * (1.0f - amount) + end * amount;
+ }
}
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 a2b4c5d24442..0df0d26aea10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -32,6 +32,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
protected final View mView;
protected boolean mDark;
+ protected boolean mDarkInitialized = false;
public static NotificationViewWrapper wrap(Context ctx, View v) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -39,6 +40,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
return new NotificationBigPictureTemplateViewWrapper(ctx, v);
} else if ("bigText".equals(v.getTag())) {
return new NotificationBigTextTemplateViewWrapper(ctx, v);
+ } else if ("media".equals(v.getTag()) || "bigMediaNarrow".equals(v.getTag())) {
+ return new NotificationMediaTemplateViewWrapper(ctx, v);
}
return new NotificationTemplateViewWrapper(ctx, v);
} else if (v instanceof NotificationHeaderView) {
@@ -61,6 +64,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
*/
public void setDark(boolean dark, boolean fade, long delay) {
mDark = dark;
+ mDarkInitialized = true;
}
/**
@@ -68,7 +72,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
* @param notification
*/
public void notifyContentUpdated(StatusBarNotification notification) {
- mDark = false;
+ mDarkInitialized = false;
};
/**
@@ -98,13 +102,24 @@ public abstract class NotificationViewWrapper implements TransformableView {
}
@Override
+ public void transformTo(TransformableView notification, float transformationAmount) {
+ CrossFadeHelper.fadeOut(mView, transformationAmount);
+ }
+
+ @Override
public void transformFrom(TransformableView notification) {
// By default we are fading in completely
CrossFadeHelper.fadeIn(mView);
}
@Override
+ public void transformFrom(TransformableView notification, float transformationAmount) {
+ CrossFadeHelper.fadeIn(mView, transformationAmount);
+ }
+
+ @Override
public void setVisible(boolean visible) {
+ mView.animate().cancel();
mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
}
}
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 5832d86628af..f04fe5e11231 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -30,23 +30,30 @@ 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.stack.StackStateAnimator;
+import com.android.systemui.statusbar.ViewTransformationHelper;
/**
* A transform state of a view.
*/
public class TransformState {
- private static final int ANIMATE_X = 0x1;
- private static final int ANIMATE_Y = 0x10;
- private static final int ANIMATE_ALL = ANIMATE_X | ANIMATE_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;
+ private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag;
+ private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag;
+ private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag;
+ private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag;
private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
protected View mTransformedView;
private int[] mOwnPosition = new int[2];
+ private float mTransformationEndY = UNDEFINED;
+ private float mTransformationEndX = UNDEFINED;
public void initFrom(View view) {
mTransformedView = view;
@@ -55,129 +62,233 @@ public class TransformState {
/**
* Transforms the {@link #mTransformedView} from the given transformviewstate
* @param otherState the state to transform from
+ * @param transformationAmount how much to transform
*/
- public void transformViewFrom(TransformState otherState) {
+ public void transformViewFrom(TransformState otherState, float transformationAmount) {
mTransformedView.animate().cancel();
if (sameAs(otherState)) {
- // We have the same content, lets show ourselves
- mTransformedView.setAlpha(1.0f);
- mTransformedView.setVisibility(View.VISIBLE);
+ if (mTransformedView.getVisibility() == View.INVISIBLE) {
+ // We have the same content, lets show ourselves
+ mTransformedView.setAlpha(1.0f);
+ mTransformedView.setVisibility(View.VISIBLE);
+ }
} else {
- CrossFadeHelper.fadeIn(mTransformedView);
+ CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
}
- animateViewFrom(otherState);
+ transformViewFullyFrom(otherState, transformationAmount);
+ }
+
+ public void transformViewFullyFrom(TransformState otherState, float transformationAmount) {
+ transformViewFrom(otherState, TRANSOFORM_ALL, null, transformationAmount);
}
- public void animateViewFrom(TransformState otherState) {
- animateViewFrom(otherState, ANIMATE_ALL);
+ public void transformViewVerticalFrom(TransformState otherState,
+ ViewTransformationHelper.CustomTransformation customTransformation,
+ float transformationAmount) {
+ transformViewFrom(otherState, TRANSOFORM_Y, customTransformation, transformationAmount);
}
- public void animateViewVerticalFrom(TransformState otherState) {
- animateViewFrom(otherState, ANIMATE_Y);
+ public void transformViewVerticalFrom(TransformState otherState, float transformationAmount) {
+ transformViewFrom(otherState, TRANSOFORM_Y, null, transformationAmount);
}
- private void animateViewFrom(TransformState otherState, int animationFlags) {
+ 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 transformScale = transformScale();
// lets animate the positions correctly
- int[] otherPosition = otherState.getLocationOnScreen();
- int[] ownStablePosition = getLaidOutLocationOnScreen();
- if ((animationFlags & ANIMATE_X) != 0) {
- transformedView.setTranslationX(otherPosition[0] - ownStablePosition[0]);
- transformedView.animate().translationX(0);
+ if (transformationAmount == 0.0f) {
+ int[] otherPosition = otherState.getLocationOnScreen();
+ int[] ownStablePosition = getLaidOutLocationOnScreen();
+ if (customTransformation == null
+ || !customTransformation.initTransformation(this, otherState)) {
+ if (transformX) {
+ setTransformationStartX(otherPosition[0] - ownStablePosition[0]);
+ }
+ if (transformY) {
+ setTransformationStartY(otherPosition[1] - ownStablePosition[1]);
+ }
+ // we also want to animate the scale if we're the same
+ View otherView = otherState.getTransformedView();
+ if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
+ setTransformationStartScaleX(otherView.getWidth() * otherView.getScaleX()
+ / (float) transformedView.getWidth());
+ transformedView.setPivotX(0);
+ } else {
+ setTransformationStartScaleX(UNDEFINED);
+ }
+ if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
+ setTransformationStartScaleY(otherView.getHeight() * otherView.getScaleY()
+ / (float) transformedView.getHeight());
+ transformedView.setPivotY(0);
+ } else {
+ setTransformationStartScaleY(UNDEFINED);
+ }
+ }
+ if (!transformX) {
+ setTransformationStartX(UNDEFINED);
+ }
+ if (!transformY) {
+ setTransformationStartY(UNDEFINED);
+ }
+ if (!transformScale) {
+ setTransformationStartScaleX(UNDEFINED);
+ setTransformationStartScaleY(UNDEFINED);
+ }
+ setClippingDeactivated(transformedView, true);
}
- if ((animationFlags & ANIMATE_Y) != 0) {
- transformedView.setTranslationY(otherPosition[1] - ownStablePosition[1]);
- transformedView.animate().translationY(0);
+ float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ transformationAmount);
+ if (transformX) {
+ transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(),
+ 0.0f,
+ interpolatedValue));
}
- if (animateScale()) {
- // we also want to animate the scale if we're the same
- View otherView = otherState.getTransformedView();
- if (otherView.getWidth() != transformedView.getWidth()) {
- float scaleX = (otherView.getWidth() * otherView.getScaleX()
- / (float) transformedView.getWidth());
- transformedView.setScaleX(scaleX);
- transformedView.setPivotX(0);
- transformedView.animate().scaleX(1.0f);
+ if (transformY) {
+ transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(),
+ 0.0f,
+ interpolatedValue));
+ }
+ if (transformScale) {
+ float transformationStartScaleX = getTransformationStartScaleX();
+ if (transformationStartScaleX != UNDEFINED) {
+ transformedView.setScaleX(
+ NotificationUtils.interpolate(transformationStartScaleX,
+ 1.0f,
+ interpolatedValue));
}
- if (otherView.getHeight() != transformedView.getHeight()) {
- float scaleY = (otherView.getHeight() * otherView.getScaleY()
- / (float) transformedView.getHeight());
- transformedView.setScaleY(scaleY);
- transformedView.setPivotY(0);
- transformedView.animate().scaleY(1.0f);
+ float transformationStartScaleY = getTransformationStartScaleY();
+ if (transformationStartScaleY != UNDEFINED) {
+ transformedView.setScaleY(
+ NotificationUtils.interpolate(transformationStartScaleY,
+ 1.0f,
+ interpolatedValue));
}
}
- transformedView.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- setClippingDeactivated(transformedView, false);
- }
- });
- setClippingDeactivated(transformedView, true);
}
- protected boolean animateScale() {
+ protected boolean transformScale() {
return false;
}
/**
* Transforms the {@link #mTransformedView} to the given transformviewstate
* @param otherState the state to transform from
- * @param endRunnable a runnable to run at the end of the animation
+ * @param transformationAmount how much to transform
* @return whether an animation was started
*/
- public boolean transformViewTo(TransformState otherState, final Runnable endRunnable) {
+ public boolean transformViewTo(TransformState otherState, float transformationAmount) {
mTransformedView.animate().cancel();
if (sameAs(otherState)) {
// We have the same text, lets show ourselfs
- mTransformedView.setAlpha(0.0f);
- mTransformedView.setVisibility(View.INVISIBLE);
+ if (mTransformedView.getVisibility() == View.VISIBLE) {
+ mTransformedView.setAlpha(0.0f);
+ mTransformedView.setVisibility(View.INVISIBLE);
+ }
return false;
} else {
- CrossFadeHelper.fadeOut(mTransformedView, endRunnable);
+ CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
}
- animateViewTo(otherState, endRunnable);
+ transformViewFullyTo(otherState, transformationAmount);
return true;
}
- public void animateViewTo(TransformState otherState, Runnable endRunnable) {
- animateViewTo(otherState, endRunnable, ANIMATE_ALL);
+ public void transformViewFullyTo(TransformState otherState, float transformationAmount) {
+ transformViewTo(otherState, TRANSOFORM_ALL, null, transformationAmount);
+ }
+
+ public void transformViewVerticalTo(TransformState otherState,
+ ViewTransformationHelper.CustomTransformation customTransformation,
+ float transformationAmount) {
+ transformViewTo(otherState, TRANSOFORM_Y, customTransformation, transformationAmount);
}
- public void animateViewVerticalTo(TransformState otherState, Runnable endRunnable) {
- animateViewTo(otherState, endRunnable, ANIMATE_Y);
+ public void transformViewVerticalTo(TransformState otherState, float transformationAmount) {
+ transformViewTo(otherState, TRANSOFORM_Y, null, transformationAmount);
}
- private void animateViewTo(TransformState otherState, final Runnable endRunnable,
- int animationFlags) {
+ private void transformViewTo(TransformState otherState, int transformationFlags,
+ ViewTransformationHelper.CustomTransformation customTransformation,
+ float transformationAmount) {
+ // lets animate the positions correctly
+
+ final View transformedView = mTransformedView;
+ boolean transformX = (transformationFlags & TRANSOFORM_X) != 0;
+ boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0;
+ boolean transformScale = transformScale();
// lets animate the positions correctly
+ if (transformationAmount == 0.0f) {
+ if (transformX) {
+ float transformationStartX = getTransformationStartX();
+ float start = transformationStartX != UNDEFINED ? transformationStartX
+ : transformedView.getTranslationX();
+ setTransformationStartX(start);
+ }
+ if (transformY) {
+ float transformationStartY = getTransformationStartY();
+ float start = transformationStartY != UNDEFINED ? transformationStartY
+ : transformedView.getTranslationY();
+ setTransformationStartY(start);
+ }
+ View otherView = otherState.getTransformedView();
+ if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
+ setTransformationStartScaleX(transformedView.getScaleX());
+ transformedView.setPivotX(0);
+ } else {
+ setTransformationStartScaleX(UNDEFINED);
+ }
+ if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
+ setTransformationStartScaleY(transformedView.getScaleY());
+ transformedView.setPivotY(0);
+ } else {
+ setTransformationStartScaleY(UNDEFINED);
+ }
+ setClippingDeactivated(transformedView, true);
+ }
+ float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ transformationAmount);
int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
int[] ownPosition = getLaidOutLocationOnScreen();
- final View transformedView = mTransformedView;
- if ((animationFlags & ANIMATE_X) != 0) {
- transformedView.animate()
- .translationX(otherStablePosition[0] - ownPosition[0]);
+ if (transformX) {
+ float endX = otherStablePosition[0] - ownPosition[0];
+ if (customTransformation != null
+ && customTransformation.customTransformTarget(this, otherState)) {
+ endX = mTransformationEndX;
+ }
+ transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(),
+ endX,
+ interpolatedValue));
}
- if ((animationFlags & ANIMATE_Y) != 0) {
- transformedView.animate()
- .translationY(otherStablePosition[1] - ownPosition[1]);
+ if (transformY) {
+ float endY = otherStablePosition[1] - ownPosition[1];
+ if (customTransformation != null
+ && customTransformation.customTransformTarget(this, otherState)) {
+ endY = mTransformationEndY;
+ }
+ transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(),
+ endY,
+ interpolatedValue));
+ }
+ if (transformScale) {
+ View otherView = otherState.getTransformedView();
+ float transformationStartScaleX = getTransformationStartScaleX();
+ if (transformationStartScaleX != UNDEFINED) {
+ transformedView.setScaleX(
+ NotificationUtils.interpolate(transformationStartScaleX,
+ (otherView.getWidth() / (float) transformedView.getWidth()),
+ interpolatedValue));
+ }
+ float transformationStartScaleY = getTransformationStartScaleY();
+ if (transformationStartScaleY != UNDEFINED) {
+ transformedView.setScaleY(
+ NotificationUtils.interpolate(transformationStartScaleY,
+ (otherView.getHeight() / (float) transformedView.getHeight()),
+ interpolatedValue));
+ }
}
- transformedView.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- if (endRunnable != null) {
- endRunnable.run();
- }
- setClippingDeactivated(transformedView, false);
- }
- });
- setClippingDeactivated(transformedView, true);
}
public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
@@ -281,8 +392,54 @@ public class TransformState {
}
}
+ public void setTransformationEndY(float transformationEndY) {
+ mTransformationEndY = transformationEndY;
+ }
+
+ public void setTransformationEndX(float transformationEndX) {
+ mTransformationEndX = transformationEndX;
+ }
+
+ public float getTransformationStartX() {
+ Object tag = mTransformedView.getTag(TRANSFORMATION_START_X);
+ return tag == null ? UNDEFINED : (float) tag;
+ }
+
+ public float getTransformationStartY() {
+ Object tag = mTransformedView.getTag(TRANSFORMATION_START_Y);
+ return tag == null ? UNDEFINED : (float) tag;
+ }
+
+ public float getTransformationStartScaleX() {
+ Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_X);
+ return tag == null ? UNDEFINED : (float) tag;
+ }
+
+ public float getTransformationStartScaleY() {
+ Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_Y);
+ return tag == null ? UNDEFINED : (float) tag;
+ }
+
+ public void setTransformationStartX(float transformationStartX) {
+ mTransformedView.setTag(TRANSFORMATION_START_X, transformationStartX);
+ }
+
+ public void setTransformationStartY(float transformationStartY) {
+ mTransformedView.setTag(TRANSFORMATION_START_Y, transformationStartY);
+ }
+
+ private void setTransformationStartScaleX(float startScaleX) {
+ mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, startScaleX);
+ }
+
+ private void setTransformationStartScaleY(float startScaleY) {
+ mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, startScaleY);
+ }
+
protected void reset() {
mTransformedView = null;
+ mTransformationEndX = UNDEFINED;
+ mTransformationEndY = UNDEFINED;
}
public void setVisible(boolean visible) {
@@ -293,14 +450,28 @@ public class TransformState {
mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
if (visible) {
- mTransformedView.setTranslationX(0);
- mTransformedView.setTranslationY(0);
- mTransformedView.setScaleX(1.0f);
- mTransformedView.setScaleY(1.0f);
+ resetTransformedView();
}
}
public void prepareFadeIn() {
+ resetTransformedView();
+ }
+
+ private void resetTransformedView() {
+ mTransformedView.setTranslationX(0);
+ mTransformedView.setTranslationY(0);
+ mTransformedView.setScaleX(1.0f);
+ mTransformedView.setScaleY(1.0f);
+ setClippingDeactivated(mTransformedView, false);
+ abortTransformation();
+ }
+
+ public void abortTransformation() {
+ mTransformedView.setTag(TRANSFORMATION_START_X, UNDEFINED);
+ mTransformedView.setTag(TRANSFORMATION_START_Y, UNDEFINED);
+ mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, UNDEFINED);
+ mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, UNDEFINED);
}
public static TransformState obtain() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index b74247960fc7..6d0fbb15ca64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
+import com.android.systemui.statusbar.policy.NightModeController;
/**
* Manages which tiles should be automatically added to QS.
@@ -66,12 +67,33 @@ public class AutoTileManager {
if (!Prefs.getBoolean(context, Key.QS_WORK_ADDED, false)) {
host.getManagedProfileController().addCallback(mProfileCallback);
}
+ if (!Prefs.getBoolean(context, Key.QS_NIGHT_ADDED, false)) {
+ host.getNightModeController().addListener(mNightModeListener);
+ }
}
public void destroy() {
// TODO: Remove any registered listeners.
}
+ private final NightModeController.Listener mNightModeListener =
+ new NightModeController.Listener() {
+ @Override
+ public void onNightModeChanged() {
+ mHost.addTile("night");
+ Prefs.putBoolean(mContext, Key.QS_NIGHT_ADDED, true);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mHost.getNightModeController().removeListener(mNightModeListener);
+ }
+ });
+ }
+
+ @Override
+ public void onTwilightAutoChanged() { }
+ };
+
private final ManagedProfileController.Callback mProfileCallback =
new ManagedProfileController.Callback() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
new file mode 100644
index 000000000000..04095e76add4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
@@ -0,0 +1,51 @@
+/*
+ * 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.phone;
+
+import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import com.android.systemui.R;
+
+public class ExpandableIndicator extends ImageView {
+
+ private boolean mExpanded;
+
+ public ExpandableIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
+ : R.drawable.ic_volume_expand_animation;
+ setImageResource(res);
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (expanded == mExpanded) return;
+ mExpanded = expanded;
+ final int res = mExpanded ? R.drawable.ic_volume_expand_animation
+ : R.drawable.ic_volume_collapse_animation;
+ // workaround to reset drawable
+ final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext()
+ .getDrawable(res).getConstantState().newDrawable();
+ setImageDrawable(avd);
+ avd.forceAnimationOnUI();
+ avd.start();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index b5b7f4383917..33315c58fb4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -79,7 +79,8 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mTouchingHeadsUpView = false;
if (child instanceof ExpandableNotificationRow) {
mPickedChild = (ExpandableNotificationRow) child;
- mTouchingHeadsUpView = mPickedChild.isHeadsUp() && mPickedChild.isPinned();
+ mTouchingHeadsUpView = !mStackScroller.isExpanded()
+ && mPickedChild.isHeadsUp() && mPickedChild.isPinned();
}
break;
case MotionEvent.ACTION_POINTER_UP:
@@ -106,7 +107,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mPanel.setPanelScrimMinFraction((float) expandedHeight
/ mPanel.getMaxPanelHeight());
mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
- mPanel.clearNotificattonEffects();
+ mPanel.clearNotificationEffects();
return true;
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index b9e1ad2e41c2..ee88b0041b7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -16,7 +16,11 @@
package com.android.systemui.statusbar.phone;
+import android.app.ActivityManager;
import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -42,6 +46,8 @@ import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
*/
public class KeyguardBouncer {
+ final static private String TAG = "KeyguardBouncer";
+
protected Context mContext;
protected ViewMediatorCallback mCallback;
protected LockPatternUtils mLockPatternUtils;
@@ -73,6 +79,11 @@ public class KeyguardBouncer {
}
public void show(boolean resetSecuritySelection) {
+ final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
+ if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
+ // In split system user mode, we never unlock system user.
+ return;
+ }
mFalsingManager.onBouncerShown();
ensureView();
if (resetSecuritySelection) {
@@ -84,14 +95,25 @@ public class KeyguardBouncer {
return;
}
- // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
- // Keyguard. If we need to authenticate, show the bouncer.
- if (!mKeyguardView.dismiss()) {
- mShowingSoon = true;
+ final int activeUserId = ActivityManager.getCurrentUser();
+ final boolean allowDismissKeyguard =
+ !(UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM)
+ && activeUserId == keyguardUserId;
+ // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
+ // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
+ if (allowDismissKeyguard && mKeyguardView.dismiss()) {
+ return;
+ }
- // Split up the work over multiple frames.
- DejankUtils.postAfterTraversal(mShowRunnable);
+ // This condition may indicate an error on Android, so log it.
+ if (!allowDismissKeyguard) {
+ Slog.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
}
+
+ mShowingSoon = true;
+
+ // Split up the work over multiple frames.
+ DejankUtils.postAfterTraversal(mShowRunnable);
}
private final Runnable mShowRunnable = new Runnable() {
@@ -258,19 +280,8 @@ public class KeyguardBouncer {
return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
}
- public boolean onMenuPressed() {
- ensureView();
- if (mKeyguardView.handleMenuKey()) {
-
- // We need to show it in case it is secure. If not, it will get dismissed in any case.
- mRoot.setVisibility(View.VISIBLE);
- mFalsingManager.onBouncerShown();
- mKeyguardView.requestFocus();
- mKeyguardView.onResume();
- return true;
- } else {
- return false;
- }
+ public boolean shouldDismissOnMenuPressed() {
+ return mKeyguardView.shouldEnableMenuKey();
}
public boolean interceptMediaKey(KeyEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
new file mode 100644
index 000000000000..f98b9e586a1c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -0,0 +1,126 @@
+/*
+ * 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.phone;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import com.android.systemui.statusbar.policy.BatteryController;
+
+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 LightStatusBarController {
+
+ private final StatusBarIconController mIconController;
+ private final BatteryController mBatteryController;
+ private FingerprintUnlockController mFingerprintUnlockController;
+
+ private int mFullscreenStackVisibility;
+ private int mDockedStackVisibility;
+ private boolean mFullscreenLight;
+ private boolean mDockedLight;
+
+ private final Rect mLastFullscreenBounds = new Rect();
+ private final Rect mLastDockedBounds = new Rect();
+
+ public LightStatusBarController(StatusBarIconController iconController,
+ BatteryController batteryController) {
+ mIconController = iconController;
+ mBatteryController = batteryController;
+ }
+
+ public void setFingerprintUnlockController(
+ FingerprintUnlockController fingerprintUnlockController) {
+ mFingerprintUnlockController = fingerprintUnlockController;
+ }
+
+ public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask,
+ Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
+ int statusBarMode) {
+ int oldFullscreen = mFullscreenStackVisibility;
+ int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
+ int diffFullscreen = newFullscreen ^ oldFullscreen;
+ int oldDocked = mDockedStackVisibility;
+ int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask);
+ int diffDocked = newDocked ^ oldDocked;
+ if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+ || (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+ || sbModeChanged
+ || !mLastFullscreenBounds.equals(fullscreenStackBounds)
+ || !mLastDockedBounds.equals(dockedStackBounds)) {
+
+ mFullscreenLight = isLight(newFullscreen, statusBarMode);
+ mDockedLight = isLight(newDocked, statusBarMode);
+ update(fullscreenStackBounds, dockedStackBounds);
+ }
+ mFullscreenStackVisibility = newFullscreen;
+ mDockedStackVisibility = newDocked;
+ mLastFullscreenBounds.set(fullscreenStackBounds);
+ mLastDockedBounds.set(dockedStackBounds);
+ }
+
+ private boolean isLight(int vis, int statusBarMode) {
+ boolean isTransparentBar = (statusBarMode == MODE_TRANSPARENT
+ || statusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
+ boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
+ boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
+ return allowLight && light;
+ }
+
+ private boolean animateChange() {
+ if (mFingerprintUnlockController == null) {
+ return false;
+ }
+ int unlockMode = mFingerprintUnlockController.getMode();
+ return unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+ && unlockMode != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
+ }
+
+ private void update(Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ boolean hasDockedStack = !dockedStackBounds.isEmpty();
+
+ // If both are light or fullscreen is light and there is no docked stack, all icons get
+ // dark.
+ if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) {
+ mIconController.setIconsDarkArea(null);
+ mIconController.setIconsDark(true, animateChange());
+
+ }
+
+ // If no one is light or the fullscreen is not light and there is no docked stack,
+ // all icons become white.
+ else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) {
+ mIconController.setIconsDark(false, animateChange());
+
+ }
+
+ // Not the same for every stack, magic!
+ else {
+ Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds;
+ if (bounds.isEmpty()) {
+ mIconController.setIconsDarkArea(null);
+ } else {
+ mIconController.setIconsDarkArea(bounds);
+ }
+ mIconController.setIconsDark(true, animateChange());
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
new file mode 100644
index 000000000000..5b4a3f0039c9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -0,0 +1,155 @@
+/*
+ * 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.phone;
+
+import android.app.ActivityManager;
+import android.app.IWallpaperManager;
+import android.app.IWallpaperManagerCallback;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import java.util.Objects;
+
+/**
+ * Manages the lockscreen wallpaper.
+ */
+public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implements Runnable {
+
+ private static final String TAG = "LockscreenWallpaper";
+
+ private final Context mContext;
+ private final PhoneStatusBar mBar;
+ private final IWallpaperManager mService;
+ private final WallpaperManager mWallpaperManager;
+ private final Handler mH;
+
+ private boolean mCached;
+ private Bitmap mCache;
+ private int mCurrentUserId;
+ // The user selected in the UI, or null if no user is selected or UI doesn't support selecting
+ // users.
+ private UserHandle mSelectedUser;
+
+ public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
+ mContext = ctx;
+ mBar = bar;
+ mH = h;
+ mService = IWallpaperManager.Stub.asInterface(
+ ServiceManager.getService(Context.WALLPAPER_SERVICE));
+ mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
+ mCurrentUserId = ActivityManager.getCurrentUser();
+
+ try {
+ mService.setLockWallpaperCallback(this);
+ } catch (RemoteException e) {
+ Log.e(TAG, "System dead?" + e);
+ }
+ }
+
+ public Bitmap getBitmap() {
+ try {
+ if (mCached) {
+ return mCache;
+ }
+ if (!mService.isWallpaperSupported(mContext.getOpPackageName())) {
+ mCached = true;
+ mCache = null;
+ return null;
+ }
+ // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
+ // wallpaper.
+ final int lockWallpaperUserId =
+ mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
+ ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
+ new Bundle(), lockWallpaperUserId);
+ if (fd != null) {
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ mCache = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options);
+ mCached = true;
+ return mCache;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't decode file", e);
+ return null;
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ } else {
+ mCached = true;
+ if (mSelectedUser != null && mSelectedUser.getIdentifier() != mCurrentUserId) {
+ // When selected user is different from the current user, show the selected
+ // user's static wallpaper.
+ mWallpaperManager.forgetLoadedWallpaper();
+ mCache = mWallpaperManager.getBitmapAsUser(mSelectedUser.getIdentifier());
+ } else {
+ // When there is no selected user, or it's same as the current user, show the
+ // system (possibly dynamic) wallpaper for the selected user.
+ mCache = null;
+ }
+ return mCache;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "System dead?" + e);
+ return null;
+ }
+ }
+
+ public void setCurrentUser(int user) {
+ if (user != mCurrentUserId) {
+ mCached = false;
+ mCurrentUserId = user;
+ }
+ }
+
+ public void setSelectedUser(UserHandle selectedUser) {
+ if (Objects.equals(selectedUser, mSelectedUser)) {
+ return;
+ }
+ mSelectedUser = selectedUser;
+
+ mH.removeCallbacks(this);
+ mH.post(this);
+ }
+
+ @Override
+ public void onWallpaperChanged() {
+ // Called on Binder thread.
+ mH.removeCallbacks(this);
+ mH.post(this);
+ }
+
+ @Override
+ public void run() {
+ // Called in response to onWallpaperChanged on the main thread.
+ mCached = false;
+ mCache = null;
+ getBitmap();
+ mBar.updateMediaMetaData(true /* metaDataChanged */, true /* allowEnterAnimation */);
+ }
+}
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 d625fc2bc738..260c9697c293 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -163,68 +163,29 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
String[] start = sets[0].split(BUTTON_SEPARATOR);
String[] center = sets[1].split(BUTTON_SEPARATOR);
String[] end = sets[2].split(BUTTON_SEPARATOR);
- inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group),
- (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
- inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group),
- (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+ inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
+ inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
- inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
- (ViewGroup) mRot0.findViewById(R.id.center_group_lightsout), false);
- inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
- (ViewGroup) mRot90.findViewById(R.id.center_group_lightsout), true);
+ inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), false);
+ inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), true);
addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
- inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group),
- (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
- inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group),
- (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+ inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
+ inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
}
private void addGravitySpacer(LinearLayout layout) {
layout.addView(new Space(mContext), new LinearLayout.LayoutParams(0, 0, 1));
}
- private void inflateButtons(String[] buttons, ViewGroup parent, ViewGroup lightsOutParent,
- boolean landscape) {
+ private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape) {
for (int i = 0; i < buttons.length; i++) {
- copyToLightsout(inflateButton(buttons[i], parent, landscape), lightsOutParent);
+ inflateButton(buttons[i], parent, landscape);
}
}
- private void copyToLightsout(View view, ViewGroup lightsOutParent) {
- if (view == null) return;
-
- if (view instanceof FrameLayout) {
- // The only ViewGroup we support in here is a FrameLayout, so copy those manually.
- FrameLayout original = (FrameLayout) view;
- FrameLayout layout = new FrameLayout(view.getContext());
- for (int i = 0; i < original.getChildCount(); i++) {
- copyToLightsout(original.getChildAt(i), layout);
- }
- lightsOutParent.addView(layout, copy(view.getLayoutParams()));
- } else if (view instanceof Space) {
- lightsOutParent.addView(new Space(view.getContext()), copy(view.getLayoutParams()));
- } else {
- lightsOutParent.addView(generateLightsOutView(view), copy(view.getLayoutParams()));
- }
- }
-
- private View generateLightsOutView(View view) {
- ImageView imageView = new ImageView(view.getContext());
- // Copy everything we can about the original view.
- imageView.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
- view.getPaddingBottom());
- imageView.setContentDescription(view.getContentDescription());
- imageView.setId(view.getId());
- // Only home gets a big dot, everything else will be little.
- imageView.setImageResource(view.getId() == R.id.home
- ? R.drawable.ic_sysbar_lights_out_dot_large
- : R.drawable.ic_sysbar_lights_out_dot_small);
- return imageView;
- }
-
private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) {
if (layoutParams instanceof LinearLayout.LayoutParams) {
return new LinearLayout.LayoutParams(layoutParams.width, layoutParams.height,
@@ -348,9 +309,7 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
}
}
clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons));
- clearAllChildren((ViewGroup) mRot0.findViewById(R.id.lights_out));
clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons));
- clearAllChildren((ViewGroup) mRot90.findViewById(R.id.lights_out));
}
private void clearAllChildren(ViewGroup group) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 134c5798c94a..1fe01153ea81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -64,42 +64,20 @@ public final class NavigationBarTransitions extends BarTransitions {
mLightsOut = lightsOut;
final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
- final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
// ok, everyone, stop it right there
navButtons.animate().cancel();
- lowLights.animate().cancel();
- final float navButtonsAlpha = lightsOut ? 0f : 1f;
- final float lowLightsAlpha = lightsOut ? 1f : 0f;
+ final float navButtonsAlpha = lightsOut ? 0.5f : 1f;
if (!animate) {
navButtons.setAlpha(navButtonsAlpha);
- lowLights.setAlpha(lowLightsAlpha);
- lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
} else {
final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
navButtons.animate()
.alpha(navButtonsAlpha)
.setDuration(duration)
.start();
-
- lowLights.setOnTouchListener(mLightsOutListener);
- if (lowLights.getVisibility() == View.GONE) {
- lowLights.setAlpha(0f);
- lowLights.setVisibility(View.VISIBLE);
- }
- lowLights.animate()
- .alpha(lowLightsAlpha)
- .setDuration(duration)
- .setInterpolator(new AccelerateInterpolator(2.0f))
- .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator _a) {
- lowLights.setVisibility(View.GONE);
- }
- })
- .start();
}
}
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 5f5974ea94b3..e53f044f4295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -79,7 +79,7 @@ public class NavigationBarView extends LinearLayout {
private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
private Drawable mHomeDefaultIcon, mHomeCarModeIcon;
private Drawable mRecentIcon;
- private Drawable mRecentLandIcon;
+ private Drawable mDockedIcon;
private NavigationBarGestureHelper mGestureHelper;
private DeadZone mDeadZone;
@@ -97,6 +97,7 @@ public class NavigationBarView extends LinearLayout {
private boolean mLayoutTransitionsEnabled = true;
private boolean mWakeAndUnlocking;
private boolean mCarMode = false;
+ private boolean mDockedStackExists;
private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
@@ -280,7 +281,7 @@ public class NavigationBarView extends LinearLayout {
mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
- mRecentLandIcon = mRecentIcon;
+ mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
getCarModeIcons(ctx);
}
@@ -335,8 +336,7 @@ public class NavigationBarView extends LinearLayout {
getBackButton().setImageDrawable(backIcon);
- getRecentsButton().setImageDrawable(
- mVertical ? mRecentLandIcon : mRecentIcon);
+ updateRecentsIcon();
if (mCarMode) {
getHomeButton().setImageDrawable(mHomeCarModeIcon);
@@ -496,8 +496,6 @@ public class NavigationBarView extends LinearLayout {
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
- updateRTLOrder();
-
try {
WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
@Override
@@ -509,20 +507,24 @@ public class NavigationBarView extends LinearLayout {
mHandler.post(new Runnable() {
@Override
public void run() {
- updateRecentsIcon(exists);
+ mDockedStackExists = exists;
+ updateRecentsIcon();
}
});
}
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
+ throws RemoteException {
+ }
});
} catch (RemoteException e) {
Log.e(TAG, "Failed registering docked stack exists listener", e);
}
}
- private void updateRecentsIcon(boolean dockedStackExists) {
- getRecentsButton().setImageResource(dockedStackExists
- ? R.drawable.ic_sysbar_docked
- : R.drawable.ic_sysbar_recent);
+ private void updateRecentsIcon() {
+ getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
}
public boolean isVertical() {
@@ -590,7 +592,6 @@ public class NavigationBarView extends LinearLayout {
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
boolean uiCarModeChanged = updateCarMode(newConfig);
- updateRTLOrder();
updateTaskSwitchHelper();
if (uiCarModeChanged) {
// uiMode changed either from carmode or to carmode.
@@ -618,59 +619,6 @@ public class NavigationBarView extends LinearLayout {
return uiCarModeChanged;
}
- /**
- * In landscape, the LinearLayout is not auto mirrored since it is vertical. Therefore we
- * have to do it manually
- */
- private void updateRTLOrder() {
- boolean isLayoutRtl = getResources().getConfiguration()
- .getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- if (mIsLayoutRtl != isLayoutRtl) {
-
- // We swap all children of the 90 and 270 degree layouts, since they are vertical
- View rotation90 = mRotatedViews[Surface.ROTATION_90];
- swapChildrenOrderIfVertical(rotation90);
-
- View rotation270 = mRotatedViews[Surface.ROTATION_270];
- if (rotation90 != rotation270) {
- swapChildrenOrderIfVertical(rotation270);
- }
- mIsLayoutRtl = isLayoutRtl;
- }
- }
-
- /**
- * Swaps the children order of a LinearLayout if it's orientation is Vertical
- *
- * @param group The LinearLayout to swap the children from.
- */
- private void swapChildrenOrderIfVertical(View group) {
- if (group instanceof LinearLayout) {
- LinearLayout linearLayout = (LinearLayout) group;
- if (linearLayout.getOrientation() == VERTICAL) {
- if ((linearLayout.getGravity() & Gravity.TOP) != 0) {
- linearLayout.setGravity(Gravity.BOTTOM);
- } else if ((linearLayout.getGravity() & Gravity.BOTTOM) != 0) {
- linearLayout.setGravity(Gravity.TOP);
- }
- int childCount = linearLayout.getChildCount();
- ArrayList<View> childList = new ArrayList<>(childCount);
- for (int i = 0; i < childCount; i++) {
- childList.add(linearLayout.getChildAt(i));
- }
- linearLayout.removeAllViews();
- for (int i = childCount - 1; i >= 0; i--) {
- linearLayout.addView(childList.get(i));
- }
- }
- } else if (group instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) group;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- swapChildrenOrderIfVertical(viewGroup.getChildAt(i));
- }
- }
- }
-
/*
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
@@ -738,9 +686,9 @@ public class NavigationBarView extends LinearLayout {
+ (offscreen ? " OFFSCREEN!" : ""));
pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s",
- getResourceName(mCurrentView.getId()),
- mCurrentView.getWidth(), mCurrentView.getHeight(),
- visibilityToString(mCurrentView.getVisibility())));
+ getResourceName(getCurrentView().getId()),
+ getCurrentView().getWidth(), getCurrentView().getHeight(),
+ visibilityToString(getCurrentView().getVisibility())));
pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
mDisabledFlags,
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 03a597c46bc5..6e345f088b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
@@ -32,6 +33,7 @@ public class NotificationIconAreaController {
protected View mNotificationIconArea;
private IconMerger mNotificationIcons;
private ImageView mMoreIcon;
+ private final Rect mTintArea = new Rect();
public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
mPhoneStatusBar = phoneStatusBar;
@@ -67,6 +69,20 @@ public class NotificationIconAreaController {
}
/**
+ * See {@link StatusBarIconController#setIconsDarkArea}.
+ *
+ * @param tintArea the area in which to tint the icons, specified in screen coordinates
+ */
+ public void setTintArea(Rect tintArea) {
+ if (tintArea == null) {
+ mTintArea.setEmpty();
+ } else {
+ mTintArea.set(tintArea);
+ }
+ applyNotificationIconsTint();
+ }
+
+ /**
* Sets the color that should be used to tint any icons in the notification area. If this
* method is not called, the default tint is {@link Color#WHITE}.
*/
@@ -145,7 +161,8 @@ public class NotificationIconAreaController {
boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
if (colorize) {
- v.setImageTintList(ColorStateList.valueOf(mIconTint));
+ v.setImageTintList(ColorStateList.valueOf(
+ StatusBarIconController.getTint(mTintArea, v, mIconTint)));
}
}
}
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 f822bd535851..05ae41be33d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.StatusBarManager;
@@ -35,13 +34,11 @@ import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
-
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
@@ -51,7 +48,6 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.qs.QSContainer;
-import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -91,18 +87,15 @@ public class NotificationPanelView extends PanelView implements
public static final long DOZE_ANIMATION_DURATION = 700;
private KeyguardAffordanceHelper mAfforanceHelper;
- protected BaseStatusBarHeader mHeader;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
- private QSContainer mQsContainer;
- private QSPanel mQsPanel;
+ protected QSContainer mQsContainer;
private KeyguardStatusView mKeyguardStatusView;
- private ObservableScrollView mScrollView;
private TextView mClockView;
private View mReserveNotificationSpace;
private View mQsNavbarScrim;
- private NotificationsQuickSettingsContainer mNotificationContainerParent;
- private NotificationStackScrollLayout mNotificationStackScroller;
+ protected NotificationsQuickSettingsContainer mNotificationContainerParent;
+ protected NotificationStackScrollLayout mNotificationStackScroller;
private boolean mAnimateNextTopPaddingChange;
private int mTrackingPointer;
@@ -133,9 +126,9 @@ public class NotificationPanelView extends PanelView implements
private float mInitialTouchY;
private float mLastTouchX;
private float mLastTouchY;
- private float mQsExpansionHeight;
- private int mQsMinExpansionHeight;
- private int mQsMaxExpansionHeight;
+ protected float mQsExpansionHeight;
+ protected int mQsMinExpansionHeight;
+ protected int mQsMaxExpansionHeight;
private int mQsPeekHeight;
private boolean mStackScrollerOverscrolling;
private boolean mQsExpansionFromOverscroll;
@@ -168,15 +161,12 @@ public class NotificationPanelView extends PanelView implements
* If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
* need to take this into account in our panel height calculation.
*/
- private int mScrollYOverride = -1;
private boolean mQsAnimatorExpand;
private boolean mIsLaunchTransitionFinished;
private boolean mIsLaunchTransitionRunning;
private Runnable mLaunchAnimationEndRunnable;
private boolean mOnlyAffordanceInThisMotion;
private boolean mKeyguardStatusViewAnimating;
- private boolean mHeaderAnimating;
- private ObjectAnimator mQsContainerAnimator;
private ValueAnimator mQsSizeChangeAnimator;
private boolean mShadeEmpty;
@@ -223,19 +213,11 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- ViewStub stub = (ViewStub) findViewById(R.id.status_bar_header);
- stub.setLayoutResource(R.layout.quick_status_bar_expanded_header);
- mHeader = (BaseStatusBarHeader) stub.inflate();
- mHeader.setOnClickListener(this);
mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
- mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+ mQsContainer.getHeader().setOnClickListener(this);
mClockView = (TextView) findViewById(R.id.clock_view);
- mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
- mScrollView.setListener(this);
- mScrollView.setFocusable(false);
- mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
mNotificationContainerParent = (NotificationsQuickSettingsContainer)
findViewById(R.id.notification_container_parent);
mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -243,7 +225,7 @@ public class NotificationPanelView extends PanelView implements
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
- mNotificationStackScroller.setScrollView(mScrollView);
+ mNotificationStackScroller.setQsContainer(mQsContainer);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -285,12 +267,12 @@ public class NotificationPanelView extends PanelView implements
public void updateResources() {
int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mQsContainer.getLayoutParams();
if (lp.width != panelWidth) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mHeader.setLayoutParams(lp);
- mHeader.post(mUpdateHeader);
+ mQsContainer.setLayoutParams(lp);
+ mQsContainer.post(mUpdateHeader);
}
lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -299,13 +281,6 @@ public class NotificationPanelView extends PanelView implements
lp.gravity = panelGravity;
mNotificationStackScroller.setLayoutParams(lp);
}
-
- lp = (FrameLayout.LayoutParams) mScrollView.getLayoutParams();
- if (lp.width != panelWidth) {
- lp.width = panelWidth;
- lp.gravity = panelGravity;
- mScrollView.setLayoutParams(lp);
- }
}
@Override
@@ -318,8 +293,8 @@ public class NotificationPanelView extends PanelView implements
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
- mQsMinExpansionHeight = mKeyguardShowing ? 0 : mHeader.getCollapsedHeight() + mQsPeekHeight;
- mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getDesiredHeight();
+ mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQsContainer.getHeader().getHeight();
+ mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
positionClockAndNotifications();
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
@@ -361,7 +336,7 @@ public class NotificationPanelView extends PanelView implements
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
- mQsContainer.setHeightOverride(height - mHeader.getExpandedHeight());
+ mQsContainer.setHeightOverride(height);
}
});
mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -381,7 +356,7 @@ public class NotificationPanelView extends PanelView implements
boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
int stackScrollerPadding;
if (mStatusBarState != StatusBarState.KEYGUARD) {
- int bottom = mHeader.getCollapsedHeight();
+ int bottom = mQsContainer.getHeader().getHeight();
stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
? bottom + mQsPeekHeight
: mKeyguardStatusBar.getHeight();
@@ -485,7 +460,7 @@ public class NotificationPanelView extends PanelView implements
public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
mQsExpansionEnabled = qsExpansionEnabled;
- mHeader.setClickable(qsExpansionEnabled);
+ mQsContainer.setHeaderClickable(qsExpansionEnabled);
}
@Override
@@ -676,17 +651,6 @@ public class NotificationPanelView extends PanelView implements
}
}
- @Override
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-
- // Block request when interacting with the scroll view so we can still intercept the
- // scrolling when QS is expanded.
- if (mScrollView.isHandlingTouchEvent()) {
- return;
- }
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
-
private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
float vel = getCurrentVelocity();
final boolean expandsQs = flingExpandsQs(vel);
@@ -808,7 +772,7 @@ public class NotificationPanelView extends PanelView implements
}
private boolean isInQsArea(float x, float y) {
- return (x >= mScrollView.getX() && x <= mScrollView.getX() + mScrollView.getWidth()) &&
+ return (x >= mQsContainer.getX() && x <= mQsContainer.getX() + mQsContainer.getWidth()) &&
(y <= mNotificationStackScroller.getBottomMostNotificationBottom()
|| y <= mQsContainer.getY() + mQsContainer.getHeight());
}
@@ -915,7 +879,11 @@ public class NotificationPanelView extends PanelView implements
mQsTracking = false;
mTrackingPointer = -1;
trackMovement(event);
- flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+ float fraction = getQsExpansionFraction();
+ if (fraction != 0f || y >= mInitialTouchY) {
+ flingQsWithCurrentVelocity(y,
+ event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+ }
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
@@ -948,7 +916,7 @@ public class NotificationPanelView extends PanelView implements
amount = 0f;
}
float rounded = amount >= 1f ? amount : 0f;
- mStackScrollerOverscrolling = rounded != 0f && isRubberbanded;
+ setOverScrolling(rounded != 0f && isRubberbanded);
mQsExpansionFromOverscroll = rounded != 0f;
mLastOverscroll = rounded;
updateQsState();
@@ -964,12 +932,17 @@ public class NotificationPanelView extends PanelView implements
@Override
public void run() {
mStackScrollerOverscrolling = false;
- mQsExpansionFromOverscroll = false;
+ setOverScrolling(false);
updateQsState();
}
}, false /* isClick */);
}
+ private void setOverScrolling(boolean overscrolling) {
+ mStackScrollerOverscrolling = overscrolling;
+ mQsContainer.setOverscrolling(overscrolling);
+ }
+
private void onQsExpansionStarted() {
onQsExpansionStarted(0);
}
@@ -979,11 +952,7 @@ public class NotificationPanelView extends PanelView implements
cancelHeightAnimator();
// Reset scroll position and apply that position to the expanded height.
- float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
- if (mScrollView.getScrollY() != 0) {
- mScrollYOverride = mScrollView.getScrollY();
- }
- mScrollView.scrollTo(0, 0);
+ float height = mQsExpansionHeight - overscrollAmount;
setQsExpansion(height);
requestPanelHeightUpdate();
}
@@ -995,9 +964,7 @@ public class NotificationPanelView extends PanelView implements
updateQsState();
requestPanelHeightUpdate();
mFalsingManager.setQsExpanded(expanded);
- mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
mStatusBar.setQsExpanded(expanded);
- mQsPanel.setExpanded(expanded);
mNotificationContainerParent.setQsExpanded(expanded);
}
}
@@ -1011,15 +978,18 @@ public class NotificationPanelView extends PanelView implements
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
+ mQsContainer.setKeyguardShowing(mKeyguardShowing);
if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
&& statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
- animateHeaderSlidingIn();
+ long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
+ ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
+ mQsContainer.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == StatusBarState.KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- animateHeaderSlidingOut();
+ mQsContainer.animateHeaderSlidingOut();
} else {
mKeyguardStatusBar.setAlpha(1f);
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
@@ -1050,95 +1020,6 @@ public class NotificationPanelView extends PanelView implements
}
};
- private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
- = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeaderAnimating = false;
- mQsContainerAnimator = null;
- mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
- }
- };
-
- private final OnLayoutChangeListener mQsContainerAnimatorUpdater
- = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- int oldHeight = oldBottom - oldTop;
- int height = bottom - top;
- if (height != oldHeight && mQsContainerAnimator != null) {
- PropertyValuesHolder[] values = mQsContainerAnimator.getValues();
- float newEndValue = mHeader.getCollapsedHeight() + mQsPeekHeight - height - top;
- float newStartValue = -height - top;
- values[0].setFloatValues(newStartValue, newEndValue);
- mQsContainerAnimator.setCurrentPlayTime(mQsContainerAnimator.getCurrentPlayTime());
- }
- }
- };
-
- private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
- = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getViewTreeObserver().removeOnPreDrawListener(this);
- long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
- ? 0
- : mStatusBar.calculateGoingToFullShadeDelay();
- mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
- mHeader.animate()
- .translationY(0f)
- .setStartDelay(delay)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- mQsContainer.setY(-mQsContainer.getHeight());
- mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
- mQsContainer.getTranslationY(),
- mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
- - mQsContainer.getTop());
- mQsContainerAnimator.setStartDelay(delay);
- mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
- mQsContainerAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
- mQsContainerAnimator.start();
- mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
- return true;
- }
- };
-
- private void animateHeaderSlidingIn() {
- // If the QS is already expanded we don't need to slide in the header as it's already
- // visible.
- if (!mQsExpanded) {
- mHeaderAnimating = true;
- getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
- }
- }
-
- private void animateHeaderSlidingOut() {
- mHeaderAnimating = true;
- mHeader.animate().y(-mHeader.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeader.animate().setListener(null);
- mHeaderAnimating = false;
- updateQsState();
- }
- })
- .start();
- mQsContainer.animate()
- .y(-mQsContainer.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- }
-
private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
@Override
public void run() {
@@ -1195,8 +1076,8 @@ public class NotificationPanelView extends PanelView implements
private void setKeyguardBottomAreaVisibility(int statusBarState,
boolean goingToFullShade) {
+ mKeyguardBottomArea.animate().cancel();
if (goingToFullShade) {
- mKeyguardBottomArea.animate().cancel();
mKeyguardBottomArea.animate()
.alpha(0f)
.setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
@@ -1206,13 +1087,11 @@ public class NotificationPanelView extends PanelView implements
.start();
} else if (statusBarState == StatusBarState.KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
- mKeyguardBottomArea.animate().cancel();
if (!mDozing) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
}
mKeyguardBottomArea.setAlpha(1f);
} else {
- mKeyguardBottomArea.animate().cancel();
mKeyguardBottomArea.setVisibility(View.GONE);
mKeyguardBottomArea.setAlpha(1f);
}
@@ -1262,19 +1141,10 @@ public class NotificationPanelView extends PanelView implements
}
private void updateQsState() {
- boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
- mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
- ? View.VISIBLE
- : View.INVISIBLE);
- mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
- || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQsContainer.setExpanded(mQsExpanded);
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
- mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
- mQsContainer.setVisibility(
- mKeyguardShowing && !expandVisually ? View.INVISIBLE : View.VISIBLE);
- mScrollView.setTouchEnabled(mQsExpanded);
updateEmptyShadeView();
mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
&& !mStackScrollerOverscrolling && mQsScrimEnabled
@@ -1298,11 +1168,10 @@ public class NotificationPanelView extends PanelView implements
}
}
mQsExpansionHeight = height;
- mHeader.setExpansion(getHeaderExpansionFraction());
- setQsTranslation(height);
+ updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
if (mKeyguardShowing) {
- updateHeaderKeyguard();
+ updateHeaderKeyguardAlpha();
}
if (mStatusBarState == StatusBarState.SHADE_LOCKED
|| mStatusBarState == StatusBarState.KEYGUARD) {
@@ -1329,6 +1198,10 @@ public class NotificationPanelView extends PanelView implements
}
}
+ protected void updateQsExpansion() {
+ mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
+ }
+
private String getKeyguardOrLockScreenString() {
if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
@@ -1337,23 +1210,6 @@ public class NotificationPanelView extends PanelView implements
}
}
- private float getHeaderExpansionFraction() {
- if (!mKeyguardShowing) {
- return getQsExpansionFraction();
- } else {
- return 1f;
- }
- }
-
- private void setQsTranslation(float height) {
- if (!mHeaderAnimating) {
- mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
- }
- if (mKeyguardShowing && !mHeaderAnimating) {
- mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
- }
- }
-
private float calculateQsTopPadding() {
if (mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
@@ -1372,7 +1228,7 @@ public class NotificationPanelView extends PanelView implements
mQsMinExpansionHeight, max);
} else if (mQsSizeChangeAnimator != null) {
return (int) mQsSizeChangeAnimator.getAnimatedValue();
- } else if (mKeyguardShowing && mScrollYOverride == -1) {
+ } else if (mKeyguardShowing) {
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
@@ -1384,9 +1240,8 @@ public class NotificationPanelView extends PanelView implements
}
}
- private void requestScrollerTopPaddingUpdate(boolean animate) {
+ protected void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
- mScrollView.getScrollY(),
mAnimateNextTopPaddingChange || animate,
mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted));
@@ -1428,7 +1283,6 @@ public class NotificationPanelView extends PanelView implements
boolean isClick) {
float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
if (target == mQsExpansionHeight) {
- mScrollYOverride = -1;
if (onFinishRunnable != null) {
onFinishRunnable.run();
}
@@ -1438,7 +1292,6 @@ public class NotificationPanelView extends PanelView implements
if (belowFalsingThreshold) {
vel = 0;
}
- mScrollView.setBlockFlinging(true);
ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
if (isClick) {
animator.setInterpolator(Interpolators.TOUCH_RESPONSE);
@@ -1458,8 +1311,6 @@ public class NotificationPanelView extends PanelView implements
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mScrollView.setBlockFlinging(false);
- mScrollYOverride = -1;
mQsExpansionAnimator = null;
if (onFinishRunnable != null) {
onFinishRunnable.run();
@@ -1478,11 +1329,11 @@ public class NotificationPanelView extends PanelView implements
if (!mQsExpansionEnabled || mCollapsedOnDown) {
return false;
}
- View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
+ View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
- return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
+ return onHeader || (yDiff < 0 && isInQsArea(x, y));
} else {
return onHeader;
}
@@ -1494,7 +1345,7 @@ public class NotificationPanelView extends PanelView implements
return mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mNotificationStackScroller.isScrolledToBottom();
} else {
- return mScrollView.isScrolledToBottom();
+ return true;
}
}
@@ -1571,11 +1422,7 @@ public class NotificationPanelView extends PanelView implements
* collapsing QS / the panel when QS was scrolled
*/
private int getTempQsMaxExpansion() {
- int qsTempMaxExpansion = mQsMaxExpansionHeight;
- if (mScrollYOverride != -1) {
- qsTempMaxExpansion -= mScrollYOverride;
- }
- return qsTempMaxExpansion;
+ return mQsMaxExpansionHeight;
}
private int calculatePanelHeightShade() {
@@ -1613,20 +1460,12 @@ public class NotificationPanelView extends PanelView implements
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
- + mNotificationStackScroller.getMinStackHeight()
- - getScrollViewScrollY();
+ + mNotificationStackScroller.getMinStackHeight();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
return (int) totalHeight;
}
- private int getScrollViewScrollY() {
- if (mScrollYOverride != -1 && !mQsTracking) {
- return mScrollYOverride;
- } else {
- return mScrollView.getScrollY();
- }
- }
private void updateNotificationTranslucency() {
float alpha = 1f;
if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
@@ -1678,30 +1517,17 @@ public class NotificationPanelView extends PanelView implements
*/
private void updateHeader() {
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
- updateHeaderKeyguard();
- } else {
- updateHeaderShade();
- }
-
- }
-
- private void updateHeaderShade() {
- if (!mHeaderAnimating) {
- mHeader.setTranslationY(getHeaderTranslation());
+ updateHeaderKeyguardAlpha();
}
- setQsTranslation(mQsExpansionHeight);
+ updateQsExpansion();
}
- private float getHeaderTranslation() {
+ protected float getHeaderTranslation() {
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
return 0;
}
if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
- if (mExpandedHeight / HEADER_RUBBERBAND_FACTOR >= mQsMinExpansionHeight) {
- return 0;
- } else {
- return mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight;
- }
+ return Math.min(0, mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight);
}
float stackTranslation = mNotificationStackScroller.getStackTranslation();
float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
@@ -1744,11 +1570,6 @@ public class NotificationPanelView extends PanelView implements
&& !mDozing ? VISIBLE : INVISIBLE);
}
- private void updateHeaderKeyguard() {
- updateHeaderKeyguardAlpha();
- setQsTranslation(mQsExpansionHeight);
- }
-
private void updateKeyguardBottomAreaAlpha() {
float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
@@ -1781,7 +1602,6 @@ public class NotificationPanelView extends PanelView implements
mNotificationStackScroller.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
mIsExpanding = false;
- mScrollYOverride = -1;
if (isFullyCollapsed()) {
DejankUtils.postAfterTraversal(new Runnable() {
@Override
@@ -1811,9 +1631,8 @@ public class NotificationPanelView extends PanelView implements
}
private void setListening(boolean listening) {
- mHeader.setListening(listening);
+ mQsContainer.setListening(listening);
mKeyguardStatusBar.setListening(listening);
- mQsPanel.setListening(listening);
}
@Override
@@ -1931,7 +1750,7 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onClick(View v) {
- if (v == mHeader) {
+ if (v == mQsContainer.getHeader()) {
onQsExpansionStarted();
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
@@ -2149,24 +1968,16 @@ public class NotificationPanelView extends PanelView implements
return mConflictingQsExpansionGesture && mQsExpanded;
}
- public void notifyVisibleChildrenChanged() {
- if (mNotificationStackScroller.getNotGoneChildCount() != 0) {
- mReserveNotificationSpace.setVisibility(View.VISIBLE);
- } else {
- mReserveNotificationSpace.setVisibility(View.GONE);
- }
- }
-
public boolean isQsExpanded() {
return mQsExpanded;
}
public boolean isQsDetailShowing() {
- return mQsPanel.isShowingDetail();
+ return mQsContainer.isShowingDetail();
}
public void closeQsDetail() {
- mQsPanel.closeDetail();
+ mQsContainer.getQsPanel().closeDetail();
}
@Override
@@ -2254,7 +2065,7 @@ public class NotificationPanelView extends PanelView implements
private final Runnable mUpdateHeader = new Runnable() {
@Override
public void run() {
- mHeader.updateEverything();
+ mQsContainer.getHeader().updateEverything();
}
};
@@ -2378,7 +2189,7 @@ public class NotificationPanelView extends PanelView implements
*
* @param x the x-coordinate the touch event
*/
- private void updateVerticalPanelPosition(float x) {
+ protected void updateVerticalPanelPosition(float x) {
if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
resetVerticalPanelPosition();
return;
@@ -2400,11 +2211,10 @@ public class NotificationPanelView extends PanelView implements
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
- mScrollView.setTranslationX(translation);
- mHeader.setTranslationX(translation);
+ mQsContainer.setTranslationX(translation);
}
- private void updateStackHeight(float stackHeight) {
+ protected void updateStackHeight(float stackHeight) {
mNotificationStackScroller.setStackHeight(stackHeight);
updateKeyguardBottomAreaAlpha();
}
@@ -2413,7 +2223,7 @@ public class NotificationPanelView extends PanelView implements
mBar.panelScrimMinFractionChanged(minFraction);
}
- public void clearNotificattonEffects() {
+ public void clearNotificationEffects() {
mStatusBar.clearNotificationEffects();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index fd28b095c09d..7cc720df1c27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -33,7 +33,7 @@ import com.android.systemui.R;
public class NotificationsQuickSettingsContainer extends FrameLayout
implements ViewStub.OnInflateListener {
- private View mScrollView;
+ private View mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
private View mKeyguardStatusBar;
@@ -47,7 +47,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mScrollView = findViewById(R.id.scroll_view);
+ mQsContainer = findViewById(R.id.quick_settings_container);
mStackScroller = findViewById(R.id.notification_stack_scroller);
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
@@ -58,7 +58,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- reloadWidth(mScrollView);
+ reloadWidth(mQsContainer);
reloadWidth(mStackScroller);
}
@@ -80,11 +80,11 @@ public class NotificationsQuickSettingsContainer extends FrameLayout
boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
- View stackQsTop = mQsExpanded ? mStackScroller : mScrollView;
- View stackQsBottom = !mQsExpanded ? mStackScroller : mScrollView;
+ View stackQsTop = mQsExpanded ? mStackScroller : mQsContainer;
+ View stackQsBottom = !mQsExpanded ? mStackScroller : mQsContainer;
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
- if (child == mScrollView) {
+ if (child == mQsContainer) {
return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
: statusBarVisible ? mKeyguardStatusBar
: userSwitcherVisible ? mUserSwitcher
@@ -104,7 +104,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout
return super.drawChild(canvas,
stackQsTop,
drawingTime);
- }else {
+ } else {
return super.drawChild(canvas, child, drawingTime);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 09a7bf08ec19..9b87a8adbeb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -23,10 +23,10 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.app.IWallpaperManagerCallback;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
@@ -68,7 +68,6 @@ import android.os.Process;
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.os.Vibrator;
@@ -95,7 +94,6 @@ import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.TextView;
-
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
@@ -111,11 +109,13 @@ import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.recents.events.EventBus;
@@ -174,7 +174,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.TreeSet;
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
@@ -249,9 +248,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private static final boolean ONLY_CORE_APPS;
/** If true, the lockscreen will show a distinct wallpaper */
- private static final boolean ENABLE_LOCKSCREEN_WALLPAPER =
- !ActivityManager.isLowRamDeviceStatic()
- && SystemProperties.getBoolean("debug.lockscreen_wallpaper", false);
+ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
/* If true, the device supports freeform window management.
* This affects the status bar UI. */
@@ -265,7 +262,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
onlyCoreApps = packageManager.isOnlyCoreApps();
freeformWindowManagement = packageManager.hasSystemFeature(
- PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, 0);
} catch (RemoteException e) {
onlyCoreApps = false;
freeformWindowManagement = false;
@@ -296,6 +293,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
BrightnessMirrorController mBrightnessMirrorController;
AccessibilityController mAccessibilityController;
FingerprintUnlockController mFingerprintUnlockController;
+ LightStatusBarController mLightStatusBarController;
+ protected LockscreenWallpaper mLockscreenWallpaper;
int mNaturalBarHeight = -1;
@@ -318,7 +317,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
StatusBarIconController mIconController;
// expanded notifications
- NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
+ protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
View mExpandedContents;
TextView mNotificationPanelDebugText;
@@ -340,6 +339,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
+ // RemoteInputView to be activated after unlock
+ private View mPendingRemoteInputView;
+
int mMaxAllowedKeyguardNotifications;
boolean mExpandedVisible;
@@ -361,6 +363,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// tracking calls to View.setSystemUiVisibility()
int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ private final Rect mLastFullscreenStackBounds = new Rect();
+ private final Rect mLastDockedStackBounds = new Rect();
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
@@ -519,7 +523,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
*/
protected boolean mStartedGoingToSleep;
- private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
+ private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN
| StackViewState.LOCATION_MAIN_AREA;
private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
@@ -641,7 +645,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
mHotspotController, mUserInfoController, mBluetoothController,
- mRotationLockController);
+ mRotationLockController, mNetworkController.getDataSaverController());
mIconPolicy.setCurrentUserSetup(mUserSetup);
mSettingsObserver.onChange(false); // set up
@@ -741,6 +745,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
R.id.notification_stack_scroller);
mStackScroller.setLongPressListener(getNotificationLongClicker());
+ mStackScroller.setGearDisplayedListener(getGearDisplayedListener());
mStackScroller.setPhoneStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setHeadsUpManager(mHeadsUpManager);
@@ -754,19 +759,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
- mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_no_notifications, mStackScroller, false);
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
- mDismissView.setOnButtonClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
- clearAllNotifications();
- }
- });
- mStackScroller.setDismissView(mDismissView);
+ inflateEmptyShadeView();
+ inflateDismissView();
mExpandedContents = mStackScroller;
mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
@@ -776,8 +770,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
- mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
- mScrimSrcModeEnabled);
+ mScrimController = SystemUIFactory.getInstance().createScrimController(
+ scrimBehind, scrimInFront, headsUpScrim, mScrimSrcModeEnabled);
mHeadsUpManager.addListener(mScrimController);
mStackScroller.setScrimController(mScrimController);
mScrimController.setBackDropView(mBackdrop);
@@ -798,6 +792,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardBottomArea.getLockIcon());
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
+ if (ENABLE_LOCKSCREEN_WALLPAPER) {
+ mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
+ }
+
// set the initial view visibility
setAreThereNotifications();
@@ -855,6 +853,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mAccessibilityController = new AccessibilityController(mContext);
mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
mNextAlarmController = new NextAlarmController(mContext);
+ mLightStatusBarController = new LightStatusBarController(mIconController,
+ mBatteryController);
mKeyguardMonitor = new KeyguardMonitor(mContext);
if (UserManager.get(mContext).isUserSwitcherEnabled()) {
mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
@@ -871,11 +871,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mCastController, mFlashlightController,
mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
mSecurityController, mBatteryController, mIconController);
- mQSPanel.setHost(qsh);
mQSPanel.setTiles(qsh.getTiles());
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
- mHeader.setQSPanel(mQSPanel);
+ QSContainer qsContainer = (QSContainer) mStatusBarWindow.findViewById(
+ R.id.quick_settings_container);
+ qsContainer.setHost(qsh);
qsh.addCallback(new QSTileHost.Callback() {
@Override
public void onTilesChanged() {
@@ -930,6 +931,34 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mStatusBarView;
}
+ @Override
+ protected void reInflateViews() {
+ super.reInflateViews();
+ inflateDismissView();
+ updateClearAll();
+ inflateEmptyShadeView();
+ updateEmptyShadeView();
+ }
+
+ private void inflateEmptyShadeView() {
+ mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_no_notifications, mStackScroller, false);
+ mStackScroller.setEmptyShadeView(mEmptyShadeView);
+ }
+
+ private void inflateDismissView() {
+ mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
+ mDismissView.setOnButtonClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
+ clearAllNotifications();
+ }
+ });
+ mStackScroller.setDismissView(mDismissView);
+ }
+
protected void createUserSwitcher() {
mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
(ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
@@ -1072,6 +1101,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
+ mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
}
@Override
@@ -1114,31 +1144,42 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public boolean onLongClick(View v) {
- if (mRecents != null) {
- int dockSide = WindowManagerProxy.getInstance().getDockSide();
- if (dockSide == WindowManager.DOCKED_INVALID) {
- Point realSize = new Point();
- mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
- .getRealSize(realSize);
- Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y);
- boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
- initialBounds);
- if (docked) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
- return true;
- }
- } else {
- EventBus.getDefault().send(new UndockingTaskEvent());
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
- return true;
- }
-
+ if (mRecents == null) {
+ return false;
+ }
+ boolean initiallyDocked = WindowManagerProxy.getInstance().getDockSide()
+ == WindowManager.DOCKED_INVALID;
+ boolean dockedAtEnd = toggleSplitScreenMode();
+ if (dockedAtEnd != initiallyDocked) {
+ int logAction = dockedAtEnd ? MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS
+ : MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS;
+ MetricsLogger.action(mContext, logAction);
+ return true;
}
return false;
}
};
+ @Override
+ protected boolean toggleSplitScreenMode() {
+ if (mRecents == null) {
+ return false;
+ }
+ int dockSide = WindowManagerProxy.getInstance().getDockSide();
+ if (dockSide == WindowManager.DOCKED_INVALID) {
+ Point realSize = new Point();
+ mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+ .getRealSize(realSize);
+ Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y);
+ return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
+ ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
+ initialBounds);
+ } else {
+ EventBus.getDefault().send(new UndockingTaskEvent());
+ return false;
+ }
+ }
+
private final View.OnLongClickListener mLongPressHomeListener
= new View.OnLongClickListener() {
@Override
@@ -1278,6 +1319,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (DEBUG) {
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
}
+ } else if (mNotificationData.getImportance(notification.getKey())
+ < NotificationListenerService.Ranking.IMPORTANCE_MAX) {
+ if (DEBUG) {
+ Log.d(TAG, "No Fullscreen intent: not important enough: "
+ + notification.getKey());
+ }
} else {
// Stop screensaver if the notification has a full-screen intent.
// (like an incoming phone call)
@@ -1384,7 +1431,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (showingPublic) {
updatePublicContentView(ent, ent.notification);
}
- ent.row.setSensitive(sensitive);
+ ent.row.setSensitive(sensitive, hideSensitive);
if (ent.autoRedacted && ent.legacy) {
// TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
// for legacy auto redacted notifications.
@@ -1483,8 +1530,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void updateNotificationShadeForChildren() {
+ // First let's remove all children which don't belong in the parents
ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
- boolean orderChanged = false;
for (int i = 0; i < mStackScroller.getChildCount(); i++) {
View view = mStackScroller.getChildAt(i);
if (!(view instanceof ExpandableNotificationRow)) {
@@ -1496,7 +1543,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
List<ExpandableNotificationRow> children = parent.getNotificationChildren();
List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
- // lets first remove all undesired children
if (children != null) {
toRemove.clear();
for (ExpandableNotificationRow childRow : children) {
@@ -1509,8 +1555,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.notifyGroupChildRemoved(remove);
}
}
+ }
+
+ // Let's now add all notification children which are missing
+ boolean orderChanged = false;
+ for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+ View view = mStackScroller.getChildAt(i);
+ if (!(view instanceof ExpandableNotificationRow)) {
+ // We don't care about non-notification views.
+ continue;
+ }
+
+ ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+ List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+ List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
- // We now add all the children which are not in there already
for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
childIndex++) {
ExpandableNotificationRow childView = orderedChildren.get(childIndex);
@@ -1600,12 +1659,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- protected void updateRowStates() {
- super.updateRowStates();
- mNotificationPanel.notifyVisibleChildrenChanged();
- }
-
- @Override
protected void setAreThereNotifications() {
if (SPEW) {
@@ -1786,7 +1839,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
};
/**
- * Refresh or remove lockscreen artwork from media metadata.
+ * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
@@ -1814,10 +1867,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
if (ENABLE_LOCKSCREEN_WALLPAPER && artworkBitmap == null) {
- // TODO: use real lockscreen wallpaper.
- WallpaperManager wallpaperManager = mContext
- .getSystemService(WallpaperManager.class);
- artworkBitmap = wallpaperManager.getBitmap();
+ artworkBitmap = mLockscreenWallpaper.getBitmap();
}
final boolean hasArtwork = artworkBitmap != null;
@@ -2227,7 +2277,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void maybeEscalateHeadsUp() {
- TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries();
+ Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
for (HeadsUpManager.HeadsUpEntry entry : entries) {
final StatusBarNotification sbn = entry.entry.notification;
final Notification notification = sbn.getNotification();
@@ -2513,7 +2563,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override // CommandQueue
- public void setSystemUiVisibility(int vis, int mask) {
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
final int oldVal = mSystemUiVisibility;
final int newVal = (oldVal&~mask) | (vis&mask);
final int diff = newVal ^ oldVal;
@@ -2522,6 +2573,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
Integer.toHexString(vis), Integer.toHexString(mask),
Integer.toHexString(oldVal), Integer.toHexString(newVal),
Integer.toHexString(diff)));
+ boolean sbModeChanged = false;
if (diff != 0) {
// we never set the recents bit via this method, so save the prior state to prevent
// clobbering the bit below
@@ -2555,7 +2607,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
oldVal, newVal, mNavigationBarView.getBarTransitions(),
View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
View.NAVIGATION_BAR_TRANSPARENT);
- final boolean sbModeChanged = sbMode != -1;
+ sbModeChanged = sbMode != -1;
final boolean nbModeChanged = nbMode != -1;
boolean checkBarModes = false;
if (sbModeChanged && sbMode != mStatusBarMode) {
@@ -2582,18 +2634,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
}
- if ((diff & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 || sbModeChanged) {
- boolean isTransparentBar = (mStatusBarMode == MODE_TRANSPARENT
- || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
- boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
- boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
- boolean animate = mFingerprintUnlockController == null
- || (mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- && mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
- mIconController.setIconsDark(allowLight && light, animate);
- }
// restore the recents bit
if (wasRecentsVisible) {
mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
@@ -2602,6 +2642,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// send updated sysui visibility to window manager
notifyUiVisibilityChanged(mSystemUiVisibility);
}
+
+ mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
+ mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
}
private int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
@@ -2729,9 +2772,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void setLightsOn(boolean on) {
Log.v(TAG, "setLightsOn(" + on + ")");
if (on) {
- setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
+ mLastFullscreenStackBounds, mLastDockedStackBounds);
} else {
- setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
+ View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
+ mLastDockedStackBounds);
}
}
@@ -3055,10 +3101,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
notifyNavigationBarScreenOn(true);
}
- else if (ENABLE_LOCKSCREEN_WALLPAPER
- && Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
- updateMediaMetaData(true, true);
- }
}
};
@@ -3144,6 +3186,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
resetUserSetupObserver();
setControllerUsers();
clearCurrentMediaNotification();
+ mLockscreenWallpaper.setCurrentUser(newUserId);
updateMediaMetaData(true, false);
}
@@ -3553,6 +3596,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */);
mDraggedDownRow = null;
}
+ mPendingRemoteInputView = null;
mAssistManager.onLockscreenShown();
}
@@ -3669,6 +3713,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public boolean hideKeyguard() {
boolean staying = mLeaveOpenOnKeyguardHide;
setBarState(StatusBarState.SHADE);
+ View viewToClick = null;
if (mLeaveOpenOnKeyguardHide) {
mLeaveOpenOnKeyguardHide = false;
long delay = calculateGoingToFullShadeDelay();
@@ -3677,6 +3722,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mDraggedDownRow.setUserLocked(false);
mDraggedDownRow = null;
}
+ viewToClick = mPendingRemoteInputView;
+ mPendingRemoteInputView = null;
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
@@ -3694,6 +3741,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
updateKeyguardState(staying, false /* fromShadeLocked */);
+ if (viewToClick != null) {
+ viewToClick.callOnClick();
+ }
+
// Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
// visibilities so next time we open the panel we know the correct height already.
if (mQSPanel != null) {
@@ -3843,7 +3894,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public boolean onMenuPressed() {
- return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
+ if (mDeviceInteractive && mState != StatusBarState.SHADE
+ && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed()) {
+ animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
+ return true;
+ }
+ return false;
}
public void endAffordanceLaunch() {
@@ -4049,7 +4106,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView;
- row.setUserExpanded(true);
+ row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
}
boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
|| !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
@@ -4057,6 +4114,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mLeaveOpenOnKeyguardHide = true;
showBouncer();
mDraggedDownRow = row;
+ mPendingRemoteInputView = null;
} else {
mNotificationPanel.animateToFullShade(0 /* delay */);
setBarState(StatusBarState.SHADE_LOCKED);
@@ -4065,6 +4123,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
+ protected void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
+ mLeaveOpenOnKeyguardHide = true;
+ showBouncer();
+ mPendingRemoteInputView = clicked;
+ }
+
+ @Override
public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
if (mState == StatusBarState.KEYGUARD && nowExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index df5a62229633..c883cc9284db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -44,6 +44,7 @@ import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothController.Callback;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
+import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -53,7 +54,7 @@ import com.android.systemui.statusbar.policy.UserInfoController;
* bar at boot time. It goes through the normal API for icons, even though it probably
* strictly doesn't need to.
*/
-public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback {
+public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback, DataSaverController.Listener {
private static final String TAG = "PhoneStatusBarPolicy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -67,6 +68,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
private final String mSlotManagedProfile;
private final String mSlotRotate;
private final String mSlotHeadset;
+ private final String mSlotDataSaver;
private final Context mContext;
private final Handler mHandler = new Handler();
@@ -77,6 +79,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
private final UserManager mUserManager;
private final StatusBarIconController mIconController;
private final RotationLockController mRotationLockController;
+ private final DataSaverController mDataSaver;
// Assume it's all good unless we hear otherwise. We don't always seem
// to get broadcasts that it *is* there.
@@ -97,7 +100,8 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController,
CastController cast, HotspotController hotspot, UserInfoController userInfoController,
- BluetoothController bluetooth, RotationLockController rotationLockController) {
+ BluetoothController bluetooth, RotationLockController rotationLockController,
+ DataSaverController dataSaver) {
mContext = context;
mIconController = iconController;
mCast = cast;
@@ -108,6 +112,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
mUserInfoController = userInfoController;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mRotationLockController = rotationLockController;
+ mDataSaver = dataSaver;
mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -120,6 +125,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
com.android.internal.R.string.status_bar_managed_profile);
mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);
mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
+ mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
mRotationLockController.addRotationLockControllerCallback(this);
@@ -176,6 +182,12 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
mContext.getString(R.string.accessibility_managed_profile));
mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);
+
+ // data saver
+ mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
+ context.getString(R.string.accessibility_data_saver_on));
+ mIconController.setIconVisibility(mSlotDataSaver, false);
+ mDataSaver.addListener(this);
}
public void setZenMode(int zen) {
@@ -456,11 +468,9 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape,
mContext.getString(R.string.accessibility_rotation_lock_on_landscape));
}
+ mIconController.setIconVisibility(mSlotRotate, true);
} else {
- mIconController.setIcon(mSlotRotate, portrait
- ? R.drawable.stat_sys_auto_rotate_portrait
- : R.drawable.stat_sys_auto_rotate_landscape,
- mContext.getString(R.string.accessibility_rotation_lock_off));
+ mIconController.setIconVisibility(mSlotRotate, false);
}
}
@@ -479,6 +489,11 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
}
}
+ @Override
+ public void onDataSaverChanged(boolean isDataSaving) {
+ mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
+ }
+
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
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 da2c20db6d90..80afb9a3c705 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -57,7 +57,7 @@ import com.android.systemui.qs.tiles.WorkModeTile;
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.DisplayController;
+import com.android.systemui.statusbar.policy.NightModeController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -68,7 +68,7 @@ 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.ColorMatrixTile;
+import com.android.systemui.tuner.NightModeTile;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -108,7 +108,7 @@ public final class QSTileHost implements QSTile.Host, Tunable {
private final TileServices mServices;
private final List<Callback> mCallbacks = new ArrayList<>();
- private final DisplayController mDisplayController;
+ private final NightModeController mNightModeController;
private final AutoTileManager mAutoTiles;
private final ManagedProfileController mProfileController;
private View mHeader;
@@ -137,7 +137,7 @@ public final class QSTileHost implements QSTile.Host, Tunable {
mSecurity = security;
mBattery = battery;
mIconController = iconController;
- mDisplayController = new DisplayController(mContext);
+ mNightModeController = new NightModeController(mContext, true);
mProfileController = new ManagedProfileController(this);
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
@@ -147,8 +147,9 @@ public final class QSTileHost implements QSTile.Host, Tunable {
mServices = new TileServices(this, mLooper);
- mAutoTiles = new AutoTileManager(context, this);
TunerService.get(mContext).addTunable(this, TILES_SETTING);
+ // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
+ mAutoTiles = new AutoTileManager(context, this);
}
public void setHeaderView(View view) {
@@ -291,8 +292,8 @@ public final class QSTileHost implements QSTile.Host, Tunable {
return mIconController;
}
- public DisplayController getDisplayController() {
- return mDisplayController;
+ public NightModeController getNightModeController() {
+ return mNightModeController;
}
public ManagedProfileController getManagedProfileController() {
@@ -421,8 +422,8 @@ public final class QSTileHost implements QSTile.Host, Tunable {
else if (tileSpec.equals("user")) return new UserTile(this);
else if (tileSpec.equals("battery")) return new BatteryTile(this);
else if (tileSpec.equals("saver")) return new DataSaverTile(this);
- else if (tileSpec.equals(ColorMatrixTile.COLOR_MATRIX_SPEC))
- return new ColorMatrixTile(this);
+ else if (tileSpec.equals(NightModeTile.NIGHT_MODE_SPEC))
+ return new NightModeTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
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 fe463855020a..b549d5912117 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -20,62 +20,76 @@ import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Rect;
-import android.graphics.drawable.Animatable;
+import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
-import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.qs.QSAnimator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QuickQSPanel;
+import com.android.systemui.qs.TouchAnimator;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tuner.TunerService;
public class QuickStatusBarHeader extends BaseStatusBarHeader implements
- NextAlarmController.NextAlarmChangeCallback, View.OnClickListener {
+ NextAlarmChangeCallback, OnClickListener {
private static final String TAG = "QuickStatusBarHeader";
+
+ private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
+
private ActivityStarter mActivityStarter;
private NextAlarmController mNextAlarmController;
private SettingsButton mSettingsButton;
private View mSettingsContainer;
+
private TextView mAlarmStatus;
- private View mQsDetailHeader;
+ private TextView mAlarmStatusCollapsed;
- private ImageView mQsDetailHeaderProgress;
private QSPanel mQsPanel;
- private Switch mQsDetailHeaderSwitch;
private boolean mExpanded;
private boolean mAlarmShowing;
- private boolean mShowingDetail;
- private boolean mDetailTransitioning;
- private ViewGroup mExpandedGroup;
private ViewGroup mDateTimeGroup;
- private View mEmergencyOnly;
- private TextView mQsDetailHeaderTitle;
+ private ViewGroup mDateTimeAlarmGroup;
+ private TextView mEmergencyOnly;
+
+ private ExpandableIndicator mExpandIndicator;
+
private boolean mListening;
private AlarmManager.AlarmClockInfo mNextAlarm;
private QuickQSPanel mHeaderQsPanel;
private boolean mShowEmergencyCallsOnly;
- private float mDateTimeTranslation;
private MultiUserSwitch mMultiUserSwitch;
private ImageView mMultiUserAvatar;
- private View mQsDetailHeaderBack;
- private final int[] mTmpInt2 = new int[2];
+ private float mDateTimeTranslation;
+ private float mDateTimeAlarmTranslation;
+ private float mDateScaleFactor;
+ private float mGearTranslation;
+
+ private TouchAnimator mAnimator;
+ private TouchAnimator mSecondHalfAnimator;
+ private TouchAnimator mFirstHalfAnimator;
+ private TouchAnimator mDateSizeAnimator;
+ private TouchAnimator mAlarmTranslation;
+ private TouchAnimator mSettingsAlpha;
+ private float mExpansionAmount;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -85,12 +99,15 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
protected void onFinishInflate() {
super.onFinishInflate();
- mEmergencyOnly = findViewById(R.id.header_emergency_calls_only);
- mDateTimeTranslation = mContext.getResources().getDimension(
- R.dimen.qs_date_anim_translation);
+ mEmergencyOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
+
+ 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.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
- mExpandedGroup = (ViewGroup) findViewById(R.id.expanded_group);
+ mDateTimeGroup.setPivotX(0);
+ mDateTimeGroup.setPivotY(0);
+
+ mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator);
mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel);
@@ -98,16 +115,10 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
mSettingsContainer = findViewById(R.id.settings_button_container);
mSettingsButton.setOnClickListener(this);
+ mAlarmStatusCollapsed = (TextView) findViewById(R.id.alarm_status_collapsed);
mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
mAlarmStatus.setOnClickListener(this);
- mQsDetailHeader = findViewById(R.id.qs_detail_header);
- mQsDetailHeader.setAlpha(0);
- mQsDetailHeaderBack = mQsDetailHeader.findViewById(com.android.internal.R.id.up);
- mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
- mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
- mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
-
mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
@@ -116,14 +127,56 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
((RippleDrawable) getBackground()).setForceSoftware(true);
((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
- addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
- setClipBounds(new Rect(getPaddingLeft(), 0, getWidth() - getPaddingRight(),
- getHeight()));
- }
- });
+ updateResources();
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateResources();
+ }
+
+ private void updateResources() {
+ FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
+ FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
+
+ mGearTranslation = mContext.getResources().getDimension(R.dimen.qs_header_gear_translation);
+
+ mDateTimeTranslation = mContext.getResources().getDimension(
+ R.dimen.qs_date_anim_translation);
+ mDateTimeAlarmTranslation = mContext.getResources().getDimension(
+ R.dimen.qs_date_alarm_anim_translation);
+ float dateCollapsedSize = mContext.getResources().getDimension(
+ R.dimen.qs_date_collapsed_text_size);
+ float dateExpandedSize = mContext.getResources().getDimension(
+ R.dimen.qs_date_text_size);
+ mDateScaleFactor = dateExpandedSize / dateCollapsedSize;
+ updateDateTimePosition();
+
+ mAnimator = new TouchAnimator.Builder()
+ .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
+ .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
+ .build();
+ mSecondHalfAnimator = new TouchAnimator.Builder()
+ .addFloat(mSettingsButton, "rotation", -180, 0)
+ .addFloat(mAlarmStatus, "alpha", 0, 1)
+ .addFloat(mEmergencyOnly, "alpha", 0, 1)
+ .setStartDelay(.5f)
+ .build();
+ mFirstHalfAnimator = new TouchAnimator.Builder()
+ .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0)
+ .setEndDelay(.5f)
+ .build();
+ mDateSizeAnimator = new TouchAnimator.Builder()
+ .addFloat(mDateTimeGroup, "scaleX", 1, mDateScaleFactor)
+ .addFloat(mDateTimeGroup, "scaleY", 1, mDateScaleFactor)
+ .setStartDelay(.36f)
+ .build();
+ mSettingsAlpha = new TouchAnimator.Builder()
+ .addFloat(mSettingsContainer, "alpha", 0, 1)
+ .addFloat(mMultiUserSwitch, "alpha", 0, 1)
+ .setStartDelay(QSAnimator.EXPANDED_TILE_DELAY)
+ .build();
}
@Override
@@ -148,19 +201,39 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
if (nextAlarm != null) {
mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
}
- mAlarmShowing = nextAlarm != null;
- updateEverything();
+ if (mAlarmShowing != (nextAlarm != null)) {
+ mAlarmShowing = nextAlarm != null;
+ updateEverything();
+ }
}
@Override
public void setExpansion(float headerExpansionFraction) {
- mExpandedGroup.setAlpha(headerExpansionFraction);
- mExpandedGroup.setVisibility(headerExpansionFraction > 0 ? View.VISIBLE : View.INVISIBLE);
- mHeaderQsPanel.setAlpha(1 - headerExpansionFraction);
- mHeaderQsPanel.setVisibility(headerExpansionFraction < 1 ? View.VISIBLE : View.INVISIBLE);
+ mExpansionAmount = headerExpansionFraction;
+ mAnimator.setPosition(headerExpansionFraction);
+ mSecondHalfAnimator.setPosition(headerExpansionFraction);
+ mFirstHalfAnimator.setPosition(headerExpansionFraction);
+ mDateSizeAnimator.setPosition(headerExpansionFraction);
+ mAlarmTranslation.setPosition(headerExpansionFraction);
+ mSettingsAlpha.setPosition(headerExpansionFraction);
+
+ updateAlarmVisibilities();
+
+ mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
+ }
- mDateTimeGroup.setTranslationY(headerExpansionFraction * mDateTimeTranslation);
- mEmergencyOnly.setAlpha(headerExpansionFraction);
+ private void updateAlarmVisibilities() {
+ mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
+ mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ private void updateDateTimePosition() {
+ // This one has its own because we have to rebuild it every time the alarm state changes.
+ mAlarmTranslation = new TouchAnimator.Builder()
+ .addFloat(mDateTimeAlarmGroup, "translationY", 0, mAlarmShowing
+ ? mDateTimeAlarmTranslation : mDateTimeTranslation)
+ .build();
+ mAlarmTranslation.setPosition(mExpansionAmount);
}
public void setListening(boolean listening) {
@@ -174,12 +247,12 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
@Override
public void updateEverything() {
+ updateDateTimePosition();
updateVisibilities();
}
private void updateVisibilities() {
- mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE);
- mQsDetailHeader.setVisibility(mExpanded && mShowingDetail ? View.VISIBLE : View.INVISIBLE);
+ updateAlarmVisibilities();
mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly
? View.VISIBLE : View.INVISIBLE);
mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
@@ -188,10 +261,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
: View.GONE);
}
- private boolean hasMultiUsers() {
- return false;
- }
-
private void updateListeners() {
if (mListening) {
mNextAlarmController.addStateChangedCallback(this);
@@ -210,7 +279,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
mQsPanel = qsPanel;
setupHost(qsPanel.getHost());
if (mQsPanel != null) {
- mQsPanel.setCallback(mQsPanelCallback);
mMultiUserSwitch.setQsPanel(qsPanel);
}
}
@@ -290,121 +358,4 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
}
}
}
-
- private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
- private boolean mScanState;
-
- @Override
- public void onShowingDetail(final QSTile.DetailAdapter detail) {
- mDetailTransitioning = true;
- post(new Runnable() {
- @Override
- public void run() {
- handleShowingDetail(detail);
- }
- });
- }
-
- @Override
- public void onToggleStateChanged(final boolean state) {
- post(new Runnable() {
- @Override
- public void run() {
- handleToggleStateChanged(state);
- }
- });
-
- }
-
- @Override
- public void onScanStateChanged(final boolean state) {
- post(new Runnable() {
- @Override
- public void run() {
- handleScanStateChanged(state);
- }
- });
- }
-
- private void handleToggleStateChanged(boolean state) {
- mQsDetailHeaderSwitch.setChecked(state);
- }
-
- private void handleScanStateChanged(boolean state) {
- if (mScanState == state) return;
- mScanState = state;
- final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
- if (state) {
- mQsDetailHeaderProgress.animate().alpha(1f);
- anim.start();
- } else {
- mQsDetailHeaderProgress.animate().alpha(0f);
- anim.stop();
- }
- }
-
- private void handleShowingDetail(final QSTile.DetailAdapter detail) {
- final boolean showingDetail = detail != null;
- transition(mDateTimeGroup, !showingDetail);
- transition(mExpandedGroup, !showingDetail);
- if (mAlarmShowing) {
- transition(mAlarmStatus, !showingDetail);
- }
- transition(mQsDetailHeader, showingDetail);
- mShowingDetail = showingDetail;
- if (showingDetail) {
- mQsDetailHeaderTitle.setText(detail.getTitle());
- final Boolean toggleState = detail.getToggleState();
- if (toggleState == null) {
- mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
- mQsDetailHeader.setClickable(false);
- } else {
- mQsDetailHeaderSwitch.setVisibility(VISIBLE);
- mQsDetailHeaderSwitch.setChecked(toggleState);
- mQsDetailHeader.setClickable(true);
- mQsDetailHeader.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- boolean checked = !mQsDetailHeaderSwitch.isChecked();
- mQsDetailHeaderSwitch.setChecked(checked);
- detail.setToggleState(checked);
- }
- });
- }
- mQsDetailHeaderBack.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- v.getLocationInWindow(mTmpInt2);
- mTmpInt2[0] += v.getWidth() / 2;
- mTmpInt2[1] += v.getHeight() / 2;
- mQsPanel.showDetailAdapter(false, null, mTmpInt2);
- }
- });
- } else {
- mQsDetailHeader.setClickable(false);
- }
- }
-
- private void transition(final View v, final boolean in) {
- if (in) {
- v.bringToFront();
- v.setVisibility(VISIBLE);
- }
- if (v.hasOverlappingRendering()) {
- v.animate().withLayer();
- }
- v.animate()
- .alpha(in ? 1 : 0)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- if (!in) {
- v.setVisibility(INVISIBLE);
- }
- mDetailTransitioning = false;
- }
- })
- .start();
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
index da16954d0d46..3682aa1b06f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
@@ -16,31 +16,79 @@ package com.android.systemui.statusbar.phone;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import java.util.ArrayList;
+
/**
* Automatically reverses the order of children as they are added.
* Also reverse the width and height values of layout params
*/
public class ReverseLinearLayout extends LinearLayout {
+ private boolean mIsLayoutRtl;
+
public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mIsLayoutRtl = getResources().getConfiguration()
+ .getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ }
+
+ @Override
public void addView(View child) {
reversParams(child.getLayoutParams());
- super.addView(child, 0);
+ if (mIsLayoutRtl) {
+ super.addView(child);
+ } else {
+ super.addView(child, 0);
+ }
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
reversParams(params);
- super.addView(child, 0, params);
+ if (mIsLayoutRtl) {
+ super.addView(child, params);
+ } else {
+ super.addView(child, 0, params);
+ }
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateRTLOrder();
+ }
+
+ /**
+ * In landscape, the LinearLayout is not auto mirrored since it is vertical. Therefore we
+ * have to do it manually
+ */
+ private void updateRTLOrder() {
+ boolean isLayoutRtl = getResources().getConfiguration()
+ .getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ if (mIsLayoutRtl != isLayoutRtl) {
+ // RTL changed, swap the order of all views.
+ int childCount = getChildCount();
+ ArrayList<View> childList = new ArrayList<>(childCount);
+ for (int i = 0; i < childCount; i++) {
+ childList.add(getChildAt(i));
+ }
+ removeAllViews();
+ for (int i = childCount - 1; i >= 0; i--) {
+ super.addView(childList.get(i));
+ }
+ mIsLayoutRtl = isLayoutRtl;
+ }
}
private void reversParams(ViewGroup.LayoutParams params) {
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 f310c2c2488c..fe76ae751520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -56,16 +56,16 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
- private final ScrimView mScrimBehind;
+ protected final ScrimView mScrimBehind;
private final ScrimView mScrimInFront;
private final UnlockMethodCache mUnlockMethodCache;
private final View mHeadsUpScrim;
- private boolean mKeyguardShowing;
+ protected boolean mKeyguardShowing;
private float mFraction;
private boolean mDarkenWhileDragging;
- private boolean mBouncerShowing;
+ protected boolean mBouncerShowing;
private boolean mWakeAndUnlocking;
private boolean mAnimateChange;
private boolean mUpdatePending;
@@ -203,7 +203,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
mUpdatePending = true;
}
- private void updateScrims() {
+ protected void updateScrims() {
if (mAnimateKeyguardFadingOut || mForceHideScrims) {
setScrimInFrontColor(0f);
setScrimBehindColor(0f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index d2f1ca9630e2..3e3b16922f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -46,6 +46,7 @@ import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTile.DetailAdapter;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -742,7 +743,7 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
}
@Override
- public void onShowingDetail(final QSTile.DetailAdapter detail) {
+ public void onShowingDetail(final DetailAdapter detail, int x, int y) {
mDetailTransitioning = true;
post(new Runnable() {
@Override
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 45aae2dd61f0..f61f31e814f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Handler;
@@ -58,8 +59,8 @@ import java.util.ArrayList;
public class StatusBarIconController extends StatusBarIconList implements Tunable {
public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
-
public static final String ICON_BLACKLIST = "icon_blacklist";
+ public static final int DEFAULT_ICON_TINT = Color.WHITE;
private Context mContext;
private PhoneStatusBar mPhoneStatusBar;
@@ -79,8 +80,11 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
private int mIconSize;
private int mIconHPadding;
- private int mIconTint = Color.WHITE;
+ private int mIconTint = DEFAULT_ICON_TINT;
private float mDarkIntensity;
+ private final Rect mTintArea = new Rect();
+ private static final Rect sTmpRect = new Rect();
+ private static final int[] sTmpInt2 = new int[2];
private boolean mTransitionPending;
private boolean mTintChangePending;
@@ -395,6 +399,25 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
}
}
+ /**
+ * Sets the dark area so {@link #setIconsDark} only affects the icons in the specified area.
+ *
+ * @param darkArea the area in which icons should change it's tint, in logical screen
+ * coordinates
+ */
+ public void setIconsDarkArea(Rect darkArea) {
+ if (darkArea == null && mTintArea.isEmpty()) {
+ return;
+ }
+ if (darkArea == null) {
+ mTintArea.setEmpty();
+ } else {
+ mTintArea.set(darkArea);
+ }
+ applyIconTint();
+ mNotificationIconAreaController.setTintArea(darkArea);
+ }
+
public void setIconsDark(boolean dark, boolean animate) {
if (!animate) {
setIconTintInternal(dark ? 1.0f : 0.0f);
@@ -446,14 +469,60 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
mPendingDarkIntensity = darkIntensity;
}
+ /**
+ * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
+ * the screen {@param tintArea} in which to apply that tint
+ */
+ public static int getTint(Rect tintArea, View view, int color) {
+ if (isInArea(tintArea, view)) {
+ return color;
+ } else {
+ return DEFAULT_ICON_TINT;
+ }
+ }
+
+ /**
+ * @return the dark intensity to apply to {@param view} depending on the desired dark
+ * {@param intensity} and the screen {@param tintArea} in which to apply that intensity
+ */
+ public static float getDarkIntensity(Rect tintArea, View view, float intensity) {
+ if (isInArea(tintArea, view)) {
+ return intensity;
+ } else {
+ return 0f;
+ }
+ }
+
+ /**
+ * @return true if more than half of the {@param view} area are in {@param area}, false
+ * otherwise
+ */
+ private static boolean isInArea(Rect area, View view) {
+ if (area.isEmpty()) {
+ return true;
+ }
+ sTmpRect.set(area);
+ view.getLocationOnScreen(sTmpInt2);
+ int left = sTmpInt2[0];
+
+ int intersectStart = Math.max(left, area.left);
+ int intersectEnd = Math.min(left + view.getWidth(), area.right);
+ int intersectAmount = Math.max(0, intersectEnd - intersectStart);
+
+ boolean coversFullStatusBar = area.top <= 0;
+ boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
+ return majorityOfWidth && coversFullStatusBar;
+ }
+
private void applyIconTint() {
for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
- v.setImageTintList(ColorStateList.valueOf(mIconTint));
+ v.setImageTintList(ColorStateList.valueOf(getTint(mTintArea, v, mIconTint)));
}
- mSignalCluster.setIconTint(mIconTint, mDarkIntensity);
- mBatteryMeterView.setDarkIntensity(mDarkIntensity);
- mClock.setTextColor(mIconTint);
+ mSignalCluster.setIconTint(mIconTint, mDarkIntensity, mTintArea);
+ mBatteryMeterView.setDarkIntensity(
+ isInArea(mTintArea, mBatteryMeterView) ? mDarkIntensity : 0);
+ mClock.setTextColor(getTint(mTintArea, mClock, mIconTint));
}
public void appTransitionPending() {
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 7a05b8f3b9c4..0e84f733cad4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -509,8 +509,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
return !(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive;
}
- public boolean onMenuPressed() {
- return mBouncer.onMenuPressed();
+ public boolean shouldDismissOnMenuPressed() {
+ return mBouncer.shouldDismissOnMenuPressed();
}
public boolean interceptMediaKey(KeyEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 3bd68a945592..ab347686be81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -80,13 +80,13 @@ public class BrightnessMirrorController {
// Original is slightly larger than the mirror, so make sure to use the center for the
// positioning.
- int originalX = mInt2Cache[0] + original.getWidth()/2;
- int originalY = mInt2Cache[1];
+ int originalX = mInt2Cache[0] + original.getWidth() / 2;
+ int originalY = mInt2Cache[1] + original.getHeight() / 2;
mBrightnessMirror.setTranslationX(0);
mBrightnessMirror.setTranslationY(0);
mBrightnessMirror.getLocationInWindow(mInt2Cache);
- int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth()/2;
- int mirrorY = mInt2Cache[1];
+ int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth() / 2;
+ int mirrorY = mInt2Cache[1] + mBrightnessMirror.getHeight() / 2;
mBrightnessMirror.setTranslationX(originalX - mirrorX);
mBrightnessMirror.setTranslationY(originalY - mirrorY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
index 186e8b51d58c..6dd196b8b0c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
@@ -60,6 +60,10 @@ public class DataSaverController {
public void setDataSaverEnabled(boolean enabled) {
mPolicyManager.setRestrictBackground(enabled);
+ try {
+ mPolicyListener.onRestrictBackgroundChanged(enabled);
+ } catch (RemoteException e) {
+ }
}
private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
deleted file mode 100644
index d47050c18519..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
+++ /dev/null
@@ -1,193 +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.policy;
-
-import libcore.util.Objects;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.provider.Settings;
-
-import com.android.systemui.R;
-import com.android.systemui.tuner.TunerService;
-
-import java.util.ArrayList;
-
-public class DisplayController implements TunerService.Tunable {
-
- public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
- public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
-
- public static final String COLOR_STATE = "sysui_color_matrix_state";
-
- public static final int COLOR_STATE_DISABLED = 0;
- public static final int COLOR_STATE_ENABLED = 1;
- public static final int COLOR_STATE_AUTO = 2;
-
- public static final String AUTO_STRING = "auto_mode";
- public static final String NONE_STRING = "none";
-
- public static final int AUTO_INDEX = 2;
- public static final int CUSTOM_INDEX = 3;
-
- // Night mode ~= 3400 K
- private static final float[] NIGHT_VALUES = new float[] {
- 1, 0, 0, 0,
- 0, .754f, 0, 0,
- 0, 0, .516f, 0,
- 0, 0, 0, 1,
- };
- public static final float[] IDENTITY_MATRIX = new float[] {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1,
- };
-
- private final ArrayList<Listener> mListeners = new ArrayList<>();
-
- private final Context mContext;
-
- private String mCurrentValue;
- private boolean mListening;
-
- public DisplayController(Context context) {
- mContext = context;
- TunerService.get(mContext).addTunable(this, COLOR_STATE,
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
- }
-
- public void addListener(Listener listener) {
- mListeners.add(listener);
- listener.onCurrentMatrixChanged();
- }
-
- public void removeListener(Listener listener) {
- mListeners.remove(listener);
- }
-
- public boolean isEnabled() {
- return TunerService.get(mContext).getValue(COLOR_STATE, COLOR_STATE_DISABLED)
- != COLOR_STATE_DISABLED;
- }
-
- public boolean isAuto() {
- return mListening;
- }
-
- public void setAuto(boolean auto) {
- TunerService.get(mContext).setValue(COLOR_STATE, auto ? COLOR_STATE_AUTO
- : COLOR_STATE_DISABLED);
- }
-
- public boolean isCustomSet() {
- return isCustomEnabled() && Objects.equal(getCurrentMatrix(), getCustomValues());
- }
-
- public String getCurrentMatrix() {
- return mCurrentValue;
- }
-
- public String getCustomValues() {
- return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
- }
-
- public boolean isCustomEnabled() {
- return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_ENABLED, 0) != 0;
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX.equals(key)) {
- mCurrentValue = newValue;
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onCurrentMatrixChanged();
- }
- } else if (COLOR_STATE.equals(key)) {
- final boolean listening = newValue != null
- && Integer.parseInt(newValue) == COLOR_STATE_AUTO;
- if (listening && !mListening) {
- mListening = true;
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
- updateNightMode();
- } else if (!listening && mListening) {
- mListening = false;
- mContext.unregisterReceiver(mReceiver);
- }
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onCurrentMatrixChanged();
- }
- }
- }
-
- private void updateNightMode() {
- final int uiMode = mContext.getResources().getConfiguration().uiMode;
- final boolean isNightMode = (uiMode & Configuration.UI_MODE_NIGHT_MASK)
- == Configuration.UI_MODE_NIGHT_YES;
- String value = null;
- if (isNightMode) {
- value = toString(NIGHT_VALUES);
- }
- TunerService.get(mContext).setValue(Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- value);
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
- updateNightMode();
- }
- }
- };
-
- public interface Listener {
- void onCurrentMatrixChanged();
- }
-
- public static String[] getColorTransforms(Context context) {
- return new String[] {
- NONE_STRING,
- toString(NIGHT_VALUES),
- AUTO_STRING, // Blank spot for auto values
- null, // Blank spot for custom values
- };
- }
-
- public static CharSequence[] getColorTitles(Context context) {
- // TODO: Move to string array resource.
- return new CharSequence[]{
- context.getString(R.string.color_matrix_none),
- context.getString(R.string.color_matrix_night),
- context.getString(R.string.color_matrix_auto),
- context.getString(R.string.color_matrix_custom),
- };
- }
-
- public static String toString(float[] values) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < values.length; i++) {
- if (builder.length() != 0) {
- builder.append(',');
- }
- builder.append(values[i]);
- }
- return builder.toString();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 29a8f67e4cfe..9a21a1e378e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -93,6 +93,10 @@ public class FlashlightController {
}
}
+ public boolean hasFlashlight() {
+ return mCameraId != null;
+ }
+
public synchronized boolean isEnabled() {
return mFlashlightEnabled;
}
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 f06552283219..ab817127564c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -39,10 +39,10 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Stack;
-import java.util.TreeSet;
/**
* A manager which handles heads up notifications which is a special mode where
@@ -90,7 +90,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
private int mSnoozeLengthMs;
private ContentObserver mSettingsObserver;
private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
- private TreeSet<HeadsUpEntry> mSortedEntries = new TreeSet<>();
private HashSet<String> mSwipedOutKeys = new HashSet<>();
private int mUser;
private Clock mClock;
@@ -230,7 +229,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
private void removeHeadsUpEntry(NotificationData.Entry entry) {
HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
- mSortedEntries.remove(remove);
entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
entry.row.setHeadsUp(false);
setEntryPinned(remove, false /* isPinned */);
@@ -345,12 +343,21 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return mHeadsUpEntries.get(key).entry;
}
- public TreeSet<HeadsUpEntry> getSortedEntries() {
- return mSortedEntries;
+ public Collection<HeadsUpEntry> getAllEntries() {
+ return mHeadsUpEntries.values();
}
public HeadsUpEntry getTopEntry() {
- return mSortedEntries.isEmpty() ? null : mSortedEntries.first();
+ if (mHeadsUpEntries.isEmpty()) {
+ return null;
+ }
+ HeadsUpEntry topEntry = null;
+ for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
+ if (topEntry == null || entry.compareTo(topEntry) == -1) {
+ topEntry = entry;
+ }
+ }
+ return topEntry;
}
/**
@@ -374,26 +381,18 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return;
}
if (mHasPinnedNotification) {
- int minX = 0;
- int maxX = 0;
- int maxY = 0;
- for (HeadsUpEntry entry : mSortedEntries) {
- ExpandableNotificationRow row = entry.entry.row;
- if (row.isPinned()) {
- if (row.isChildInGroup()) {
- final ExpandableNotificationRow groupSummary
- = mGroupManager.getGroupSummary(row.getStatusBarNotification());
- if (groupSummary != null) {
- row = groupSummary;
- }
- }
- row.getLocationOnScreen(mTmpTwoArray);
- minX = mTmpTwoArray[0];
- maxX = mTmpTwoArray[0] + row.getWidth();
- maxY = row.getIntrinsicHeight();
- break;
+ ExpandableNotificationRow topEntry = getTopEntry().entry.row;
+ if (topEntry.isChildInGroup()) {
+ final ExpandableNotificationRow groupSummary
+ = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
+ if (groupSummary != null) {
+ topEntry = groupSummary;
}
}
+ topEntry.getLocationOnScreen(mTmpTwoArray);
+ int minX = mTmpTwoArray[0];
+ int maxX = mTmpTwoArray[0] + topEntry.getWidth();
+ int maxY = topEntry.getIntrinsicHeight();
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(minX, 0, maxX, maxY);
@@ -413,7 +412,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
pw.print(" now="); pw.println(SystemClock.elapsedRealtime());
pw.print(" mUser="); pw.println(mUser);
- for (HeadsUpEntry entry: mSortedEntries) {
+ for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
pw.print(" HeadsUpEntry="); pw.println(entry.entry);
}
int N = mSnoozedPackages.size();
@@ -633,7 +632,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
public void updateEntry(boolean updatePostTime) {
- mSortedEntries.remove(HeadsUpEntry.this);
long currentTime = mClock.currentTimeMillis();
earliestRemovaltime = currentTime + mMinimumDisplayTime;
if (updatePostTime) {
@@ -648,7 +646,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
}
- mSortedEntries.add(HeadsUpEntry.this);
}
private boolean isSticky() {
@@ -658,6 +655,13 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
@Override
public int compareTo(HeadsUpEntry o) {
+ boolean isPinned = entry.row.isPinned();
+ boolean otherPinned = o.entry.row.isPinned();
+ if (isPinned && !otherPinned) {
+ return -1;
+ } else if (!isPinned && otherPinned) {
+ return 1;
+ }
boolean selfFullscreen = hasFullScreenIntent(entry);
boolean otherFullscreen = hasFullScreenIntent(o.entry);
if (selfFullscreen && !otherFullscreen) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 500d60359145..047f14def5cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -21,7 +21,6 @@ public interface HotspotController {
void removeCallback(Callback callback);
boolean isHotspotEnabled();
void setHotspotEnabled(boolean enabled);
- boolean isTetheringAllowed();
public interface Callback {
void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 07b74094ffb2..f03d9e9dce84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,15 +16,12 @@
package com.android.systemui.statusbar.policy;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Log;
import java.io.FileDescriptor;
@@ -40,8 +37,6 @@ public class HotspotControllerImpl implements HotspotController {
private final Receiver mReceiver = new Receiver();
private final ConnectivityManager mConnectivityManager;
private final Context mContext;
- private final UserManager mUserManager;
- private final int mCurrentUser;
private int mHotspotState;
@@ -49,8 +44,6 @@ public class HotspotControllerImpl implements HotspotController {
mContext = context;
mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mCurrentUser = ActivityManager.getCurrentUser();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,12 +88,6 @@ public class HotspotControllerImpl implements HotspotController {
return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
}
- @Override
- public boolean isTetheringAllowed() {
- return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
- UserHandle.of(mCurrentUser));
- }
-
static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 867a8a3ca833..fb310a64a358 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,6 +21,8 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -242,7 +244,6 @@ public class KeyguardUserSwitcher {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
UserSwitcherController.UserRecord item = getItem(position);
-
if (!(convertView instanceof UserDetailItemView)
|| !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
convertView = LayoutInflater.from(mContext).inflate(
@@ -252,11 +253,17 @@ public class KeyguardUserSwitcher {
UserDetailItemView v = (UserDetailItemView) convertView;
String name = getName(mContext, item);
+ Drawable drawable;
if (item.picture == null) {
- v.bind(name, getDrawable(mContext, item));
+ drawable = getDrawable(mContext, item).mutate();
} else {
- v.bind(name, item.picture);
+ drawable = new BitmapDrawable(mContext.getResources(), item.picture);
+ }
+ // Disable the icon if switching is disabled
+ if (!item.isSwitchToEnabled) {
+ drawable.setTint(mContext.getColor(R.color.qs_tile_disabled_color));
}
+ v.bind(name, drawable);
convertView.setActivated(item.isCurrent);
convertView.setTag(item);
return convertView;
@@ -269,7 +276,7 @@ public class KeyguardUserSwitcher {
// Close the switcher if tapping the current user. Guest is excluded because
// tapping the guest user while it's current clears the session.
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
- } else {
+ } else if (user.isSwitchToEnabled) {
switchTo(user);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 401943e1c321..29a8981fd89e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,7 +21,6 @@ public interface LocationController {
boolean setLocationEnabled(boolean enabled);
void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
- boolean isUserLocationRestricted();
/**
* A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 436a40d25bfa..8d84be485c91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,7 +52,6 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
private AppOpsManager mAppOpsManager;
private StatusBarManager mStatusBarManager;
- private final int mCurrentUser;
private boolean mAreActiveLocationRequests;
@@ -74,7 +73,6 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mStatusBarManager
= (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
- mCurrentUser = ActivityManager.getCurrentUser();
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -105,6 +103,10 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
* @return true if attempt to change setting was successful.
*/
public boolean setLocationEnabled(boolean enabled) {
+ int currentUserId = ActivityManager.getCurrentUser();
+ if (isUserLocationRestricted(currentUserId)) {
+ return false;
+ }
final ContentResolver cr = mContext.getContentResolver();
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
@@ -113,7 +115,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
+ .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
}
/**
@@ -131,10 +133,10 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
/**
* Returns true if the current user is restricted from using location.
*/
- public boolean isUserLocationRestricted() {
+ private boolean isUserLocationRestricted(int userId) {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
- UserHandle.of(mCurrentUser));
+ UserHandle.of(userId));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
new file mode 100644
index 000000000000..0b1911bb15fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
@@ -0,0 +1,250 @@
+/*
+ * 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.policy;
+
+import libcore.util.Objects;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.opengl.Matrix;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.util.MathUtils;
+
+import com.android.systemui.tuner.TunerService;
+
+import java.util.ArrayList;
+
+/**
+ * Listens for changes to twilight from the TwilightService.
+ *
+ * Also pushes the current matrix to accessibility based on the current twilight
+ * and various tuner settings.
+ */
+public class NightModeController implements TunerService.Tunable {
+
+ public static final String NIGHT_MODE_ADJUST_TINT = "tuner_night_mode_adjust_tint";
+ private static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+ private static final String ACTION_TWILIGHT_CHANGED = "android.intent.action.TWILIGHT_CHANGED";
+
+ private static final String EXTRA_IS_NIGHT = "isNight";
+ private static final String EXTRA_AMOUNT = "amount";
+
+ // Night mode ~= 3400 K
+ private static final float[] NIGHT_VALUES = new float[] {
+ 1, 0, 0, 0,
+ 0, .754f, 0, 0,
+ 0, 0, .516f, 0,
+ 0, 0, 0, 1,
+ };
+ public static final float[] IDENTITY_MATRIX = new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+
+ private final ArrayList<Listener> mListeners = new ArrayList<>();
+
+ private final Context mContext;
+
+ // This is whether or not this is the main NightMode controller in SysUI that should be
+ // updating relevant color matrixes or if its in the tuner process getting current state
+ // for UI.
+ private final boolean mUpdateMatrix;
+
+ private float[] mCustomMatrix;
+ private boolean mListening;
+ private boolean mAdjustTint;
+
+ private boolean mIsNight;
+ private float mAmount;
+ private boolean mIsAuto;
+
+ public NightModeController(Context context) {
+ this(context, false);
+ }
+
+ public NightModeController(Context context, boolean updateMatrix) {
+ mContext = context;
+ mUpdateMatrix = updateMatrix;
+ TunerService.get(mContext).addTunable(this, NIGHT_MODE_ADJUST_TINT,
+ COLOR_MATRIX_CUSTOM_VALUES, Secure.TWILIGHT_MODE);
+ }
+
+ public void setNightMode(boolean isNight) {
+ if (mIsAuto) {
+ if (mIsNight != isNight) {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, isNight
+ ? Secure.TWILIGHT_MODE_AUTO_OVERRIDE_ON
+ : Secure.TWILIGHT_MODE_AUTO_OVERRIDE_OFF);
+ } else {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE,
+ Secure.TWILIGHT_MODE_AUTO);
+ }
+ } else {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, isNight
+ ? Secure.TWILIGHT_MODE_LOCKED_ON : Secure.TWILIGHT_MODE_LOCKED_OFF);
+ }
+ }
+
+ public void setAuto(boolean auto) {
+ mIsAuto = auto;
+ if (auto) {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_AUTO);
+ } else {
+ // Lock into the current state
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, mIsNight
+ ? Secure.TWILIGHT_MODE_LOCKED_ON : Secure.TWILIGHT_MODE_LOCKED_OFF);
+ }
+ }
+
+ public boolean isAuto() {
+ return mIsAuto;
+ }
+
+ public void setAdjustTint(Boolean newValue) {
+ TunerService.get(mContext).setValue(NIGHT_MODE_ADJUST_TINT, ((Boolean) newValue) ? 1 : 0);
+ }
+
+ public void addListener(Listener listener) {
+ mListeners.add(listener);
+ listener.onNightModeChanged();
+ updateListening();
+ }
+
+ public void removeListener(Listener listener) {
+ mListeners.remove(listener);
+ updateListening();
+ }
+
+ private void updateListening() {
+ boolean shouldListen = mListeners.size() != 0 || (mUpdateMatrix && mAdjustTint);
+ if (shouldListen == mListening) return;
+ mListening = shouldListen;
+ if (mListening) {
+ mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_TWILIGHT_CHANGED));
+ } else {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ }
+
+ public boolean isEnabled() {
+ if (!mListening) {
+ updateNightMode(mContext.registerReceiver(null,
+ new IntentFilter(ACTION_TWILIGHT_CHANGED)));
+ }
+ return mIsNight;
+ }
+
+ public String getCustomValues() {
+ return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
+ }
+
+ public void setCustomValues(String values) {
+ TunerService.get(mContext).setValue(COLOR_MATRIX_CUSTOM_VALUES, values);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ mCustomMatrix = newValue != null ? toValues(newValue) : null;
+ updateCurrentMatrix();
+ } else if (NIGHT_MODE_ADJUST_TINT.equals(key)) {
+ mAdjustTint = newValue == null || Integer.parseInt(newValue) != 0;
+ updateListening();
+ updateCurrentMatrix();
+ } else if (Secure.TWILIGHT_MODE.equals(key)) {
+ mIsAuto = newValue != null && Integer.parseInt(newValue) >= Secure.TWILIGHT_MODE_AUTO;
+ }
+ }
+
+ private void updateCurrentMatrix() {
+ if (!mUpdateMatrix) return;
+ if ((!mAdjustTint || mAmount == 0) && mCustomMatrix == null) {
+ TunerService.get(mContext).setValue(Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ return;
+ }
+ float[] values = scaleValues(IDENTITY_MATRIX, NIGHT_VALUES, mAdjustTint ? mAmount : 0);
+ if (mCustomMatrix != null) {
+ values = multiply(values, mCustomMatrix);
+ }
+ TunerService.get(mContext).setValue(Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ toString(values));
+ }
+
+ private void updateNightMode(Intent intent) {
+ mIsNight = intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
+ mAmount = intent.getFloatExtra(EXTRA_AMOUNT, 0);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_TWILIGHT_CHANGED.equals(intent.getAction())) {
+ updateNightMode(intent);
+ updateCurrentMatrix();
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onNightModeChanged();
+ }
+ }
+ }
+ };
+
+ public interface Listener {
+ void onNightModeChanged();
+ void onTwilightAutoChanged();
+ }
+
+ private static float[] multiply(float[] matrix, float[] other) {
+ if (matrix == null) {
+ return other;
+ }
+ float[] result = new float[16];
+ Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
+ return result;
+ }
+
+ private float[] scaleValues(float[] identityMatrix, float[] nightValues, float amount) {
+ float[] values = new float[identityMatrix.length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = MathUtils.lerp(identityMatrix[i], nightValues[i], amount);
+ }
+ return values;
+ }
+
+ public static String toString(float[] values) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < values.length; i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(values[i]);
+ }
+ return builder.toString();
+ }
+
+ public static float[] toValues(String customValues) {
+ String[] strValues = customValues.split(",");
+ float[] values = new float[strValues.length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = Float.parseFloat(strValues[i]);
+ }
+ return values;
+ }
+}
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 6ca7dc8a4566..53fd446b2444 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -99,6 +99,7 @@ public class UserSwitcherController {
private boolean mSimpleUserSwitcher;
private boolean mAddUsersWhenLocked;
private boolean mPauseRefreshUsers;
+ private boolean mAllowUserSwitchingWhenSystemUserLocked;
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
@@ -115,6 +116,7 @@ public class UserSwitcherController {
filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_STOPPING);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
null /* permission */, null /* scheduler */);
@@ -130,6 +132,10 @@ public class UserSwitcherController {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
mSettingsObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(
+ Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED),
+ true, mSettingsObserver);
// Fetch initial values.
mSettingsObserver.onChange(false);
@@ -180,6 +186,8 @@ public class UserSwitcherController {
}
ArrayList<UserRecord> records = new ArrayList<>(infos.size());
int currentId = ActivityManager.getCurrentUser();
+ boolean allowUserSwitching = mAllowUserSwitchingWhenSystemUserLocked
+ || mUserManager.isUserUnlocked(UserHandle.SYSTEM);
UserInfo currentUserInfo = null;
UserRecord guestRecord = null;
int avatarSize = mContext.getResources()
@@ -190,32 +198,40 @@ public class UserSwitcherController {
if (isCurrent) {
currentUserInfo = info;
}
- if (info.isGuest()) {
- guestRecord = new UserRecord(info, null /* picture */,
- true /* isGuest */, isCurrent, false /* isAddUser */,
- false /* isRestricted */);
- } else if (info.isEnabled() && info.supportsSwitchToByUser()) {
- Bitmap picture = bitmaps.get(info.id);
- if (picture == null) {
- picture = mUserManager.getUserIcon(info.id);
-
- if (picture != null) {
- picture = BitmapHelper.createCircularClip(
- picture, avatarSize, avatarSize);
+ boolean switchToEnabled = allowUserSwitching || isCurrent;
+ if (info.isEnabled()) {
+ if (info.isGuest()) {
+ guestRecord = new UserRecord(info, null /* picture */,
+ true /* isGuest */, isCurrent, false /* isAddUser */,
+ false /* isRestricted */, switchToEnabled);
+ } else if (info.supportsSwitchToByUser()) {
+ Bitmap picture = bitmaps.get(info.id);
+ if (picture == null) {
+ picture = mUserManager.getUserIcon(info.id);
+
+ if (picture != null) {
+ picture = BitmapHelper.createCircularClip(
+ picture, avatarSize, avatarSize);
+ }
}
+ int index = isCurrent ? 0 : records.size();
+ records.add(index, new UserRecord(info, picture, false /* isGuest */,
+ isCurrent, false /* isAddUser */, false /* isRestricted */,
+ switchToEnabled));
}
- int index = isCurrent ? 0 : records.size();
- records.add(index, new UserRecord(info, picture, false /* isGuest */,
- isCurrent, false /* isAddUser */, false /* isRestricted */));
}
}
+ boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
boolean currentUserCanCreateUsers = currentUserInfo != null
&& (currentUserInfo.isAdmin()
- || currentUserInfo.id == UserHandle.USER_SYSTEM);
- boolean canCreateGuest = (currentUserCanCreateUsers || addUsersWhenLocked)
+ || currentUserInfo.id == UserHandle.USER_SYSTEM)
+ && systemCanCreateUsers;
+ boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
+ boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
&& guestRecord == null;
- boolean canCreateUser = (currentUserCanCreateUsers || addUsersWhenLocked)
+ boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
&& mUserManager.canAddMoreUsers();
boolean createIsRestricted = !addUsersWhenLocked;
@@ -224,8 +240,8 @@ public class UserSwitcherController {
if (canCreateGuest) {
guestRecord = new UserRecord(null /* info */, null /* picture */,
true /* isGuest */, false /* isCurrent */,
- false /* isAddUser */, createIsRestricted);
- checkIfAddUserDisallowed(guestRecord);
+ false /* isAddUser */, createIsRestricted, allowUserSwitching);
+ checkIfAddUserDisallowedByAdminOnly(guestRecord);
records.add(guestRecord);
}
} else {
@@ -237,8 +253,8 @@ public class UserSwitcherController {
if (!mSimpleUserSwitcher && canCreateUser) {
UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
- createIsRestricted);
- checkIfAddUserDisallowed(addUserRecord);
+ createIsRestricted, allowUserSwitching);
+ checkIfAddUserDisallowedByAdminOnly(addUserRecord);
records.add(addUserRecord);
}
@@ -459,6 +475,12 @@ public class UserSwitcherController {
} else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ // Unlocking the system user may require a refresh
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId != UserHandle.USER_SYSTEM) {
+ return;
+ }
}
refreshUsers(forcePictureLoadForId);
if (unpauseRefreshUsers) {
@@ -521,6 +543,9 @@ public class UserSwitcherController {
SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
+ mAllowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
refreshUsers(UserHandle.USER_NULL);
};
};
@@ -615,10 +640,11 @@ public class UserSwitcherController {
}
}
- private void checkIfAddUserDisallowed(UserRecord record) {
+ private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
- if (admin != null) {
+ if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+ UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
record.isDisabledByAdmin = true;
record.enforcedAdmin = admin;
} else {
@@ -641,26 +667,29 @@ public class UserSwitcherController {
public final boolean isRestricted;
public boolean isDisabledByAdmin;
public EnforcedAdmin enforcedAdmin;
+ public boolean isSwitchToEnabled;
public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
- boolean isAddUser, boolean isRestricted) {
+ boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
this.info = info;
this.picture = picture;
this.isGuest = isGuest;
this.isCurrent = isCurrent;
this.isAddUser = isAddUser;
this.isRestricted = isRestricted;
+ this.isSwitchToEnabled = isSwitchToEnabled;
}
public UserRecord copyWithIsCurrent(boolean _isCurrent) {
- return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
+ return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
+ isSwitchToEnabled);
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UserRecord(");
if (info != null) {
- sb.append("name=\"" + info.name + "\" id=" + info.id);
+ sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
} else {
if (isGuest) {
sb.append("<add guest placeholder>");
@@ -675,7 +704,10 @@ public class UserSwitcherController {
if (isRestricted) sb.append(" <isRestricted>");
if (isDisabledByAdmin) {
sb.append(" <isDisabledByAdmin>");
- sb.append(" enforcedAdmin=" + enforcedAdmin);
+ sb.append(" enforcedAdmin=").append(enforcedAdmin);
+ }
+ if (isSwitchToEnabled) {
+ sb.append(" <isSwitchToEnabled>");
}
sb.append(')');
return sb.toString();
@@ -683,7 +715,7 @@ public class UserSwitcherController {
}
public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
- private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
+ private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
@Override
public CharSequence getTitle() {
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 5cfcd8981890..030c8b737e84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList;
@@ -43,16 +44,16 @@ public class NotificationChildrenContainer extends ViewGroup {
private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
- private final int mChildPadding;
- private final int mDividerHeight;
- private final int mMaxNotificationHeight;
private final List<View> mDividers = new ArrayList<>();
private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
- private final int mNotificationHeaderHeight;
- private final int mNotificationAppearDistance;
- private final int mNotificatonTopPadding;
private final HybridNotificationViewManager mHybridViewManager;
- private final float mCollapsedBottompadding;
+ private int mChildPadding;
+ private int mDividerHeight;
+ private int mMaxNotificationHeight;
+ private int mNotificationHeaderHeight;
+ private int mNotificationAppearDistance;
+ private int mNotificatonTopPadding;
+ private float mCollapsedBottompadding;
private ViewInvertHelper mOverflowInvertHelper;
private boolean mChildrenExpanded;
private ExpandableNotificationRow mNotificationParent;
@@ -60,6 +61,8 @@ public class NotificationChildrenContainer extends ViewGroup {
private ViewState mGroupOverFlowState;
private int mRealHeight;
private int mLayoutDirection = LAYOUT_DIRECTION_UNDEFINED;
+ private boolean mUserLocked;
+ private int mActualHeight;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -76,6 +79,11 @@ public class NotificationChildrenContainer extends ViewGroup {
public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ initDimens();
+ mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
+ }
+
+ private void initDimens() {
mChildPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_padding);
mDividerHeight = Math.max(1, getResources().getDimensionPixelSize(
@@ -89,7 +97,6 @@ public class NotificationChildrenContainer extends ViewGroup {
mNotificatonTopPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_container_top_padding);
mCollapsedBottompadding = 11.5f * getResources().getDisplayMetrics().density;
- mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
}
@Override
@@ -277,27 +284,45 @@ public class NotificationChildrenContainer extends ViewGroup {
*/
private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
int intrinsicHeight = mNotificationHeaderHeight;
- if (mChildrenExpanded) {
- intrinsicHeight += mNotificatonTopPadding;
- }
int visibleChildren = 0;
int childCount = mChildren.size();
+ boolean firstChild = true;
+ float expandFactor = 0;
+ if (mUserLocked) {
+ expandFactor = getChildExpandFraction();
+ }
for (int i = 0; i < childCount; i++) {
if (visibleChildren >= maxAllowedVisibleChildren) {
break;
}
+ if (!firstChild) {
+ if (mUserLocked) {
+ intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
+ expandFactor);
+ } else {
+ intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ }
+ } else {
+ if (mUserLocked) {
+ intrinsicHeight += NotificationUtils.interpolate(
+ 0,
+ mNotificatonTopPadding + mDividerHeight,
+ expandFactor);
+ } else {
+ intrinsicHeight += mChildrenExpanded
+ ? mNotificatonTopPadding + mDividerHeight
+ : 0;
+ }
+ firstChild = false;
+ }
ExpandableNotificationRow child = mChildren.get(i);
intrinsicHeight += child.getIntrinsicHeight();
visibleChildren++;
}
- if (visibleChildren > 0) {
- if (mChildrenExpanded) {
- intrinsicHeight += visibleChildren * mDividerHeight;
- } else {
- intrinsicHeight += (visibleChildren - 1) * mChildPadding;
- }
- }
- if (!mChildrenExpanded) {
+ if (mUserLocked) {
+ intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f,
+ expandFactor);
+ } else if (!mChildrenExpanded) {
intrinsicHeight += mCollapsedBottompadding;
}
return intrinsicHeight;
@@ -319,12 +344,28 @@ public class NotificationChildrenContainer extends ViewGroup {
int lastVisibleIndex = hasOverflow
? maxAllowedVisibleChildren - 2
: maxAllowedVisibleChildren - 1;
+ float expandFactor = 0;
+ if (mUserLocked) {
+ expandFactor = getChildExpandFraction();
+ }
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
- yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ if (mUserLocked) {
+ yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
+ expandFactor);
+ } else {
+ yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ }
} else {
- yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+ if (mUserLocked) {
+ yPosition += NotificationUtils.interpolate(
+ 0,
+ mNotificatonTopPadding + mDividerHeight,
+ expandFactor);
+ } else {
+ yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+ }
firstChild = false;
}
StackViewState childState = resultState.getViewStateForView(child);
@@ -371,6 +412,7 @@ public class NotificationChildrenContainer extends ViewGroup {
public void applyState(StackScrollState state) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
+ float expandFraction = getChildExpandFraction();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -380,7 +422,11 @@ public class NotificationChildrenContainer extends ViewGroup {
View divider = mDividers.get(i);
tmpState.initFrom(divider);
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
- tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ if (mUserLocked && viewState.alpha != 0) {
+ alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction);
+ }
+ tmpState.alpha = alpha;
state.applyViewState(divider, tmpState);
}
if (mGroupOverflowContainer != null) {
@@ -403,6 +449,7 @@ public class NotificationChildrenContainer extends ViewGroup {
long baseDelay, long duration) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
+ float expandFraction = getChildExpandFraction();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -412,7 +459,11 @@ public class NotificationChildrenContainer extends ViewGroup {
View divider = mDividers.get(i);
tmpState.initFrom(divider);
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
- tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+ if (mUserLocked && viewState.alpha != 0) {
+ alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction);
+ }
+ tmpState.alpha = alpha;
stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
}
if (mGroupOverflowContainer != null) {
@@ -445,7 +496,70 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public int getMaxContentHeight() {
- return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+ int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding;
+ int visibleChildren = 0;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) {
+ break;
+ }
+ ExpandableNotificationRow child = mChildren.get(i);
+ float childHeight = child.isExpanded()
+ ? child.getMaxExpandHeight()
+ : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+ maxContentHeight += childHeight;
+ visibleChildren++;
+ }
+ if (visibleChildren > 0) {
+ maxContentHeight += visibleChildren * mDividerHeight;
+ }
+ return maxContentHeight;
+ }
+
+ public void setActualHeight(int actualHeight) {
+ if (!mUserLocked) {
+ return;
+ }
+ mActualHeight = actualHeight;
+ float fraction = getChildExpandFraction();
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ ExpandableNotificationRow child = mChildren.get(i);
+ float childHeight = child.isExpanded()
+ ? child.getMaxExpandHeight()
+ : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+ float singleLineHeight = child.getShowingLayout().getMinHeight(
+ false /* likeGroupExpanded */);
+ child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, childHeight,
+ fraction), false);
+ }
+ }
+
+ public float getChildExpandFraction() {
+ int allChildrenVisibleHeight = getChildrenExpandStartHeight();
+ int maxContentHeight = getMaxContentHeight();
+ float factor = (mActualHeight - allChildrenVisibleHeight)
+ / (float) (maxContentHeight - allChildrenVisibleHeight);
+ return Math.max(0.0f, Math.min(1.0f, factor));
+ }
+
+ private int getChildrenExpandStartHeight() {
+ int intrinsicHeight = mNotificationHeaderHeight;
+ int visibleChildren = 0;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) {
+ break;
+ }
+ ExpandableNotificationRow child = mChildren.get(i);
+ intrinsicHeight += child.getMinHeight();
+ visibleChildren++;
+ }
+ if (visibleChildren > 0) {
+ intrinsicHeight += (visibleChildren - 1) * mChildPadding;
+ }
+ intrinsicHeight += mCollapsedBottompadding;
+ return intrinsicHeight;
}
public int getMinHeight() {
@@ -461,4 +575,25 @@ public class NotificationChildrenContainer extends ViewGroup {
mOverflowInvertHelper.setInverted(dark, fade, delay);
}
}
+
+ public void reInflateViews() {
+ initDimens();
+ for (int i = 0; i < mDividers.size(); i++) {
+ View prevDivider = mDividers.get(i);
+ int index = indexOfChild(prevDivider);
+ removeView(prevDivider);
+ View divider = inflateDivider();
+ addView(divider, index);
+ mDividers.set(i, divider);
+ }
+ }
+
+ public void setUserLocked(boolean userLocked) {
+ mUserLocked = userLocked;
+ int childCount = mChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ ExpandableNotificationRow child = mChildren.get(i);
+ child.setUserLocked(userLocked);
+ }
+ }
}
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 cc0e67df39cb..85b14264837d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -18,10 +18,12 @@ package com.android.systemui.statusbar.stack;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
@@ -32,6 +34,7 @@ import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
@@ -56,8 +59,12 @@ import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationOverflowContainer;
+import com.android.systemui.statusbar.NotificationSettingsIconRow;
+import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -65,6 +72,8 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
/**
@@ -72,10 +81,11 @@ import java.util.HashSet;
*/
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
- ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
+ ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
+ SettingsIconRowListener {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
- private static final String TAG = "NotificationStackScrollLayout";
+ private static final String TAG = "StackScroller";
private static final boolean DEBUG = false;
private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f;
@@ -87,7 +97,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private static final int INVALID_POINTER = -1;
private ExpandHelper mExpandHelper;
- private SwipeHelper mSwipeHelper;
+ private NotificationSwipeHelper mSwipeHelper;
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
@@ -136,7 +146,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
private AmbientState mAmbientState = new AmbientState();
private NotificationGroupManager mGroupManager;
- private ArrayList<View> mChildrenToAddAnimated = new ArrayList<>();
+ private HashSet<View> mChildrenToAddAnimated = new HashSet<>();
private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<>();
private ArrayList<View> mSnappedBackChildren = new ArrayList<>();
@@ -207,13 +217,17 @@ public class NotificationStackScrollLayout extends ViewGroup
*/
private int mMaxScrollAfterExpand;
private SwipeHelper.LongPressListener mLongPressListener;
+ private GearDisplayedListener mGearDisplayedListener;
+
+ private NotificationSettingsIconRow mCurrIconRow;
+ private View mTranslatingParentView;
+ private View mGearExposedView;
/**
* Should in this touch motion only be scrolling allowed? It's true when the scroller was
* animating.
*/
private boolean mOnlyScrollingInThisMotion;
- private ViewGroup mScrollView;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
@@ -267,6 +281,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private int mBgColor;
private float mDimAmount;
private ValueAnimator mDimAnimator;
+ private ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
private Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -281,6 +296,32 @@ public class NotificationStackScrollLayout extends ViewGroup
setDimAmount((Float) animation.getAnimatedValue());
}
};
+ private ViewGroup mQsContainer;
+ private boolean mContinuousShadowUpdate;
+ private ViewTreeObserver.OnPreDrawListener mShadowUpdater
+ = new ViewTreeObserver.OnPreDrawListener() {
+
+ @Override
+ public boolean onPreDraw() {
+ updateViewShadows();
+ return true;
+ }
+ };
+ private Comparator<ExpandableView> mViewPositionComparator = new Comparator<ExpandableView>() {
+ @Override
+ public int compare(ExpandableView view, ExpandableView otherView) {
+ float endY = view.getTranslationY() + view.getActualHeight();
+ float otherEndY = otherView.getTranslationY() + otherView.getActualHeight();
+ if (endY < otherEndY) {
+ return -1;
+ } else if (endY > otherEndY) {
+ return 1;
+ } else {
+ // The two notifications end at the same location
+ return 0;
+ }
+ }
+ };
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -304,8 +345,7 @@ public class NotificationStackScrollLayout extends ViewGroup
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
-
- mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
+ mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext());
mSwipeHelper.setLongPressListener(mLongPressListener);
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
initView(context);
@@ -321,6 +361,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ public void onGearTouched(ExpandableNotificationRow row, int x, int y) {
+ if (mLongPressListener != null) {
+ mLongPressListener.onLongPress(row, x, y);
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
if (DEBUG) {
@@ -474,6 +521,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
private void updateChildren() {
+ updateScrollStateForAddedChildren();
mAmbientState.setScrollY(mOwnScrollY);
mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
if (!isCurrentlyAnimating() && !mNeedsAnimation) {
@@ -483,6 +531,28 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ private void updateScrollStateForAddedChildren() {
+ if (mChildrenToAddAnimated.isEmpty()) {
+ return;
+ }
+ for (int i = 0; i < getChildCount(); i++) {
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ if (mChildrenToAddAnimated.contains(child)) {
+ int startingPosition = getPositionInLinearLayout(child);
+ int padding = child.getIncreasedPaddingAmount() == 1.0f
+ ? mIncreasedPaddingBetweenElements :
+ 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
+
+ mOwnScrollY += childHeight;
+ }
+ }
+ }
+ clampScrollPosition();
+ }
+
private void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
@@ -607,12 +677,12 @@ public class NotificationStackScrollLayout extends ViewGroup
mLongPressListener = listener;
}
- public void setScrollView(ViewGroup scrollView) {
- mScrollView = scrollView;
+ public void setGearDisplayedListener(GearDisplayedListener listener) {
+ mGearDisplayedListener = listener;
}
- public void setInterceptDelegateEnabled(boolean interceptDelegateEnabled) {
- mInterceptDelegateEnabled = interceptDelegateEnabled;
+ public void setQsContainer(ViewGroup qsContainer) {
+ mQsContainer = qsContainer;
}
public void onChildDismissed(View v) {
@@ -627,6 +697,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
mSwipedOutViews.add(v);
mAmbientState.onDragFinished(v);
+ updateContinuousShadowDrawing();
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (row.isHeadsUp()) {
@@ -647,8 +718,9 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- public void onChildSnappedBack(View animView) {
+ public void onChildSnappedBack(View animView, float targetLeft) {
mAmbientState.onDragFinished(animView);
+ updateContinuousShadowDrawing();
if (!mDragAnimPendingChildren.contains(animView)) {
if (mAnimationsEnabled) {
mSnappedBackChildren.add(animView);
@@ -659,6 +731,13 @@ public class NotificationStackScrollLayout extends ViewGroup
// We start the swipe and snap back in the same frame, we don't want any animation
mDragAnimPendingChildren.remove(animView);
}
+
+ if (targetLeft == 0 && mCurrIconRow != null) {
+ mCurrIconRow.resetState();
+ if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
+ mGearExposedView = null;
+ }
+ }
}
@Override
@@ -667,13 +746,14 @@ public class NotificationStackScrollLayout extends ViewGroup
mScrimController.setTopHeadsUpDragAmount(animView,
Math.min(Math.abs(swipeProgress - 1.0f), 1.0f));
}
- return false;
+ return true; // Don't fade out the notification
}
public void onBeginDrag(View v) {
mFalsingManager.onNotificatonStartDismissing();
setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
+ updateContinuousShadowDrawing();
if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
mDragAnimPendingChildren.add(v);
mNeedsAnimation = true;
@@ -707,8 +787,21 @@ public class NotificationStackScrollLayout extends ViewGroup
return mPhoneStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
+ @Override
public View getChildAtPosition(MotionEvent ev) {
- return getChildAtPosition(ev.getX(), ev.getY());
+ View child = getChildAtPosition(ev.getX(), ev.getY());
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (mGearExposedView != null && parent != null
+ && parent.areChildrenExpanded() && mGearExposedView == parent) {
+ // In this case the group is expanded and showing the gear for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child.
+ child = row.getNotificationParent();
+ }
+ }
+ return child;
}
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
@@ -822,10 +915,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return mScrollingEnabled;
}
- public View getChildContentView(View v) {
- return v;
- }
-
public boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@@ -860,13 +949,6 @@ public class NotificationStackScrollLayout extends ViewGroup
public boolean onTouchEvent(MotionEvent ev) {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked()== MotionEvent.ACTION_UP;
- if (mDelegateToScrollView) {
- if (isCancelOrUp) {
- mDelegateToScrollView = false;
- }
- transformTouchEvent(ev, this, mScrollView);
- return mScrollView.onTouchEvent(ev);
- }
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion) {
@@ -906,6 +988,9 @@ public class NotificationStackScrollLayout extends ViewGroup
if (!isScrollingEnabled()) {
return false;
}
+ if (ev.getY() < mQsContainer.getBottom()) {
+ return false;
+ }
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
@@ -1447,18 +1532,18 @@ public class NotificationStackScrollLayout extends ViewGroup
private void updateContentHeight() {
int height = 0;
- boolean previousNeedsIncreasedPaddings = false;
+ float previousIncreasedAmount = 0.0f;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView expandableView = (ExpandableView) getChildAt(i);
if (expandableView.getVisibility() != View.GONE) {
- boolean needsIncreasedPaddings = expandableView.needsIncreasedPadding();
+ float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
if (height != 0) {
- int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
- ? mIncreasedPaddingBetweenElements
- : mPaddingBetweenElements;
- height += padding;
+ height += (int) NotificationUtils.interpolate(
+ mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ Math.max(previousIncreasedAmount, increasedPaddingAmount));
}
- previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+ previousIncreasedAmount = increasedPaddingAmount;
height += expandableView.getIntrinsicHeight();
}
}
@@ -1648,12 +1733,17 @@ public class NotificationStackScrollLayout extends ViewGroup
bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
bottom = Math.min(bottom, getHeight());
}
- } else if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) {
- top = mTopPadding;
+ } else {
+ top = (int) (mTopPadding + mStackTranslation);
bottom = top;
}
- mBackgroundBounds.top = Math.max(0, top);
- mBackgroundBounds.bottom = Math.min(getHeight(), bottom);
+ if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD) {
+ mBackgroundBounds.top = (int) Math.max(mTopPadding + mStackTranslation, top);
+ } else {
+ // otherwise the animation from the shade to the keyguard will jump as it's maxed
+ mBackgroundBounds.top = Math.max(0, top);
+ }
+ mBackgroundBounds.bottom = Math.min(getHeight(), Math.max(bottom, top));
}
private ActivatableNotificationView getFirstPinnedHeadsUp() {
@@ -1724,8 +1814,12 @@ public class NotificationStackScrollLayout extends ViewGroup
// it will be set once we reach the boundary
mMaxOverScroll = 0.0f;
}
+ int minScrollY = Math.max(0, scrollRange);
+ if (mExpandedInThisMotion) {
+ minScrollY = Math.min(minScrollY, mMaxScrollAfterExpand);
+ }
mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0,
- Math.max(0, scrollRange), 0, Integer.MAX_VALUE / 2);
+ minScrollY, 0, mExpandedInThisMotion && mOwnScrollY >= 0 ? 0 : Integer.MAX_VALUE / 2);
postInvalidateOnAnimation();
}
@@ -1748,15 +1842,13 @@ public class NotificationStackScrollLayout extends ViewGroup
* account.
*
* @param qsHeight the top padding imposed by the quick settings panel
- * @param scrollY how much the notifications are scrolled inside the QS/notifications scroll
- * container
* @param animate whether to animate the change
* @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
* {@code qsHeight} is the final top padding
*/
- public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
+ public void updateTopPadding(float qsHeight, boolean animate,
boolean ignoreIntrinsicPadding) {
- float start = qsHeight - scrollY;
+ float start = qsHeight;
float stackHeight = getHeight() - start;
int minStackHeight = getMinStackHeight();
if (stackHeight <= minStackHeight) {
@@ -1839,15 +1931,6 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mInterceptDelegateEnabled) {
- transformTouchEvent(ev, this, mScrollView);
- if (mScrollView.onInterceptTouchEvent(ev)) {
- mDelegateToScrollView = true;
- removeLongPressCallback();
- return true;
- }
- transformTouchEvent(ev, mScrollView, this);
- }
initDownStates(ev);
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
@@ -2019,9 +2102,10 @@ public class NotificationStackScrollLayout extends ViewGroup
*/
private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
int startingPosition = getPositionInLinearLayout(removedChild);
- int padding = removedChild.needsIncreasedPadding()
- ? mIncreasedPaddingBetweenElements :
- mPaddingBetweenElements;
+ int padding = (int) NotificationUtils.interpolate(
+ mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ removedChild.getIncreasedPaddingAmount());
int childHeight = getIntrinsicHeight(removedChild) + padding;
int endPosition = startingPosition + childHeight;
if (endPosition <= mOwnScrollY) {
@@ -2045,19 +2129,19 @@ public class NotificationStackScrollLayout extends ViewGroup
private int getPositionInLinearLayout(View requestedChild) {
int position = 0;
- boolean previousNeedsIncreasedPaddings = false;
+ float previousIncreasedAmount = 0.0f;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
boolean notGone = child.getVisibility() != View.GONE;
if (notGone) {
- boolean needsIncreasedPaddings = child.needsIncreasedPadding();
+ float increasedPaddingAmount = child.getIncreasedPaddingAmount();
if (position != 0) {
- int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
- ? mIncreasedPaddingBetweenElements :
- mPaddingBetweenElements;
- position += padding;
+ position += (int) NotificationUtils.interpolate(
+ mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ Math.max(previousIncreasedAmount, increasedPaddingAmount));
}
- previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+ previousIncreasedAmount = increasedPaddingAmount;
}
if (child == requestedChild) {
return position;
@@ -2129,7 +2213,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateAnimationState(View child) {
- updateAnimationState((mAnimationsEnabled || isPinnedHeadsUp(child)) && mIsExpanded, child);
+ updateAnimationState(mAnimationsEnabled && (mIsExpanded || isPinnedHeadsUp(child)), child);
}
@@ -2196,6 +2280,7 @@ public class NotificationStackScrollLayout extends ViewGroup
setAnimationRunning(true);
mAnimationEvents.clear();
updateBackground();
+ updateViewShadows();
} else {
applyCurrentState();
}
@@ -2778,6 +2863,43 @@ public class NotificationStackScrollLayout extends ViewGroup
}
runAnimationFinishedRunnables();
updateBackground();
+ updateViewShadows();
+ }
+
+ private void updateViewShadows() {
+ // we need to work around an issue where the shadow would not cast between siblings when
+ // their z difference is between 0 and 0.1
+
+ // Lefts first sort by Z difference
+ for (int i = 0; i < getChildCount(); i++) {
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ mTmpSortedChildren.add(child);
+ }
+ }
+ Collections.sort(mTmpSortedChildren, mViewPositionComparator);
+
+ // Now lets update the shadow for the views
+ ExpandableView previous = null;
+ for (int i = 0; i < mTmpSortedChildren.size(); i++) {
+ ExpandableView expandableView = mTmpSortedChildren.get(i);
+ float translationZ = expandableView.getTranslationZ();
+ float otherZ = previous == null ? translationZ : previous.getTranslationZ();
+ float diff = otherZ - translationZ;
+ if (diff <= 0.0f || diff >= FakeShadowView.SHADOW_SIBLING_TRESHOLD) {
+ // There is no fake shadow to be drawn
+ expandableView.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
+ } else {
+ float yLocation = previous.getTranslationY() + previous.getActualHeight() -
+ expandableView.getTranslationY();
+ expandableView.setFakeShadowIntensity(diff / FakeShadowView.SHADOW_SIBLING_TRESHOLD,
+ previous.getOutlineAlpha(), (int) yLocation,
+ previous.getOutlineTranslation());
+ }
+ previous = expandableView;
+ }
+
+ mTmpSortedChildren.clear();
}
public void goToFullShade(long delay) {
@@ -2865,13 +2987,23 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public void setDismissView(DismissView dismissView) {
+ int index = -1;
+ if (mDismissView != null) {
+ index = indexOfChild(mDismissView);
+ removeView(mDismissView);
+ }
mDismissView = dismissView;
- addView(mDismissView);
+ addView(mDismissView, index);
}
public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
+ int index = -1;
+ if (mEmptyShadeView != null) {
+ index = indexOfChild(mEmptyShadeView);
+ removeView(mEmptyShadeView);
+ }
mEmptyShadeView = emptyShadeView;
- addView(mEmptyShadeView);
+ addView(mEmptyShadeView, index);
}
public void updateEmptyShadeView(boolean visible) {
@@ -2989,6 +3121,9 @@ public class NotificationStackScrollLayout extends ViewGroup
disableClipOptimization();
}
handleDismissAllClipping();
+ if (mCurrIconRow != null && mCurrIconRow.isVisible()) {
+ mCurrIconRow.getNotificationParent().animateTranslateNotification(0 /* left target */);
+ }
}
private void handleDismissAllClipping() {
@@ -3203,9 +3338,14 @@ public class NotificationStackScrollLayout extends ViewGroup
getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
}
mAnimationRunning = animationRunning;
+ updateContinuousShadowDrawing();
}
}
+ public boolean isExpanded() {
+ return mIsExpanded;
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
@@ -3245,6 +3385,259 @@ public class NotificationStackScrollLayout extends ViewGroup
public void flingTopOverscroll(float velocity, boolean open);
}
+ /**
+ * A listener that is notified when the gear is shown behind a notification.
+ */
+ public interface GearDisplayedListener {
+ void onGearDisplayed(ExpandableNotificationRow row);
+ }
+
+ private class NotificationSwipeHelper extends SwipeHelper {
+ private static final int MOVE_STATE_LEFT = -1;
+ private static final int MOVE_STATE_UNDEFINED = 0;
+ private static final int MOVE_STATE_RIGHT = 1;
+
+ private static final long GEAR_SHOW_DELAY = 60;
+
+ private ArrayList<View> mTranslatingViews = new ArrayList<>();
+ private CheckForDrag mCheckForDrag;
+ private Handler mHandler;
+ private int mMoveState = MOVE_STATE_UNDEFINED;
+
+ public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
+ super(swipeDirection, callback, context);
+ mHandler = new Handler();
+ }
+
+ @Override
+ public void onDownUpdate(View currView) {
+ // Set the active view
+ mTranslatingParentView = currView;
+
+ // Reset check for drag gesture
+ mCheckForDrag = null;
+
+ // Slide back any notifications that might be showing a gear
+ resetExposedGearView();
+
+ if (currView instanceof ExpandableNotificationRow) {
+ // Set the listener for the current row's gear
+ mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
+ mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
+
+ // And the translating children
+ mTranslatingViews = ((ExpandableNotificationRow) currView).getContentViews();
+ }
+ mMoveState = MOVE_STATE_UNDEFINED;
+ }
+
+ @Override
+ public void onMoveUpdate(View view, float translation, float delta) {
+ final int newMoveState = (delta < 0) ? MOVE_STATE_RIGHT : MOVE_STATE_LEFT;
+ if (mMoveState != MOVE_STATE_UNDEFINED && mMoveState != newMoveState) {
+ // Changed directions, make sure we check for drag again.
+ mCheckForDrag = null;
+ }
+ mMoveState = newMoveState;
+
+ if (view instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) view).setTranslationForOutline(translation);
+ if (!isPinnedHeadsUp(view)) {
+ // Only show the gear if we're not a heads up view.
+ checkForDrag();
+ if (mCurrIconRow != null) {
+ mCurrIconRow.updateSettingsIcons(translation, getSize(view));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dismissChild(final View view, float velocity) {
+ cancelCheckForDrag();
+ super.dismissChild(view, velocity);
+ }
+
+ @Override
+ public void snapChild(final View animView, final float targetLeft, float velocity) {
+ final float snapBackThreshold = getSpaceForGear(animView);
+ final float translation = getTranslation(animView);
+ final boolean fromLeft = translation > 0;
+ final float absTrans = Math.abs(translation);
+ final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
+
+ boolean pastGear = (fromLeft && translation >= snapBackThreshold * 0.4f
+ && translation <= notiThreshold) ||
+ (!fromLeft && absTrans >= snapBackThreshold * 0.4f
+ && absTrans <= notiThreshold);
+
+ if (pastGear && !isPinnedHeadsUp(animView)) {
+ // bouncity
+ final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
+ mGearExposedView = mTranslatingParentView;
+ if (mGearDisplayedListener != null
+ && (animView instanceof ExpandableNotificationRow)) {
+ mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
+ }
+ super.snapChild(animView, target, velocity);
+ } else {
+ super.snapChild(animView, 0, velocity);
+ }
+ }
+
+ @Override
+ public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ super.onTranslationUpdate(animView, value, canBeDismissed);
+ return;
+ }
+ if (animView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) animView).setTranslationForOutline(value);
+ }
+ if (mCurrIconRow != null) {
+ mCurrIconRow.updateSettingsIcons(value, getSize(animView));
+ }
+ }
+
+ @Override
+ public Animator getViewTranslationAnimator(View v, float target,
+ AnimatorUpdateListener listener) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ return super.getViewTranslationAnimator(v, target, listener);
+ }
+ ArrayList<Animator> animators = new ArrayList<Animator>();
+ for (int i = 0; i < mTranslatingViews.size(); i++) {
+ ObjectAnimator anim = createTranslationAnimation(mTranslatingViews.get(i), target);
+ animators.add(anim);
+ if (i == 0 && listener != null) {
+ anim.addUpdateListener(listener);
+ }
+ }
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animators);
+ return set;
+ }
+
+ @Override
+ public void setTranslation(View v, float translate) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ super.setTranslation(v, translate);
+ return;
+ }
+ // Translate the group of views
+ for (int i = 0; i < mTranslatingViews.size(); i++) {
+ if (mTranslatingViews.get(i) != null) {
+ super.setTranslation(mTranslatingViews.get(i), translate);
+ }
+ }
+ }
+
+ @Override
+ public float getTranslation(View v) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ return super.getTranslation(v);
+ }
+ // All of the views in the list should have same translation, just use first one.
+ if (mTranslatingViews.size() > 0) {
+ return super.getTranslation(mTranslatingViews.get(0));
+ }
+ return 0;
+ }
+
+
+ /**
+ * Returns the horizontal space in pixels required to display the gear behind a
+ * notification.
+ */
+ private float getSpaceForGear(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) view).getSpaceForGear();
+ }
+ return 0;
+ }
+
+ private void checkForDrag() {
+ if (mCheckForDrag == null) {
+ mCheckForDrag = new CheckForDrag();
+ mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
+ }
+ }
+
+ private void cancelCheckForDrag() {
+ if (mCurrIconRow != null) {
+ mCurrIconRow.cancelFadeAnimator();
+ }
+ mHandler.removeCallbacks(mCheckForDrag);
+ mCheckForDrag = null;
+ }
+
+ private final class CheckForDrag implements Runnable {
+ @Override
+ public void run() {
+ final float translation = getTranslation(mTranslatingParentView);
+ final float absTransX = Math.abs(translation);
+ final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
+ final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
+ if (mCurrIconRow != null && absTransX >= bounceBackToGearWidth * 0.4
+ && absTransX < notiThreshold) {
+ // Show icon
+ mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
+ notiThreshold);
+ } else {
+ // Allow more to be posted if this wasn't a drag.
+ mCheckForDrag = null;
+ }
+ }
+ }
+
+ private void resetExposedGearView() {
+ if (mGearExposedView == null || mGearExposedView == mTranslatingParentView) {
+ // If no gear is showing or it's showing for this view we do nothing.
+ return;
+ }
+
+ final View prevGearExposedView = mGearExposedView;
+ mGearExposedView = null;
+
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animator) {
+ if (prevGearExposedView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) prevGearExposedView).getSettingsRow()
+ .resetState();
+ }
+ }
+ };
+ AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (prevGearExposedView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) prevGearExposedView)
+ .setTranslationForOutline((float) animation.getAnimatedValue());
+ }
+ }
+ };
+ Animator set = getViewTranslationAnimator(prevGearExposedView, 0, updateListener);
+ set.addListener(listener);
+ set.start();
+ }
+ }
+
+ private void updateContinuousShadowDrawing() {
+ boolean continuousShadowUpdate = mAnimationRunning
+ || !mAmbientState.getDraggedViews().isEmpty();
+ if (continuousShadowUpdate != mContinuousShadowUpdate) {
+ if (continuousShadowUpdate) {
+ getViewTreeObserver().addOnPreDrawListener(mShadowUpdater);
+ } else {
+ getViewTreeObserver().removeOnPreDrawListener(mShadowUpdater);
+ }
+ }
+ }
+
static class AnimationEvent {
static AnimationFilter[] FILTERS = new AnimationFilter[] {
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 f6959f0dfcbb..eea923f68b20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -24,9 +24,11 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
/**
@@ -39,17 +41,14 @@ public class StackScrollAlgorithm {
private static final String LOG_TAG = "StackScrollAlgorithm";
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
- private static final int MAX_ITEMS_IN_TOP_STACK = 3;
private int mPaddingBetweenElements;
private int mIncreasedPaddingBetweenElements;
private int mCollapsedSize;
- private int mTopStackPeekSize;
private int mBottomStackPeekSize;
private int mZDistanceBetweenElements;
private int mZBasicHeight;
- private StackIndentationFunctor mTopStackIndentationFunctor;
private StackIndentationFunctor mBottomStackIndentationFunctor;
private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
@@ -58,12 +57,8 @@ public class StackScrollAlgorithm {
private boolean mIsExpanded;
private ExpandableView mFirstChildWhileExpanding;
private boolean mExpandedOnStart;
- private int mTopStackTotalSize;
private int mBottomStackSlowDownLength;
- private int mTopStackSlowDownLength;
private int mCollapseSecondCardPadding;
- private ExpandableView mFirstChild;
- private int mFirstChildMinHeight;
public StackScrollAlgorithm(Context context) {
initView(context);
@@ -71,22 +66,6 @@ public class StackScrollAlgorithm {
public void initView(Context context) {
initConstants(context);
- updatePadding();
- }
-
- private void updatePadding() {
- mTopStackTotalSize = mTopStackSlowDownLength + mPaddingBetweenElements
- + mTopStackPeekSize;
- mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
- MAX_ITEMS_IN_TOP_STACK,
- mTopStackPeekSize,
- mTopStackTotalSize - mTopStackPeekSize,
- 0.5f);
- mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
- MAX_ITEMS_IN_BOTTOM_STACK,
- mBottomStackPeekSize,
- getBottomStackSlowDownLength(),
- 0.5f);
}
public int getBottomStackSlowDownLength() {
@@ -100,8 +79,6 @@ public class StackScrollAlgorithm {
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
- mTopStackPeekSize = context.getResources()
- .getDimensionPixelSize(R.dimen.top_stack_peek_amount);
mBottomStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
mZDistanceBetweenElements = Math.max(1, context.getResources()
@@ -109,10 +86,13 @@ public class StackScrollAlgorithm {
mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
mBottomStackSlowDownLength = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
- mTopStackSlowDownLength = context.getResources()
- .getDimensionPixelSize(R.dimen.top_stack_slow_down_length);
mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
R.dimen.notification_collapse_second_card_padding);
+ mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
+ MAX_ITEMS_IN_BOTTOM_STACK,
+ mBottomStackPeekSize,
+ getBottomStackSlowDownLength(),
+ 0.5f);
}
public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -123,32 +103,13 @@ public class StackScrollAlgorithm {
// First we reset the view states to their default values.
resultState.resetViewStates();
- algorithmState.itemsInTopStack = 0.0f;
- algorithmState.partialInTop = 0.0f;
- algorithmState.lastTopStackIndex = 0;
- algorithmState.scrolledPixelsTop = 0;
- algorithmState.itemsInBottomStack = 0.0f;
- algorithmState.partialInBottom = 0.0f;
- mFirstChildMinHeight = mFirstChild == null ? 0 : mFirstChild.getMinHeight();
- float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
-
- int scrollY = ambientState.getScrollY();
-
- // Due to the overScroller, the stackscroller can have negative scroll state. This is
- // already accounted for by the top padding and doesn't need an additional adaption
- scrollY = Math.max(0, scrollY);
- algorithmState.scrollY = (int) (scrollY + mFirstChildMinHeight + bottomOverScroll);
-
- initAlgorithmState(resultState, algorithmState);
-
- // Phase 1:
- findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState, ambientState);
+ initAlgorithmState(resultState, algorithmState, ambientState);
- // Phase 2:
updatePositionsForState(resultState, algorithmState, ambientState);
- // Phase 3:
- updateZValuesForState(resultState, algorithmState);
+ updateZValuesForState(resultState, algorithmState, ambientState);
+
+ updateHeadsUpStates(resultState, algorithmState, ambientState);
handleDraggedViews(ambientState, resultState, algorithmState);
updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
@@ -185,6 +146,7 @@ public class StackScrollAlgorithm {
private void updateClipping(StackScrollState resultState,
StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
boolean dismissAllInProgress = ambientState.isDismissAllInProgress();
+ float drawStart = ambientState.getTopPadding() + ambientState.getStackTranslation();
float previousNotificationEnd = 0;
float previousNotificationStart = 0;
boolean previousNotificationIsSwiped = false;
@@ -192,6 +154,10 @@ public class StackScrollAlgorithm {
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState state = resultState.getViewStateForView(child);
+ if (!child.mustStayOnScreen()) {
+ previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
+ previousNotificationStart = Math.max(drawStart, previousNotificationStart);
+ }
float newYTranslation = state.yTranslation;
float newHeight = state.height;
// apply clipping and shadow
@@ -222,7 +188,7 @@ public class StackScrollAlgorithm {
} else {
previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child);
previousNotificationEnd = newNotificationEnd;
- previousNotificationStart = newYTranslation + state.clipTopAmount;
+ previousNotificationStart =newYTranslation + state.clipTopAmount;
}
}
}
@@ -314,24 +280,40 @@ public class StackScrollAlgorithm {
/**
* Initialize the algorithm state like updating the visible children.
*/
- private void initAlgorithmState(StackScrollState resultState,
- StackScrollAlgorithmState state) {
+ private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state,
+ AmbientState ambientState) {
+ state.itemsInBottomStack = 0.0f;
+ state.partialInBottom = 0.0f;
+ float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
+
+ int scrollY = ambientState.getScrollY();
+
+ // Due to the overScroller, the stackscroller can have negative scroll state. This is
+ // already accounted for by the top padding and doesn't need an additional adaption
+ scrollY = Math.max(0, scrollY);
+ state.scrollY = (int) (scrollY + bottomOverScroll);
+
+ //now init the visible children and update paddings
ViewGroup hostView = resultState.getHostView();
int childCount = hostView.getChildCount();
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
- state.increasedPaddingSet.clear();
+ state.increasedPaddingMap.clear();
int notGoneIndex = 0;
ExpandableView lastView = null;
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
- boolean needsIncreasedPadding = v.needsIncreasedPadding();
- if (needsIncreasedPadding) {
- state.increasedPaddingSet.add(v);
+ float increasedPadding = v.getIncreasedPaddingAmount();
+ if (increasedPadding != 0.0f) {
+ state.increasedPaddingMap.put(v, increasedPadding);
if (lastView != null) {
- state.increasedPaddingSet.add(lastView);
+ Float prevValue = state.increasedPaddingMap.get(lastView);
+ float newValue = prevValue != null
+ ? Math.max(prevValue, increasedPadding)
+ : increasedPadding;
+ state.increasedPaddingMap.put(lastView, newValue);
}
}
if (v instanceof ExpandableNotificationRow) {
@@ -383,15 +365,9 @@ public class StackScrollAlgorithm {
float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;
// The y coordinate of the current child.
- float currentYPosition = 0.0f;
-
- // How far in is the element currently transitioning into the bottom stack.
- float yPositionInScrollView = 0.0f;
+ float currentYPosition = -algorithmState.scrollY;
int childCount = algorithmState.visibleChildren.size();
- int numberOfElementsCompletelyIn = algorithmState.partialInTop == 1.0f
- ? algorithmState.lastTopStackIndex
- : (int) algorithmState.itemsInTopStack;
int paddingAfterChild;
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
@@ -400,47 +376,16 @@ public class StackScrollAlgorithm {
paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
int minHeight = child.getMinHeight();
- float yPositionInScrollViewAfterElement = yPositionInScrollView
- + childHeight
- + paddingAfterChild;
- float scrollOffset = yPositionInScrollView - algorithmState.scrollY +
- mFirstChildMinHeight;
-
- if (i == algorithmState.lastTopStackIndex + 1) {
- // Normally the position of this child is the position in the regular scrollview,
- // but if the two stacks are very close to each other,
- // then have have to push it even more upwards to the position of the bottom
- // stack start.
- currentYPosition = Math.min(scrollOffset, bottomStackStart);
- }
childViewState.yTranslation = currentYPosition;
+ if (i == 0) {
+ updateFirstChildHeight(child, childViewState, childHeight, ambientState);
+ }
// The y position after this element
float nextYPosition = currentYPosition + childHeight +
paddingAfterChild;
-
- if (i <= algorithmState.lastTopStackIndex) {
+ if (nextYPosition >= bottomStackStart) {
// Case 1:
- // We are in the top Stack
- updateStateForTopStackChild(algorithmState, child,
- numberOfElementsCompletelyIn, i, childHeight, childViewState, scrollOffset);
- clampPositionToTopStackEnd(childViewState, childHeight);
-
- // check if we are overlapping with the bottom stack
- if (childViewState.yTranslation + childHeight + paddingAfterChild
- >= bottomStackStart && !mIsExpansionChanging && i != 0) {
- // we just collapse this element slightly
- int newSize = (int) Math.max(bottomStackStart - paddingAfterChild -
- childViewState.yTranslation, minHeight);
- childViewState.height = newSize;
- updateStateForChildTransitioningInBottom(algorithmState, bottomStackStart,
- child, childViewState.yTranslation, childViewState,
- childHeight);
- }
- clampPositionToBottomStackStart(childViewState, childViewState.height,
- minHeight, ambientState);
- } else if (nextYPosition >= bottomStackStart) {
- // Case 2:
// We are in the bottom stack.
if (currentYPosition >= bottomStackStart) {
// According to the regular scroll view we are fully translated out of the
@@ -455,43 +400,40 @@ public class StackScrollAlgorithm {
childViewState, childHeight);
}
} else {
- // Case 3:
+ // Case 2:
// We are in the regular scroll area.
childViewState.location = StackViewState.LOCATION_MAIN_AREA;
- clampYTranslation(childViewState, childHeight, ambientState);
+ clampPositionToBottomStackStart(childViewState, childViewState.height, childHeight,
+ ambientState);
}
- // The first card is always rendered.
- if (i == 0) {
- childViewState.hidden = false;
- childViewState.shadowAlpha = 1.0f;
- childViewState.yTranslation = Math.max(
- mFirstChildMinHeight - algorithmState.scrollY, 0);
- if (childViewState.yTranslation + childViewState.height
- > bottomPeekStart - mCollapseSecondCardPadding) {
- childViewState.height = (int) Math.max(
- bottomPeekStart - mCollapseSecondCardPadding
- - childViewState.yTranslation, mFirstChildMinHeight);
- }
- childViewState.location = StackViewState.LOCATION_FIRST_CARD;
+ if (i == 0 && ambientState.getScrollY() <= 0) {
+ // The first card can get into the bottom stack if it's the only one
+ // on the lockscreen which pushes it up. Let's make sure that doesn't happen and
+ // it stays at the top
+ childViewState.yTranslation = Math.max(0, childViewState.yTranslation);
+ }
+ currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
+ if (currentYPosition <= 0) {
+ childViewState.location = StackViewState.LOCATION_HIDDEN_TOP;
}
if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
- currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
- yPositionInScrollView = yPositionInScrollViewAfterElement;
childViewState.yTranslation += ambientState.getTopPadding()
+ ambientState.getStackTranslation();
}
- updateHeadsUpStates(resultState, algorithmState, ambientState);
}
private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
ExpandableView child) {
- return algorithmState.increasedPaddingSet.contains(child)
- ? mIncreasedPaddingBetweenElements
- : mPaddingBetweenElements;
+ Float paddingValue = algorithmState.increasedPaddingMap.get(child);
+ return paddingValue == null
+ ? mPaddingBetweenElements
+ : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ paddingValue);
}
private void updateHeadsUpStates(StackScrollState resultState,
@@ -506,24 +448,27 @@ public class StackScrollAlgorithm {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
if (!row.isHeadsUp()) {
break;
- } else if (topHeadsUpEntry == null) {
- topHeadsUpEntry = row;
}
StackViewState childState = resultState.getViewStateForView(row);
+ if (topHeadsUpEntry == null) {
+ topHeadsUpEntry = row;
+ childState.location = StackViewState.LOCATION_FIRST_HUN;
+ }
boolean isTopEntry = topHeadsUpEntry == row;
+ float unmodifiedEndLocation = childState.yTranslation + childState.height;
if (mIsExpanded) {
- // Ensure that the heads up is always visible even when scrolled off from the bottom
- float bottomPosition = ambientState.getMaxHeadsUpTranslation() - childState.height;
- childState.yTranslation = Math.min(childState.yTranslation,
- bottomPosition);
+ // Ensure that the heads up is always visible even when scrolled off
+ clampHunToTop(ambientState, row, childState);
+ clampHunToMaxTranslation(ambientState, row, childState);
}
if (row.isPinned()) {
childState.yTranslation = Math.max(childState.yTranslation, 0);
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
- if (!isTopEntry) {
+ StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
+ if (!isTopEntry && (!mIsExpanded
+ || unmodifiedEndLocation < topState.yTranslation + topState.height)) {
// Ensure that a headsUp doesn't vertically extend further than the heads-up at
// the top most z-position
- StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
childState.height = row.getIntrinsicHeight();
childState.yTranslation = topState.yTranslation + topState.height
- childState.height;
@@ -532,17 +477,23 @@ public class StackScrollAlgorithm {
}
}
- /**
- * Clamp the yTranslation both up and down to valid positions.
- *
- * @param childViewState the view state of the child
- * @param minHeight the minimum height of this child
- */
- private void clampYTranslation(StackViewState childViewState, int minHeight,
- AmbientState ambientState) {
- clampPositionToBottomStackStart(childViewState, childViewState.height, minHeight,
- ambientState);
- clampPositionToTopStackEnd(childViewState, childViewState.height);
+ private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
+ StackViewState childState) {
+ float newTranslation = Math.max(ambientState.getTopPadding()
+ + ambientState.getStackTranslation(), childState.yTranslation);
+ childState.height = (int) Math.max(childState.height - (newTranslation
+ - childState.yTranslation), row.getMinHeight());
+ childState.yTranslation = newTranslation;
+ }
+
+ private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
+ StackViewState childState) {
+ float newTranslation;
+ float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getMinHeight();
+ newTranslation = Math.min(childState.yTranslation, bottomPosition);
+ childState.height = (int) Math.max(childState.height
+ - (childState.yTranslation - newTranslation), row.getMinHeight());
+ childState.yTranslation = newTranslation;
}
/**
@@ -569,19 +520,6 @@ public class StackScrollAlgorithm {
}
}
- /**
- * Clamp the yTranslation of the child up such that its end is at lest on the end of the top
- * stack.
- *
- * @param childViewState the view state of the child
- * @param childHeight the height of this child
- */
- private void clampPositionToTopStackEnd(StackViewState childViewState,
- int childHeight) {
- childViewState.yTranslation = Math.max(childViewState.yTranslation,
- mFirstChildMinHeight - childHeight);
- }
-
private int getMaxAllowedChildHeight(View child) {
if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
@@ -611,9 +549,6 @@ public class StackScrollAlgorithm {
}
childViewState.yTranslation = transitioningPositionStart + offset - newHeight
- getPaddingAfterChild(algorithmState, child);
-
- // We want at least to be at the end of the top stack when collapsing
- clampPositionToTopStackEnd(childViewState, newHeight);
childViewState.location = StackViewState.LOCATION_MAIN_AREA;
}
@@ -642,177 +577,79 @@ public class StackScrollAlgorithm {
}
childViewState.height = minHeight;
childViewState.yTranslation = currentYPosition - minHeight;
- clampPositionToTopStackEnd(childViewState, minHeight);
}
- private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
- ExpandableView child, int numberOfElementsCompletelyIn, int i, int childHeight,
- StackViewState childViewState, float scrollOffset) {
-
-
- // First we calculate the index relative to the current stack window of size at most
- // {@link #MAX_ITEMS_IN_TOP_STACK}
- int paddedIndex = i - 1
- - Math.max(numberOfElementsCompletelyIn - MAX_ITEMS_IN_TOP_STACK, 0);
- if (paddedIndex >= 0) {
-
- // We are currently visually entering the top stack
- float distanceToStack = (childHeight + getPaddingAfterChild(algorithmState, child))
- - algorithmState.scrolledPixelsTop;
- if (i == algorithmState.lastTopStackIndex
- && distanceToStack > (mTopStackTotalSize
- + getPaddingAfterChild(algorithmState, child))) {
-
- // Child is currently translating into stack but not yet inside slow down zone.
- // Handle it like the regular scrollview.
- childViewState.yTranslation = scrollOffset;
- } else {
- // Apply stacking logic.
- float numItemsBefore;
- if (i == algorithmState.lastTopStackIndex) {
- numItemsBefore = 1.0f
- - (distanceToStack / (mTopStackTotalSize
- + getPaddingAfterChild(algorithmState, child)));
- } else {
- numItemsBefore = algorithmState.itemsInTopStack - i;
- }
- // The end position of the current child
- float currentChildEndY = mFirstChildMinHeight + mTopStackTotalSize
- - mTopStackIndentationFunctor.getValue(numItemsBefore);
- childViewState.yTranslation = currentChildEndY - childHeight;
- }
- childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING;
- } else {
- if (paddedIndex == -1) {
- childViewState.shadowAlpha = 1.0f - algorithmState.partialInTop;
- } else {
- // We are hidden behind the top card and faded out, so we can hide ourselves.
- childViewState.hidden = true;
- childViewState.shadowAlpha = 0.0f;
- }
- childViewState.yTranslation = mFirstChildMinHeight - childHeight;
- childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN;
- }
-
-
- }
/**
- * Find the number of items in the top stack and update the result state if needed.
+ * Update the height of the first child i.e clamp it to the bottom stack
+ *
*
- * @param resultState The result state to update if a height change of an child occurs
- * @param algorithmState The state in which the current pass of the algorithm is currently in
- */
- private void findNumberOfItemsInTopStackAndUpdateState(StackScrollState resultState,
- StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
- // The y Position if the element would be in a regular scrollView
- float yPositionInScrollView = 0.0f;
- int childCount = algorithmState.visibleChildren.size();
- // find the number of elements in the top stack.
- for (int i = 0; i < childCount; i++) {
- ExpandableView child = algorithmState.visibleChildren.get(i);
- StackViewState childViewState = resultState.getViewStateForView(child);
- int childHeight = getMaxAllowedChildHeight(child);
- int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
- float yPositionInScrollViewAfterElement = yPositionInScrollView
- + childHeight
- + paddingAfterChild;
- if (yPositionInScrollView < algorithmState.scrollY) {
- if (i == 0 && algorithmState.scrollY <= mFirstChildMinHeight) {
-
- // The starting position of the bottom stack peek
- int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
- mCollapseSecondCardPadding;
- // Collapse and expand the first child while the shade is being expanded
- float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
- ? mFirstChildMaxHeight
- : childHeight;
- childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
- mFirstChildMinHeight);
- algorithmState.itemsInTopStack = 1.0f;
-
- } else if (yPositionInScrollViewAfterElement < algorithmState.scrollY) {
- // According to the regular scroll view we are fully off screen
- algorithmState.itemsInTopStack += 1.0f;
- if (i == 0) {
- childViewState.height = child.getMinHeight();
- }
- } else {
- // According to the regular scroll view we are partially off screen
-
- // How much did we scroll into this child
- algorithmState.scrolledPixelsTop = algorithmState.scrollY
- - yPositionInScrollView;
- algorithmState.partialInTop = (algorithmState.scrolledPixelsTop) / (childHeight
- + paddingAfterChild);
-
- // Our element can be expanded, so this can get negative
- algorithmState.partialInTop = Math.max(0.0f, algorithmState.partialInTop);
- algorithmState.itemsInTopStack += algorithmState.partialInTop;
-
- if (i == 0) {
- // If it is expanded we have to collapse it to a new size
- float newSize = yPositionInScrollViewAfterElement
- - paddingAfterChild
- - algorithmState.scrollY + mFirstChildMinHeight;
- newSize = Math.max(mFirstChildMinHeight, newSize);
- algorithmState.itemsInTopStack = 1.0f;
- childViewState.height = (int) newSize;
- }
- algorithmState.lastTopStackIndex = i;
- break;
- }
- } else {
- algorithmState.lastTopStackIndex = i - 1;
- // We are already past the stack so we can end the loop
- break;
- }
- yPositionInScrollView = yPositionInScrollViewAfterElement;
- }
+ * @param child the child to update
+ * @param childViewState the viewstate of the child
+ * @param childHeight the height of the child
+ * @param ambientState The ambient state of the algorithm
+ */
+ private void updateFirstChildHeight(ExpandableView child, StackViewState childViewState,
+ int childHeight, AmbientState ambientState) {
+
+ // The starting position of the bottom stack peek
+ int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
+ mCollapseSecondCardPadding + ambientState.getScrollY();
+ // Collapse and expand the first child while the shade is being expanded
+ float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
+ ? mFirstChildMaxHeight
+ : childHeight;
+ childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+ child.getMinHeight());
}
/**
* Calculate the Z positions for all children based on the number of items in both stacks and
* save it in the resultState
- *
- * @param resultState The result state to update the zTranslation values
+ * @param resultState The result state to update the zTranslation values
* @param algorithmState The state in which the current pass of the algorithm is currently in
+ * @param ambientState The ambient state of the algorithm
*/
private void updateZValuesForState(StackScrollState resultState,
- StackScrollAlgorithmState algorithmState) {
+ StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
int childCount = algorithmState.visibleChildren.size();
- for (int i = 0; i < childCount; i++) {
- View child = algorithmState.visibleChildren.get(i);
+ float childrenOnTop = 0.0f;
+ for (int i = childCount - 1; i >= 0; i--) {
+ ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
- if (i < algorithmState.itemsInTopStack) {
- float stackIndex = algorithmState.itemsInTopStack - i;
-
- // Ensure that the topmost item is a little bit higher than the rest when fully
- // scrolled, to avoid drawing errors when swiping it out
- float max = MAX_ITEMS_IN_TOP_STACK + (i == 0 ? 2.5f : 2);
- stackIndex = Math.min(stackIndex, max);
- if (i == 0 && algorithmState.itemsInTopStack < 2.0f) {
-
- // We only have the top item and an additional item in the top stack,
- // Interpolate the index from 0 to 2 while the second item is
- // translating in.
- stackIndex -= 1.0f;
- if (algorithmState.scrollY > mFirstChildMinHeight) {
-
- // Since there is a shadow treshhold, we cant just interpolate from 0 to
- // 2 but we interpolate from 0.1f to 2.0f when scrolled in. The jump in
- // height will not be noticable since we have padding in between.
- stackIndex = 0.1f + stackIndex * 1.9f;
+ if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
+ // We are in the bottom stack
+ float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);
+ float zSubtraction;
+ if (numItemsAbove <= 1.0f) {
+ float factor = 0.2f;
+ // Lets fade in slower to the threshold to make the shadow fade in look nicer
+ if (numItemsAbove <= factor) {
+ zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
+ * numItemsAbove * (1.0f / factor);
+ } else {
+ zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
+ + (numItemsAbove - factor) * (1.0f / (1.0f - factor))
+ * (mZDistanceBetweenElements
+ - FakeShadowView.SHADOW_SIBLING_TRESHOLD);
}
+ } else {
+ zSubtraction = numItemsAbove * mZDistanceBetweenElements;
+ }
+ childViewState.zTranslation = mZBasicHeight - zSubtraction;
+ } else if (child.mustStayOnScreen()
+ && childViewState.yTranslation < ambientState.getTopPadding()
+ + ambientState.getStackTranslation()) {
+ if (childrenOnTop != 0.0f) {
+ childrenOnTop++;
+ } else {
+ float overlap = ambientState.getTopPadding()
+ + ambientState.getStackTranslation() - childViewState.yTranslation;
+ childrenOnTop += Math.min(1.0f, overlap / childViewState.height);
}
childViewState.zTranslation = mZBasicHeight
- + stackIndex * mZDistanceBetweenElements;
- } else if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
- float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);
- float translationZ = mZBasicHeight
- - numItemsAbove * mZDistanceBetweenElements;
- childViewState.zTranslation = translationZ;
+ + childrenOnTop * mZDistanceBetweenElements;
} else {
childViewState.zTranslation = mZBasicHeight;
}
@@ -897,7 +734,6 @@ public class StackScrollAlgorithm {
}
public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
- mFirstChild = hostView.getFirstChildNotGone();
if (mIsExpansionChanging) {
hostView.post(new Runnable() {
@Override
@@ -922,26 +758,6 @@ public class StackScrollAlgorithm {
public int scrollY;
/**
- * The quantity of items which are in the top stack.
- */
- public float itemsInTopStack;
-
- /**
- * how far in is the element currently transitioning into the top stack
- */
- public float partialInTop;
-
- /**
- * The number of pixels the last child in the top stack has scrolled in to the stack
- */
- public float scrolledPixelsTop;
-
- /**
- * The last item index which is in the top stack.
- */
- public int lastTopStackIndex;
-
- /**
* The quantity of items which are in the bottom stack.
*/
public float itemsInBottomStack;
@@ -957,9 +773,10 @@ public class StackScrollAlgorithm {
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
/**
- * The children from the host that need an increased padding after them.
+ * 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.
*/
- public final HashSet<ExpandableView> increasedPaddingSet = new HashSet<>();
+ public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
index 05fa27d04e4e..fa151950c1cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -24,12 +24,11 @@ public class StackViewState extends ViewState {
// These are flags such that we can create masks for filtering.
public static final int LOCATION_UNKNOWN = 0x00;
- public static final int LOCATION_FIRST_CARD = 0x01;
- public static final int LOCATION_TOP_STACK_HIDDEN = 0x02;
- public static final int LOCATION_TOP_STACK_PEEKING = 0x04;
- public static final int LOCATION_MAIN_AREA = 0x08;
- public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
- public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+ public static final int LOCATION_FIRST_HUN = 0x01;
+ public static final int LOCATION_HIDDEN_TOP = 0x02;
+ public static final int LOCATION_MAIN_AREA = 0x04;
+ public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08;
+ public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10;
/** The view isn't layouted at all. */
public static final int LOCATION_GONE = 0x40;
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 784f610e40a1..0ed6ef899d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.tv;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.os.IBinder;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
@@ -68,7 +69,8 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void setSystemUiVisibility(int vis, int mask) {
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
}
@Override
@@ -114,6 +116,11 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
+ protected boolean toggleSplitScreenMode() {
+ return false;
+ }
+
+ @Override
public void maybeEscalateHeadsUp() {
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
new file mode 100644
index 000000000000..8881c7939337
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v7.preference.DropDownPreference;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+
+import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
+
+public class BatteryPreference extends DropDownPreference implements TunerService.Tunable {
+
+ private static final String PERCENT = "percent";
+ private static final String DEFAULT = "default";
+ private static final String DISABLED = "disabled";
+
+ private final String mBattery;
+ private boolean mBatteryEnabled;
+ private boolean mHasPercentage;
+ private ArraySet<String> mBlacklist;
+ private boolean mHasSetValue;
+
+ public BatteryPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mBattery = context.getString(com.android.internal.R.string.status_bar_battery);
+ setEntryValues(new CharSequence[] {PERCENT, DEFAULT, DISABLED });
+ }
+
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ mHasPercentage = Settings.System.getInt(getContext().getContentResolver(),
+ SHOW_PERCENT_SETTING, 0) != 0;
+ }
+
+ @Override
+ public void onDetached() {
+ TunerService.get(getContext()).removeTunable(this);
+ super.onDetached();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ mBlacklist = StatusBarIconController.getIconBlacklist(newValue);
+ mBatteryEnabled = !mBlacklist.contains(mBattery);
+ }
+ if (!mHasSetValue) {
+ // Because of the complicated tri-state it can end up looping and setting state back to
+ // what the user didn't choose. To avoid this, just set the state once and rely on the
+ // preference to handle updates.
+ mHasSetValue = true;
+ if (mBatteryEnabled && mHasPercentage) {
+ setValue(PERCENT);
+ } else if (mBatteryEnabled) {
+ setValue(DEFAULT);
+ } else {
+ setValue(DISABLED);
+ }
+ }
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ final boolean v = PERCENT.equals(value);
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
+ Settings.System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
+ if (DISABLED.equals(value)) {
+ mBlacklist.add(mBattery);
+ } else {
+ mBlacklist.remove(mBattery);
+ }
+ TunerService.get(getContext()).setValue(StatusBarIconController.ICON_BLACKLIST,
+ TextUtils.join(",", mBlacklist));
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java
new file mode 100644
index 000000000000..ff7be1367388
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java
@@ -0,0 +1,25 @@
+/*
+ * 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.content.Context;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+
+public class CalibratePreference extends DialogPreference {
+ public CalibratePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
new file mode 100644
index 000000000000..ea92443b7265
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
@@ -0,0 +1,90 @@
+/*
+ * 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.content.Context;
+import android.support.v7.preference.DropDownPreference;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.Clock;
+
+public class ClockPreference extends DropDownPreference implements TunerService.Tunable {
+
+ private static final String SECONDS = "seconds";
+ private static final String DEFAULT = "default";
+ private static final String DISABLED = "disabled";
+
+ private final String mClock;
+ private boolean mClockEnabled;
+ private boolean mHasSeconds;
+ private ArraySet<String> mBlacklist;
+ private boolean mHasSetValue;
+
+ public ClockPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mClock = context.getString(com.android.internal.R.string.status_bar_clock);
+ setEntryValues(new CharSequence[] { SECONDS, DEFAULT, DISABLED });
+ }
+
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST,
+ Clock.CLOCK_SECONDS);
+ }
+
+ @Override
+ public void onDetached() {
+ TunerService.get(getContext()).removeTunable(this);
+ super.onDetached();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ mBlacklist = StatusBarIconController.getIconBlacklist(newValue);
+ mClockEnabled = !mBlacklist.contains(mClock);
+ } else if (Clock.CLOCK_SECONDS.equals(key)) {
+ mHasSeconds = newValue != null && Integer.parseInt(newValue) != 0;
+ }
+ if (!mHasSetValue) {
+ // Because of the complicated tri-state it can end up looping and setting state back to
+ // what the user didn't choose. To avoid this, just set the state once and rely on the
+ // preference to handle updates.
+ mHasSetValue = true;
+ if (mClockEnabled && mHasSeconds) {
+ setValue(SECONDS);
+ } else if (mClockEnabled) {
+ setValue(DEFAULT);
+ } else {
+ setValue(DISABLED);
+ }
+ }
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ TunerService.get(getContext()).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,
+ TextUtils.join(",", mBlacklist));
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
new file mode 100644
index 000000000000..af95cf9354bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
@@ -0,0 +1,219 @@
+/*
+ * 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.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.SeekBar;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NightModeController;
+
+public class ColorAndAppearanceFragment extends PreferenceFragment {
+
+ private static final String KEY_CALIBRATE = "calibrate";
+
+ private static final long RESET_DELAY = 10000;
+ private static final CharSequence KEY_NIGHT_MODE = "night_mode";
+
+ private NightModeController mNightModeController;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNightModeController = new NightModeController(getContext());
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.color_and_appearance);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_COLOR_AND_APPEARANCE, true);
+ // TODO: Figure out better title model for Tuner, to avoid any more of this.
+ getActivity().setTitle(R.string.color_and_appearance);
+
+ Preference nightMode = findPreference(KEY_NIGHT_MODE);
+ nightMode.setSummary(mNightModeController.isEnabled()
+ ? R.string.night_mode_on : R.string.night_mode_off);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_COLOR_AND_APPEARANCE, false);
+ }
+
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+ if (preference instanceof CalibratePreference) {
+ CalibrateDialog.show(this);
+ } else {
+ super.onDisplayPreferenceDialog(preference);
+ }
+ }
+
+ private void startRevertTimer() {
+ getView().postDelayed(mResetColorMatrix, RESET_DELAY);
+ }
+
+ private void onApply() {
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_CALIBRATE_DISPLAY_CHANGED);
+ mNightModeController.setCustomValues(Settings.Secure.getString(
+ getContext().getContentResolver(), Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX));
+ getView().removeCallbacks(mResetColorMatrix);
+ }
+
+ private void onRevert() {
+ getView().removeCallbacks(mResetColorMatrix);
+ mResetColorMatrix.run();
+ }
+
+ private final Runnable mResetColorMatrix = new Runnable() {
+ @Override
+ public void run() {
+ ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ }
+ };
+
+ public static class CalibrateDialog extends DialogFragment implements
+ DialogInterface.OnClickListener {
+ private float[] mValues;
+ private NightModeController mNightModeController;
+
+ public static void show(ColorAndAppearanceFragment fragment) {
+ CalibrateDialog dialog = new CalibrateDialog();
+ dialog.setTargetFragment(fragment, 0);
+ dialog.show(fragment.getFragmentManager(), "Calibrate");
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNightModeController = new NightModeController(getContext());
+ String customValues = mNightModeController.getCustomValues();
+ if (customValues == null) {
+ // Generate this as a string because its the easiest way to generate a copy of the
+ // identity.
+ customValues = NightModeController.toString(NightModeController.IDENTITY_MATRIX);
+ }
+ mValues = NightModeController.toValues(customValues);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ View v = LayoutInflater.from(getContext()).inflate(R.layout.calibrate_sliders, null);
+ bindView(v.findViewById(R.id.r_group), 0);
+ bindView(v.findViewById(R.id.g_group), 5);
+ bindView(v.findViewById(R.id.b_group), 10);
+ MetricsLogger.visible(getContext(), MetricsEvent.TUNER_CALIBRATE_DISPLAY);
+ return new AlertDialog.Builder(getContext())
+ .setTitle(R.string.calibrate_display)
+ .setView(v)
+ .setPositiveButton(R.string.color_apply, this)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ MetricsLogger.hidden(getContext(), MetricsEvent.TUNER_CALIBRATE_DISPLAY);
+ }
+
+ private void bindView(View view, final int index) {
+ SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+ seekBar.setMax(1000);
+ seekBar.setProgress((int) (1000 * mValues[index]));
+ seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mValues[index] = progress / 1000f;
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (mValues[0] == 1 && mValues[5] == 1 && mValues[10] == 1) {
+ // Allow removal of matrix by all values set to highest.
+ mNightModeController.setCustomValues(null);
+ return;
+ }
+ ((ColorAndAppearanceFragment) getTargetFragment()).startRevertTimer();
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ NightModeController.toString(mValues));
+ RevertWarning.show((ColorAndAppearanceFragment) getTargetFragment());
+ }
+ }
+
+ public static class RevertWarning extends DialogFragment
+ implements DialogInterface.OnClickListener {
+
+ public static void show(ColorAndAppearanceFragment fragment) {
+ RevertWarning warning = new RevertWarning();
+ warning.setTargetFragment(fragment, 0);
+ warning.show(fragment.getFragmentManager(), "RevertWarning");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog alertDialog = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.color_revert_title)
+ .setMessage(R.string.color_revert_message)
+ .setPositiveButton(R.string.ok, this)
+ .create();
+ alertDialog.setCanceledOnTouchOutside(true);
+ return alertDialog;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ ((ColorAndAppearanceFragment) getTargetFragment()).onRevert();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((ColorAndAppearanceFragment) getTargetFragment()).onApply();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
deleted file mode 100644
index dfacd033a90e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
+++ /dev/null
@@ -1,341 +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.tuner;
-
-import android.annotation.Nullable;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.support.v14.preference.PreferenceFragment;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.DropDownPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SeekBar;
-import android.widget.Switch;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.policy.DisplayController;
-
-import java.util.Objects;
-
-public class ColorMatrixFragment extends PreferenceFragment implements TunerService.Tunable {
-
- private static final String TAG = "ColorMatrixFragment";
-
- private static final long RESET_DELAY = 10000;
-
- private boolean mCustomEnabled;
- private DropDownPreference mSelectPreference;
- private String mCurrentValue;
- private String mCustomValues;
- private SwitchPreference mEnableCustomPreference;
- private MatrixPreference mCustomPreference;
- private int mState;
- private Switch mSwitch;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
- TunerService.get(context).addTunable(this, DisplayController.COLOR_MATRIX_CUSTOM_ENABLED,
- DisplayController.COLOR_MATRIX_CUSTOM_VALUES, DisplayController.COLOR_STATE,
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View view = LayoutInflater.from(getContext()).inflate(
- R.layout.color_matrix_settings, container, false);
- ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
- return view;
- }
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- final Context context = getPreferenceManager().getContext();
- setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
-
- mSelectPreference = new DropDownPreference(context);
- mSelectPreference.setTitle(R.string.color_transform);
- mSelectPreference.setSummary("%s");
- mSelectPreference.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (Objects.equals(newValue, DisplayController.AUTO_STRING)) {
- Settings.Secure.putInt(context.getContentResolver(),
- DisplayController.COLOR_STATE,
- DisplayController.COLOR_STATE_AUTO);
- return true;
- }
- if (Objects.equals(newValue, DisplayController.NONE_STRING)) {
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
- return true;
- }
- Settings.Secure.putInt(context.getContentResolver(),
- DisplayController.COLOR_STATE,
- DisplayController.COLOR_STATE_ENABLED);
- final String value = (String) newValue;
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- value);
- return true;
- }
- });
- getPreferenceScreen().addPreference(mSelectPreference);
-
- mEnableCustomPreference = new SwitchPreference(context);
- mEnableCustomPreference.setTitle(R.string.color_enable_custom);
- mEnableCustomPreference.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- boolean enabled = (Boolean) newValue;
- if (!enabled && Objects.equals(mCurrentValue, mCustomValues)) {
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
- }
- Settings.Secure.putInt(context.getContentResolver(),
- DisplayController.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
- return true;
- }
- });
- getPreferenceScreen().addPreference(mEnableCustomPreference);
-
- mCustomPreference = new MatrixPreference(context);
- getPreferenceScreen().addPreference(mCustomPreference);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- View switchBar = view.findViewById(R.id.switch_bar);
- mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
- mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
- switchBar.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int newState = mState != DisplayController.COLOR_STATE_DISABLED
- ? DisplayController.COLOR_STATE_DISABLED
- : DisplayController.COLOR_STATE_ENABLED;
- ContentResolver contentResolver = getContext().getContentResolver();
- if (newState == DisplayController.COLOR_STATE_DISABLED) {
- String tiles = Settings.Secure.getString(contentResolver,
- QSTileHost.TILES_SETTING);
- if (tiles != null) {
- if (tiles.contains(",colors")) {
- tiles = tiles.replace(",colors", "");
- } else if (tiles.contains("colors,")) {
- tiles = tiles.replace("colors,", "");
- }
- Settings.Secure.putString(contentResolver, QSTileHost.TILES_SETTING,
- tiles);
- }
- }
- Settings.Secure.putInt(contentResolver,
- DisplayController.COLOR_STATE, newState);
- }
- });
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- TunerService.get(getContext()).removeTunable(this);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (DisplayController.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
- mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
- mEnableCustomPreference.setChecked(mCustomEnabled);
- mCustomPreference.setEnabled(mCustomEnabled
- && mState != DisplayController.COLOR_STATE_DISABLED);
- updateSelectOptions();
- } else if (DisplayController.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
- mCustomValues = newValue;
- if (mCustomValues == null) {
- mCustomValues = DisplayController.toString(DisplayController.IDENTITY_MATRIX);
- }
- mCustomPreference.setValues(mCustomValues);
- updateSelectOptions();
- } else if (DisplayController.COLOR_STATE.equals(key)) {
- mState = newValue != null ? Integer.parseInt(newValue) : 0;
- if (mSwitch != null) {
- mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
- }
- mSelectPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
- mEnableCustomPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
- mCustomPreference.setEnabled(mCustomEnabled
- && mState != DisplayController.COLOR_STATE_DISABLED);
- } else {
- mCurrentValue = newValue;
- updateSelectOptions();
- }
- }
-
- private void updateSelectOptions() {
- final int N = DisplayController.CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
- String[] values = new String[N];
- CharSequence[] names = new CharSequence[N];
- CharSequence[] totalNames = DisplayController.getColorTitles(getContext());
- String[] entries = DisplayController.getColorTransforms(getContext());
- entries[DisplayController.CUSTOM_INDEX] = mCustomValues != null ? mCustomValues : "";
- for (int i = 0; i < N; i++) {
- values[i] = entries[i];
- names[i] = totalNames[i];
- }
- mSelectPreference.setEntries(names);
- mSelectPreference.setEntryValues(values);
- int index = 0;
- if (mState == DisplayController.COLOR_STATE_AUTO) {
- index = DisplayController.AUTO_INDEX;
- } else if (mCustomValues != null && Objects.equals(mCurrentValue, mCustomValues)) {
- index = DisplayController.CUSTOM_INDEX;
- } else if (Objects.equals(mCurrentValue, entries[1])) {
- index = 1;
- }
- mSelectPreference.setValueIndex(index);
- mSelectPreference.setSummary("%s");
- return;
- }
-
- private void startRevertTimer() {
- getView().postDelayed(mResetColorMatrix, RESET_DELAY);
- }
-
- private void onApply() {
- Settings.Secure.putString(getContext().getContentResolver(),
- DisplayController.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
- getView().removeCallbacks(mResetColorMatrix);
- }
-
- private void onRevert() {
- getView().removeCallbacks(mResetColorMatrix);
- mResetColorMatrix.run();
- }
-
- private final Runnable mResetColorMatrix = new Runnable() {
- @Override
- public void run() {
- ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
- }
- };
-
- private class MatrixPreference extends Preference implements View.OnClickListener {
- private float[] mValues;
-
- public MatrixPreference(Context context) {
- super(context);
- setLayoutResource(R.layout.preference_matrix);
- }
-
- public void setValues(String customValues) {
- String[] strValues = customValues.split(",");
- mValues = new float[strValues.length];
- for (int i = 0; i < mValues.length; i++) {
- mValues[i] = Float.parseFloat(strValues[i]);
- }
- notifyChanged();
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
- bindView(holder.findViewById(R.id.r_group), 0);
- bindView(holder.findViewById(R.id.g_group), 5);
- bindView(holder.findViewById(R.id.b_group), 10);
- holder.findViewById(R.id.apply).setOnClickListener(this);
- }
-
- private void bindView(View view, final int index) {
- SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
- seekBar.setMax(1000);
- seekBar.setProgress((int) (1000 * mValues[index]));
- seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- mValues[index] = progress / 1000f;
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- }
-
- @Override
- public void onClick(View v) {
- startRevertTimer();
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- DisplayController.toString(mValues));
- RevertWarning.show(ColorMatrixFragment.this);
- }
-
- }
-
- public static class RevertWarning extends DialogFragment
- implements DialogInterface.OnClickListener {
-
- public static void show(ColorMatrixFragment fragment) {
- RevertWarning warning = new RevertWarning();
- warning.setTargetFragment(fragment, 0);
- warning.show(fragment.getFragmentManager(), "RevertWarning");
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog alertDialog = new AlertDialog.Builder(getContext())
- .setTitle(R.string.color_revert_title)
- .setMessage(R.string.color_revert_message)
- .setPositiveButton(R.string.ok, this)
- .create();
- alertDialog.setCanceledOnTouchOutside(true);
- return alertDialog;
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
- ((ColorMatrixFragment) getTargetFragment()).onRevert();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- ((ColorMatrixFragment) getTargetFragment()).onApply();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
deleted file mode 100644
index d8cf2e2bcbdc..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
+++ /dev/null
@@ -1,107 +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.tuner;
-
-import android.app.ActivityManager;
-import android.provider.Settings;
-
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.DisplayController;
-
-import java.util.Objects;
-
-
-public class ColorMatrixTile extends QSTile<QSTile.State> implements DisplayController.Listener {
-
- public static final String COLOR_MATRIX_SPEC = "colors";
-
- private final DisplayController mDisplayController;
-
- private int mIndex;
- private String mCurrentValue;
-
- private boolean mCustomEnabled;
- private String[] mValues;
- private CharSequence[] mValueTitles;
-
- public ColorMatrixTile(Host host) {
- super(host);
- mDisplayController = host.getDisplayController();
- }
-
- @Override
- public void setListening(boolean listening) {
- if (listening) {
- mValues = DisplayController.getColorTransforms(mContext);
- mValueTitles = DisplayController.getColorTitles(mContext);
- mDisplayController.addListener(this);
- } else {
- mDisplayController.removeListener(this);
- }
- }
-
- @Override
- public State newTileState() {
- return new State();
- }
-
- @Override
- protected void handleClick() {
- mIndex++;
- if (mIndex == DisplayController.AUTO_INDEX) {
- mDisplayController.setAuto(true);
- } else {
- mDisplayController.setAuto(false);
- if (!mDisplayController.isCustomEnabled()
- && (mIndex == DisplayController.CUSTOM_INDEX)) {
- mIndex++;
- }
- if (mIndex == mValues.length - 1) {
- mIndex = 0;
- }
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
- ActivityManager.getCurrentUser());
- }
- refreshState();
- }
-
- @Override
- protected void handleUpdateState(State state, Object arg) {
- if (mDisplayController.isAuto()) {
- mIndex = DisplayController.AUTO_INDEX;
- } else if (mDisplayController.isCustomSet()) {
- mIndex = DisplayController.CUSTOM_INDEX;
- } else {
- mIndex = Objects.equals(mDisplayController.getCurrentMatrix(), mValues[1]) ? 1 : 0;
- }
- state.icon = ResourceIcon.get(R.drawable.ic_colorize);
- state.label = mValueTitles[mIndex];
- state.contentDescription = mValueTitles[mIndex];
- }
-
- @Override
- public void onCurrentMatrixChanged() {
- refreshState();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_COLOR_MATRIX;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 5ded8856d39d..ad424590f663 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -117,13 +117,9 @@ public class NavBarTuner extends Fragment implements TunerService.Tunable {
if (isRotated) {
mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
final View rot90 = mPreview.findViewById(R.id.rot90);
- rot90.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
- rot90.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
} else {
mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
final View rot0 = mPreview.findViewById(R.id.rot0);
- rot0.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
- rot0.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
new file mode 100644
index 000000000000..8c945f9f7a13
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -0,0 +1,203 @@
+/**
+ * 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.annotation.Nullable;
+import android.app.UiModeManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.provider.Settings.Secure;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Switch;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NightModeController;
+import com.android.systemui.statusbar.policy.NightModeController.Listener;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+public class NightModeFragment extends PreferenceFragment implements Tunable,
+ Listener, OnPreferenceChangeListener {
+
+ private static final String TAG = "NightModeFragment";
+
+ public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
+
+ private static final CharSequence KEY_AUTO = "auto";
+ private static final CharSequence KEY_DARK_THEME = "dark_theme";
+ private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
+ private static final CharSequence KEY_ADJUST_BRIGHTNESS = "adjust_brightness";
+
+ private Switch mSwitch;
+
+ private NightModeController mNightModeController;
+ private SwitchPreference mAutoSwitch;
+ private SwitchPreference mDarkTheme;
+ private SwitchPreference mAdjustTint;
+ private SwitchPreference mAdjustBrightness;
+ private UiModeManager mUiModeManager;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNightModeController = new NightModeController(getContext());
+ mUiModeManager = getContext().getSystemService(UiModeManager.class);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = LayoutInflater.from(getContext()).inflate(
+ R.layout.night_mode_settings, container, false);
+ ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
+ return view;
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ final Context context = getPreferenceManager().getContext();
+
+ addPreferencesFromResource(R.xml.night_mode);
+ mAutoSwitch = (SwitchPreference) findPreference(KEY_AUTO);
+ mAutoSwitch.setOnPreferenceChangeListener(this);
+ mDarkTheme = (SwitchPreference) findPreference(KEY_DARK_THEME);
+ mDarkTheme.setOnPreferenceChangeListener(this);
+ mAdjustTint = (SwitchPreference) findPreference(KEY_ADJUST_TINT);
+ mAdjustTint.setOnPreferenceChangeListener(this);
+ mAdjustBrightness = (SwitchPreference) findPreference(KEY_ADJUST_BRIGHTNESS);
+ mAdjustBrightness.setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ View switchBar = view.findViewById(R.id.switch_bar);
+ mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
+ mSwitch.setChecked(mNightModeController.isEnabled());
+ switchBar.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean newState = !mNightModeController.isEnabled();
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE, newState);
+ mNightModeController.setNightMode(newState);
+ mSwitch.setChecked(newState);
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_NIGHT_MODE, true);
+ mNightModeController.addListener(this);
+ TunerService.get(getContext()).addTunable(this, Secure.BRIGHTNESS_USE_TWILIGHT,
+ NightModeController.NIGHT_MODE_ADJUST_TINT);
+ mDarkTheme.setChecked(mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO);
+ calculateDisabled();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_NIGHT_MODE, false);
+ mNightModeController.removeListener(this);
+ TunerService.get(getContext()).removeTunable(this);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final Boolean value = (Boolean) newValue;
+ if (mAutoSwitch == preference) {
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE_AUTO, value);
+ mNightModeController.setAuto(value);
+ } else if (mDarkTheme == preference) {
+ MetricsLogger.action(getContext(),
+ MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_DARK_THEME, value);
+ mUiModeManager.setNightMode(value ? UiModeManager.MODE_NIGHT_AUTO
+ : UiModeManager.MODE_NIGHT_NO);
+ postCalculateDisabled();
+ } else if (mAdjustTint == preference) {
+ MetricsLogger.action(getContext(),
+ MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_TINT, value);
+ mNightModeController.setAdjustTint(value);
+ postCalculateDisabled();
+ } else if (mAdjustBrightness == preference) {
+ MetricsLogger.action(getContext(),
+ MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_BRIGHTNESS, value);
+ TunerService.get(getContext()).setValue(Secure.BRIGHTNESS_USE_TWILIGHT,
+ value ? 1 : 0);
+ postCalculateDisabled();
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ private void postCalculateDisabled() {
+ // Post this because its the easiest way to wait for all state to be calculated.
+ getView().post(new Runnable() {
+ @Override
+ public void run() {
+ calculateDisabled();
+ }
+ });
+ }
+
+ private void calculateDisabled() {
+ int enabledCount = (mDarkTheme.isChecked() ? 1 : 0)
+ + (mAdjustTint.isChecked() ? 1 : 0)
+ + (mAdjustBrightness.isChecked() ? 1 : 0);
+ if (enabledCount == 1) {
+ if (mDarkTheme.isChecked()) {
+ mDarkTheme.setEnabled(false);
+ } else if (mAdjustTint.isChecked()) {
+ mAdjustTint.setEnabled(false);
+ } else {
+ mAdjustBrightness.setEnabled(false);
+ }
+ } else {
+ mDarkTheme.setEnabled(true);
+ mAdjustTint.setEnabled(true);
+ mAdjustBrightness.setEnabled(true);
+ }
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (Secure.BRIGHTNESS_USE_TWILIGHT.equals(key)) {
+ mAdjustBrightness.setChecked(newValue != null && Integer.parseInt(newValue) != 0);
+ } else if (NightModeController.NIGHT_MODE_ADJUST_TINT.equals(key)) {
+ // Default on.
+ mAdjustTint.setChecked(newValue == null || Integer.parseInt(newValue) != 0);
+ }
+ }
+
+ @Override
+ public void onNightModeChanged() {
+ mSwitch.setChecked(mNightModeController.isEnabled());
+ }
+
+ @Override
+ public void onTwilightAutoChanged() {
+ mAutoSwitch.setChecked(mNightModeController.isAuto());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
new file mode 100644
index 000000000000..61135bd968f9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
@@ -0,0 +1,99 @@
+/**
+ * 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.ActivityManager;
+import android.content.Intent;
+import android.provider.Settings;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.NightModeController;
+
+import java.util.Objects;
+
+
+public class NightModeTile extends QSTile<QSTile.State> implements NightModeController.Listener {
+
+ public static final String NIGHT_MODE_SPEC = "night";
+
+ private final NightModeController mNightModeController;
+
+ private int mIndex;
+ private String mCurrentValue;
+
+ private boolean mCustomEnabled;
+ private String[] mValues;
+ private CharSequence[] mValueTitles;
+
+ public NightModeTile(Host host) {
+ super(host);
+ mNightModeController = host.getNightModeController();
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mNightModeController.addListener(this);
+ refreshState();
+ } else {
+ mNightModeController.removeListener(this);
+ }
+ }
+
+ @Override
+ public State newTileState() {
+ return new State();
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(mContext, TunerActivity.class)
+ .putExtra(NightModeFragment.EXTRA_SHOW_NIGHT_MODE, true);
+ }
+
+ @Override
+ protected void handleClick() {
+ mNightModeController.setNightMode(!mNightModeController.isEnabled());
+ refreshState();
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ // TODO: Right now this is just a dropper, needs an actual night icon.
+ boolean enabled = mNightModeController.isEnabled();
+ state.icon = ResourceIcon.get(enabled ? R.drawable.ic_night_mode
+ : R.drawable.ic_night_mode_disabled);
+ state.label = mContext.getString(R.string.night_mode);
+ state.contentDescription = mContext.getString(R.string.night_mode);
+ }
+
+ @Override
+ public void onNightModeChanged() {
+ refreshState();
+ }
+
+ @Override
+ public void onTwilightAutoChanged() {
+ // Don't care.
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.QS_COLOR_MATRIX;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 4225b48fbf45..748ee97c0621 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -36,12 +36,22 @@ public class TunerActivity extends SettingsDrawerActivity implements
super.onCreate(savedInstanceState);
if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
- getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment(),
+ boolean showNightMode = getIntent().getBooleanExtra(
+ NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false);
+ getFragmentManager().beginTransaction().replace(R.id.content_frame,
+ showNightMode ? new NightModeFragment() : new TunerFragment(),
TAG_TUNER).commit();
}
}
@Override
+ public void onBackPressed() {
+ if (!getFragmentManager().popBackStackImmediate()) {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
try {
Class<?> cls = Class.forName(pref.getFragment());
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 9df53682c5ad..70f2fdcfa8d3 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -37,8 +37,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
-import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
-
public class TunerFragment extends PreferenceFragment {
private static final String TAG = "TunerFragment";
@@ -51,10 +49,6 @@ public class TunerFragment extends PreferenceFragment {
private static final int MENU_REMOVE = Menu.FIRST + 1;
- private final SettingObserver mSettingObserver = new SettingObserver();
-
- private SwitchPreference mBatteryPct;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -72,7 +66,6 @@ public class TunerFragment extends PreferenceFragment {
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.tuner_prefs);
- mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT);
if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
0) == 0) {
if (getFragmentManager().findFragmentByTag(WARNING_TAG) == null) {
@@ -85,9 +78,6 @@ public class TunerFragment extends PreferenceFragment {
public void onResume() {
super.onResume();
getActivity().setTitle(R.string.system_ui_tuner);
- updateBatteryPct();
- getContext().getContentResolver().registerContentObserver(
- System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, true);
}
@@ -95,7 +85,6 @@ public class TunerFragment extends PreferenceFragment {
@Override
public void onPause() {
super.onPause();
- getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, false);
}
@@ -123,35 +112,6 @@ public class TunerFragment extends PreferenceFragment {
return super.onOptionsItemSelected(item);
}
- private void updateBatteryPct() {
- mBatteryPct.setOnPreferenceChangeListener(null);
- mBatteryPct.setChecked(System.getInt(getContext().getContentResolver(),
- SHOW_PERCENT_SETTING, 0) != 0);
- mBatteryPct.setOnPreferenceChangeListener(mBatteryPctChange);
- }
-
- private final class SettingObserver extends ContentObserver {
- public SettingObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- super.onChange(selfChange, uri, userId);
- updateBatteryPct();
- }
- }
-
- private final OnPreferenceChangeListener mBatteryPctChange = new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean v = (Boolean) newValue;
- MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
- System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
- return true;
- }
- };
-
public static class TunerWarningFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 7ad752ec74ce..5b9ebd7722c6 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -6,24 +6,27 @@ import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.tuner.TunerService.Tunable;
public class TunerSwitch extends SwitchPreference implements Tunable {
private final boolean mDefault;
+ private final int mAction;
public TunerSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TunerSwitch);
mDefault = a.getBoolean(R.styleable.TunerSwitch_defValue, false);
+ mAction = a.getInt(R.styleable.TunerSwitch_metricsAction, -1);
}
@Override
public void onAttached() {
super.onAttached();
- TunerService.get(getContext()).addTunable(this, getKey());
+ TunerService.get(getContext()).addTunable(this, getKey().split(","));
}
@Override
@@ -38,8 +41,18 @@ public class TunerSwitch extends SwitchPreference implements Tunable {
}
@Override
+ protected void onClick() {
+ super.onClick();
+ if (mAction != -1) {
+ MetricsLogger.action(getContext(), mAction, isChecked());
+ }
+ }
+
+ @Override
protected boolean persistBoolean(boolean value) {
- Settings.Secure.putString(getContext().getContentResolver(), getKey(), value ? "1" : "0");
+ for (String key : getKey().split(",")) {
+ Settings.Secure.putString(getContext().getContentResolver(), key, value ? "1" : "0");
+ }
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
new file mode 100644
index 000000000000..cc0ffb0e2653
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
@@ -0,0 +1,141 @@
+/*
+ * 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.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Checkable;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+import com.android.systemui.volume.ZenModePanel.Callback;
+
+public class TunerZenModePanel extends LinearLayout implements OnClickListener {
+ private static final String TAG = "TunerZenModePanel";
+
+ private Callback mCallback;
+ private ZenModePanel mZenModePanel;
+ private View mHeaderSwitch;
+ private int mZenMode;
+ private ZenModeController mController;
+ private View mButtons;
+ private View mMoreSettings;
+ private View mDone;
+ private OnClickListener mDoneListener;
+ private boolean mEditing;
+
+ public TunerZenModePanel(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void init(ZenModeController zenModeController) {
+ mController = zenModeController;
+ mHeaderSwitch = findViewById(R.id.tuner_zen_switch);
+ mHeaderSwitch.setVisibility(View.VISIBLE);
+ mHeaderSwitch.setOnClickListener(this);
+ mHeaderSwitch.findViewById(com.android.internal.R.id.up).setVisibility(View.GONE);
+ ((TextView) mHeaderSwitch.findViewById(android.R.id.title)).setText(
+ R.string.quick_settings_dnd_label);
+ mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
+ mZenModePanel.init(zenModeController);
+ mButtons = findViewById(R.id.tuner_zen_buttons);
+ mMoreSettings = mButtons.findViewById(android.R.id.button2);
+ mMoreSettings.setOnClickListener(this);
+ ((TextView) mMoreSettings).setText(R.string.quick_settings_more_settings);
+ mDone = mButtons.findViewById(android.R.id.button1);
+ mDone.setOnClickListener(this);
+ ((TextView) mDone).setText(R.string.quick_settings_done);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mEditing = false;
+ }
+
+ public void setCallback(Callback zenPanelCallback) {
+ mCallback = zenPanelCallback;
+ mZenModePanel.setCallback(zenPanelCallback);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mHeaderSwitch) {
+ mEditing = true;
+ if (mZenMode == Global.ZEN_MODE_OFF) {
+ mZenMode = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
+ Global.ZEN_MODE_ALARMS);
+ mController.setZen(mZenMode, null, TAG);
+ postUpdatePanel();
+ } else {
+ mZenMode = Global.ZEN_MODE_OFF;
+ mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
+ postUpdatePanel();
+ }
+ } else if (v == mMoreSettings) {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ } else if (v == mDone) {
+ mEditing = false;
+ setVisibility(View.GONE);
+ mDoneListener.onClick(v);
+ }
+ }
+
+ public boolean isEditing() {
+ return mEditing;
+ }
+
+ public void setZenState(int zenMode) {
+ mZenMode = zenMode;
+ postUpdatePanel();
+ }
+
+ private void postUpdatePanel() {
+ // The complicated structure from reusing the same ZenPanel has resulted in some
+ // unstableness/flickering from callbacks coming in quickly. To solve this just
+ // post the UI updates a little bit.
+ removeCallbacks(mUpdate);
+ postDelayed(mUpdate, 40);
+ }
+
+ public void setDoneListener(OnClickListener onClickListener) {
+ mDoneListener = onClickListener;
+ }
+
+ private void updatePanel() {
+ boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
+ ((Checkable) mHeaderSwitch.findViewById(android.R.id.toggle)).setChecked(zenOn);
+ mZenModePanel.setVisibility(zenOn ? View.VISIBLE : View.GONE);
+ mButtons.setVisibility(zenOn ? View.VISIBLE : View.GONE);
+ }
+
+ private final Runnable mUpdate = new Runnable() {
+ @Override
+ public void run() {
+ updatePanel();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 3e47d8571fad..123165e3ba3c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -23,11 +23,15 @@ import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.ITaskStackListener;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -53,24 +57,39 @@ public class PipManager {
private static final int MAX_RUNNING_TASKS_COUNT = 10;
- private static final int STATE_NO_PIP = 0;
- private static final int STATE_PIP_OVERLAY = 1;
- private static final int STATE_PIP_MENU = 2;
+ public static final int STATE_NO_PIP = 0;
+ public static final int STATE_PIP_OVERLAY = 1;
+ public static final int STATE_PIP_MENU = 2;
private static final int TASK_ID_NO_PIP = -1;
private static final int INVALID_RESOURCE_TYPE = -1;
+ public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
+ public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH = 0x2;
+ private int mSuspendPipResizingReason;
+
+ private static final float SCALE_FACTOR = 1.1f;
+
private Context mContext;
private IActivityManager mActivityManager;
+ private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
- private Rect mPipBound;
- private Rect mMenuModePipBound;
+ private Rect mCurrentPipBounds;
+ private Rect mPipBounds;
+ private Rect mMenuModePipBounds;
+ private Rect mRecentsPipBounds;
+ private Rect mRecentsFocusedPipBounds;
private boolean mInitialized;
private int mPipTaskId = TASK_ID_NO_PIP;
+ private ComponentName mPipComponentName;
+ private MediaController mPipMediaController;
private boolean mOnboardingShown;
+ private boolean mIsRecentsShown;
+ private boolean mIsPipFocusedInRecent;
+
private final Runnable mOnActivityPinnedRunnable = new Runnable() {
@Override
public void run() {
@@ -78,7 +97,7 @@ public class PipManager {
try {
stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
if (stackInfo == null) {
- Log.w(TAG, "There is no pinned stack");
+ Log.w(TAG, "Cannot find pinned stack");
return;
}
} catch (RemoteException e) {
@@ -87,15 +106,41 @@ public class PipManager {
}
if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
- showPipOverlay(false);
+ mPipComponentName = ComponentName.unflattenFromString(
+ stackInfo.taskNames[stackInfo.taskNames.length - 1]);
+ // Set state to overlay so we show it when the pinned stack animation ends.
+ mState = STATE_PIP_OVERLAY;
+ mCurrentPipBounds = mPipBounds;
launchPipOnboardingActivityIfNeeded();
+ mMediaSessionManager.addOnActiveSessionsChangedListener(
+ mActiveMediaSessionListener, null);
+ updateMediaController(mMediaSessionManager.getActiveSessions(null));
}
};
private final Runnable mOnTaskStackChanged = new Runnable() {
@Override
public void run() {
if (mState != STATE_NO_PIP) {
- // TODO: check whether PIP task is closed.
+ StackInfo stackInfo = null;
+ try {
+ stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo == null) {
+ Log.w(TAG, "There is no pinned stack");
+ closePipInternal(false);
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getStackInfo failed", e);
+ return;
+ }
+ for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
+ if (stackInfo.taskIds[i] == mPipTaskId) {
+ // PIP task is still alive.
+ return;
+ }
+ }
+ // PIP task doesn't exist anymore in PINNED_STACK.
+ closePipInternal(true);
}
}
};
@@ -105,6 +150,26 @@ public class PipManager {
movePipToFullscreen();
}
};
+ private final Runnable mOnPinnedStackAnimationEnded = new Runnable() {
+ @Override
+ public void run() {
+ switch (mState) {
+ case STATE_PIP_OVERLAY:
+ showPipOverlay();
+ break;
+ case STATE_PIP_MENU:
+ showPipMenu();
+ break;
+ }
+ }
+ };
+
+ private final Runnable mResizePinnedStackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ resizePinnedStack(mState);
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -122,6 +187,13 @@ public class PipManager {
}
};
+ private final MediaSessionManager.OnActiveSessionsChangedListener mActiveMediaSessionListener =
+ new MediaSessionManager.OnActiveSessionsChangedListener() {
+ @Override
+ public void onActiveSessionsChanged(List<MediaController> controllers) {
+ updateMediaController(controllers);
+ }
+ };
private PipManager() { }
@@ -135,10 +207,18 @@ public class PipManager {
mInitialized = true;
mContext = context;
Resources res = context.getResources();
- mPipBound = Rect.unflattenFromString(res.getString(
+ mPipBounds = Rect.unflattenFromString(res.getString(
com.android.internal.R.string.config_defaultPictureInPictureBounds));
- mMenuModePipBound = Rect.unflattenFromString(res.getString(
+ mMenuModePipBounds = Rect.unflattenFromString(res.getString(
com.android.internal.R.string.config_centeredPictureInPictureBounds));
+ mRecentsPipBounds = Rect.unflattenFromString(res.getString(
+ com.android.internal.R.string.config_pictureInPictureBoundsInRecents));
+ float scaleBy = (SCALE_FACTOR - 1.0f) / 2;
+ mRecentsFocusedPipBounds = new Rect(
+ (int) (mRecentsPipBounds.left - scaleBy * mRecentsPipBounds.width()),
+ (int) (mRecentsPipBounds.top - scaleBy * mRecentsPipBounds.height()),
+ (int) (mRecentsPipBounds.right + scaleBy * mRecentsPipBounds.width()),
+ (int) (mRecentsPipBounds.bottom + scaleBy * mRecentsPipBounds.height()));
mActivityManager = ActivityManagerNative.getDefault();
TaskStackListener taskStackListener = new TaskStackListener();
@@ -153,6 +233,9 @@ public class PipManager {
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
mOnboardingShown = Prefs.getBoolean(
mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
+
+ mMediaSessionManager =
+ (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
}
/**
@@ -161,16 +244,16 @@ public class PipManager {
*/
public void requestTvPictureInPicture() {
if (DEBUG) Log.d(TAG, "requestTvPictureInPicture()");
- if (!hasPipTasks()) {
+ if (!isPipShown()) {
startPip();
} else if (mState == STATE_PIP_OVERLAY) {
- showPipMenu();
+ resizePinnedStack(STATE_PIP_MENU);
}
}
private void startPip() {
try {
- mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBound);
+ mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBounds);
} catch (RemoteException|IllegalArgumentException e) {
Log.e(TAG, "moveTopActivityToPinnedStack failed", e);
}
@@ -180,25 +263,24 @@ public class PipManager {
* Closes PIP (PIPed activity and PIP system UI).
*/
public void closePip() {
+ closePipInternal(true);
+ }
+
+ private void closePipInternal(boolean removePipStack) {
mState = STATE_NO_PIP;
mPipTaskId = TASK_ID_NO_PIP;
- StackInfo stackInfo = null;
- try {
- stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
- if (stackInfo == null) {
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getStackInfo failed", e);
- return;
- }
- for (int taskId : stackInfo.taskIds) {
+ mPipMediaController = null;
+ mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener);
+ if (removePipStack) {
try {
- mActivityManager.removeTask(taskId);
+ mActivityManager.removeStack(PINNED_STACK_ID);
} catch (RemoteException e) {
- Log.e(TAG, "removeTask failed", e);
+ Log.e(TAG, "removeStack failed", e);
}
}
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ mListeners.get(i).onPipActivityClosed();
+ }
}
/**
@@ -210,11 +292,7 @@ public class PipManager {
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onMoveToFullscreen();
}
- try {
- mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true);
- } catch (RemoteException e) {
- Log.e(TAG, "moveTasksToFullscreenStack failed", e);
- }
+ resizePinnedStack(mState);
}
/**
@@ -222,25 +300,146 @@ public class PipManager {
* stack to the default PIP bound {@link com.android.internal.R.string
* .config_defaultPictureInPictureBounds}.
*/
- public void showPipOverlay(boolean resizeStack) {
+ private void showPipOverlay() {
if (DEBUG) Log.d(TAG, "showPipOverlay()");
mState = STATE_PIP_OVERLAY;
Intent intent = new Intent(mContext, PipOverlayActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchStackId(PINNED_STACK_ID);
- if (resizeStack) {
- options.setLaunchBounds(mPipBound);
- }
mContext.startActivity(intent, options.toBundle());
}
/**
+ * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
+ * @param reason The reason for suspending resizing operations on the Pip.
+ */
+ public void suspendPipResizing(int reason) {
+ if (DEBUG) Log.d(TAG,
+ "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ mSuspendPipResizingReason |= reason;
+ }
+
+ /**
+ * Resumes resizing operation on the Pip that was previously suspended.
+ * @param reason The reason resizing operations on the Pip was suspended.
+ */
+ public void resumePipResizing(int reason) {
+ if ((mSuspendPipResizingReason & reason) == 0) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG,
+ "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ mSuspendPipResizingReason &= ~reason;
+ mHandler.post(mResizePinnedStackRunnable);
+ }
+
+ /**
+ * Resize the Pip to the appropriate size for the input state.
+ * @param state In Pip state also used to determine the new size for the Pip.
+ */
+ public void resizePinnedStack(int state) {
+ if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+ mState = state;
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ mListeners.get(i).onPipResizeAboutToStart();
+ }
+ if (mSuspendPipResizingReason != 0) {
+ if (DEBUG) Log.d(TAG,
+ "resizePinnedStack() deferring mSuspendPipResizingReason=" +
+ mSuspendPipResizingReason);
+ return;
+ }
+ switch (mState) {
+ case STATE_NO_PIP:
+ mCurrentPipBounds = null;
+ break;
+ case STATE_PIP_MENU:
+ mCurrentPipBounds = mMenuModePipBounds;
+ break;
+ case STATE_PIP_OVERLAY:
+ if (mIsRecentsShown) {
+ if (mIsPipFocusedInRecent) {
+ mCurrentPipBounds = mRecentsFocusedPipBounds;
+ } else {
+ mCurrentPipBounds = mRecentsPipBounds;
+ }
+ } else {
+ mCurrentPipBounds = mPipBounds;
+ }
+ break;
+ default:
+ mCurrentPipBounds = mPipBounds;
+ break;
+ }
+ try {
+ mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds, true, true, true);
+ } catch (RemoteException e) {
+ Log.e(TAG, "showPipMenu failed", e);
+ }
+ }
+
+ /**
+ * Returns the current PIP bound for activities to sync their UI with PIP.
+ */
+ public Rect getPipBounds() {
+ return mCurrentPipBounds;
+ }
+
+ /**
+ * Called when Recents is started.
+ * PIPed activity will be resized accordingly and overlay will show available buttons.
+ */
+ public void onRecentsStarted() {
+ mIsRecentsShown = true;
+ mIsPipFocusedInRecent = false;
+ if (mState == STATE_NO_PIP) {
+ return;
+ }
+ resizePinnedStack(STATE_PIP_OVERLAY);
+ }
+
+ /**
+ * Called when Recents is stopped.
+ * PIPed activity will be resized accordingly and overlay will hide available buttons.
+ */
+ public void onRecentsStopped() {
+ mIsRecentsShown = false;
+ mIsPipFocusedInRecent = false;
+ if (mState == STATE_NO_PIP) {
+ return;
+ }
+ resizePinnedStack(STATE_PIP_OVERLAY);
+ }
+
+ /**
+ * Returns {@code true} if recents is shown.
+ */
+ boolean isRecentsShown() {
+ return mIsRecentsShown;
+ }
+
+ /**
+ * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+ * is focused.
+ * This only resizes pinned stack so it looks like it's in Recents.
+ * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+ */
+ public void onPipViewFocusChangedInRecents(boolean hasFocus) {
+ mIsPipFocusedInRecent = hasFocus;
+ if (mState != STATE_PIP_OVERLAY) {
+ Log.w(TAG, "There is no pinned stack to handle focus change.");
+ return;
+ }
+ resizePinnedStack(STATE_PIP_OVERLAY);
+ }
+
+ /**
* Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
* stack to the centered PIP bound {@link com.android.internal.R.string
* .config_centeredPictureInPictureBounds}.
*/
- public void showPipMenu() {
+ private void showPipMenu() {
if (DEBUG) Log.d(TAG, "showPipMenu()");
mState = STATE_PIP_MENU;
for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -248,22 +447,13 @@ public class PipManager {
}
Intent intent = new Intent(mContext, PipMenuActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(PINNED_STACK_ID);
- options.setLaunchBounds(mMenuModePipBound);
- mContext.startActivity(intent, options.toBundle());
+ mContext.startActivity(intent);
}
- /**
- * Adds {@link Listener}.
- */
public void addListener(Listener listener) {
mListeners.add(listener);
}
- /**
- * Removes {@link Listener}.
- */
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
@@ -279,6 +469,13 @@ public class PipManager {
}
}
+ /**
+ * Returns {@code true} if PIP is shown.
+ */
+ public boolean isPipShown() {
+ return hasPipTasks();
+ }
+
private boolean hasPipTasks() {
try {
StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
@@ -328,6 +525,34 @@ public class PipManager {
}
}
+ private void updateMediaController(List<MediaController> controllers) {
+ MediaController mediaController = null;
+ if (controllers != null && mState != STATE_NO_PIP && mPipComponentName != null) {
+ for (int i = controllers.size() - 1; i >= 0; i--) {
+ MediaController controller = controllers.get(i);
+ // We assumes that an app with PIPable activity
+ // keeps the single instance of media controller especially when PIP is on.
+ if (controller.getPackageName().equals(mPipComponentName.getPackageName())) {
+ mediaController = controller;
+ break;
+ }
+ }
+ }
+ if (mPipMediaController != mediaController) {
+ mPipMediaController = mediaController;
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onMediaControllerChanged();
+ }
+ }
+ }
+
+ /**
+ * Gets the {@link android.media.session.MediaController} for the PIPed activity.
+ */
+ MediaController getMediaController() {
+ return mPipMediaController;
+ }
+
private class TaskStackListener extends ITaskStackListener.Stub {
@Override
public void onTaskStackChanged() throws RemoteException {
@@ -338,32 +563,38 @@ public class PipManager {
@Override
public void onActivityPinned() throws RemoteException {
// Post the message back to the UI thread.
+ if (DEBUG) Log.d(TAG, "onActivityPinned()");
mHandler.post(mOnActivityPinnedRunnable);
}
@Override
public void onPinnedActivityRestartAttempt() {
// Post the message back to the UI thread.
+ if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
mHandler.post(mOnPinnedActivityRestartAttempt);
}
+
+ @Override
+ public void onPinnedStackAnimationEnded() {
+ if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
+ mHandler.post(mOnPinnedStackAnimationEnded);
+ }
}
/**
* A listener interface to receive notification on changes in PIP.
*/
public interface Listener {
- /**
- * Invoked when a PIPed activity is closed.
- */
+ /** Invoked when a PIPed activity is closed. */
void onPipActivityClosed();
- /**
- * Invoked when the PIP menu gets shown.
- */
+ /** Invoked when the PIP menu gets shown. */
void onShowPipMenu();
- /**
- * Invoked when the PIPed activity is returned back to the fullscreen.
- */
+ /** Invoked when the PIPed activity is returned back to the fullscreen. */
void onMoveToFullscreen();
+ /** Invoked when we are above to start resizing the Pip. */
+ void onPipResizeAboutToStart();
+ /** Invoked when the MediaController on PIPed activity is changed. */
+ void onMediaControllerChanged();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 15c55f5b26ff..fb7fa4de088f 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -18,58 +18,176 @@ package com.android.systemui.tv.pip;
import android.app.Activity;
import android.media.session.MediaController;
+import android.media.session.PlaybackState;
import android.os.Bundle;
import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
import com.android.systemui.R;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.media.session.PlaybackState.ACTION_PAUSE;
+import static android.media.session.PlaybackState.ACTION_PLAY;
+
/**
* Activity to show the PIP menu to control PIP.
*/
public class PipMenuActivity extends Activity implements PipManager.Listener {
private static final String TAG = "PipMenuActivity";
- private static final boolean DEBUG = false;
private final PipManager mPipManager = PipManager.getInstance();
private MediaController mMediaController;
+ private View mFullButtonView;
+ private View mFullDescriptionView;
+ private View mPlayPauseView;
+ private ImageView mPlayPauseButtonImageView;
+ private TextView mPlayPauseDescriptionTextView;
+ private View mCloseButtonView;
+ private View mCloseDescriptionView;
+
+ private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ updatePlayPauseView(state);
+ }
+ };
+
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_menu);
mPipManager.addListener(this);
- findViewById(R.id.full).setOnClickListener(new View.OnClickListener() {
+ mFullButtonView = findViewById(R.id.full_button);
+ mFullDescriptionView = findViewById(R.id.full_desc);
+ mFullButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPipManager.movePipToFullscreen();
+ finish();
}
});
- findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() {
+ mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+
+ mPlayPauseView = findViewById(R.id.play_pause);
+ mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
+ mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
+ mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- mPipManager.closePip();
- finish();
+ if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+ return;
+ }
+ long actions = mMediaController.getPlaybackState().getActions();
+ int state = mMediaController.getPlaybackState().getState();
+ if (((actions & ACTION_PLAY) != 0) && !isPlaying(state)) {
+ mMediaController.getTransportControls().play();
+ } else if ((actions & ACTION_PAUSE) != 0 && isPlaying(state)) {
+ mMediaController.getTransportControls().pause();
+ }
+ // View will be updated later in {@link mMediaControllerCallback}
}
});
- findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
+ mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPlayPauseDescriptionTextView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+
+ mCloseButtonView = findViewById(R.id.close_button);
+ mCloseDescriptionView = findViewById(R.id.close_desc);
+ mCloseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- mPipManager.showPipOverlay(true);
+ mPipManager.closePip();
finish();
}
});
+ mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+ updateMediaController();
+ }
+
+ private void updateMediaController() {
+ MediaController newController = mPipManager.getMediaController();
+ if (mMediaController == newController) {
+ return;
+ }
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mMediaController = newController;
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ updatePlayPauseView(mMediaController.getPlaybackState());
+ } else {
+ updatePlayPauseView(null);
+ }
+ }
+
+ private void updatePlayPauseView(PlaybackState playbackState) {
+ if (playbackState != null
+ && (playbackState.getActions() & (ACTION_PLAY | ACTION_PAUSE)) != 0) {
+ mPlayPauseView.setVisibility(View.VISIBLE);
+ if (isPlaying(playbackState.getState())) {
+ mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
+ mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+ } else {
+ mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
+ mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+ }
+ } else {
+ mPlayPauseView.setVisibility(View.GONE);
+ }
+ }
+
+ private boolean isPlaying(int state) {
+ return state == PlaybackState.STATE_BUFFERING
+ || state == PlaybackState.STATE_CONNECTING
+ || state == PlaybackState.STATE_PLAYING
+ || state == PlaybackState.STATE_FAST_FORWARDING
+ || state == PlaybackState.STATE_REWINDING
+ || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS
+ || state == PlaybackState.STATE_SKIPPING_TO_NEXT;
+ }
+
+ private void restorePipAndFinish() {
+ mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+ finish();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ restorePipAndFinish();
}
@Override
protected void onDestroy() {
- mPipManager.removeListener(this);
super.onDestroy();
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mPipManager.removeListener(this);
+ mPipManager.resumePipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
}
@Override
public void onBackPressed() {
- mPipManager.showPipOverlay(true);
- finish();
+ restorePipAndFinish();
}
@Override
@@ -84,4 +202,16 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
public void onMoveToFullscreen() {
finish();
}
+
+ @Override
+ public void onMediaControllerChanged() {
+ updateMediaController();
+ }
+
+ @Override
+ public void onPipResizeAboutToStart() {
+ finish();
+ mPipManager.suspendPipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index a0b913ab9b2c..ad45625b0f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -17,9 +17,11 @@
package com.android.systemui.tv.pip;
import android.app.Activity;
+import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup.LayoutParams;
import com.android.systemui.R;
@@ -33,6 +35,8 @@ public class PipOnboardingActivity extends Activity implements PipManager.Listen
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_onboarding);
+ View pipOnboardingView = findViewById(R.id.pip_onboarding);
+ View pipOutlineView = findViewById(R.id.pip_outline);
mPipManager.addListener(this);
findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
@Override
@@ -40,6 +44,20 @@ public class PipOnboardingActivity extends Activity implements PipManager.Listen
finish();
}
});
+
+ int pipOutlineSpace = getResources().getDimensionPixelSize(R.dimen.tv_pip_bounds_space);
+ int screenWidth = getResources().getDisplayMetrics().widthPixels;
+ Rect pipBounds = mPipManager.getPipBounds();
+ pipOnboardingView.setPadding(
+ pipBounds.left - pipOutlineSpace,
+ pipBounds.top - pipOutlineSpace,
+ screenWidth - pipBounds.right - pipOutlineSpace, 0);
+
+ // Set width and height for outline view to enclose the PIP.
+ LayoutParams lp = pipOutlineView.getLayoutParams();
+ lp.width = pipBounds.width() + pipOutlineSpace * 2;
+ lp.height = pipBounds.height() + pipOutlineSpace * 2;
+ pipOutlineView.setLayoutParams(lp);
}
@Override
@@ -62,4 +80,10 @@ public class PipOnboardingActivity extends Activity implements PipManager.Listen
public void onMoveToFullscreen() {
finish();
}
+
+ @Override
+ public void onPipResizeAboutToStart() { }
+
+ @Override
+ public void onMediaControllerChanged() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index bc59a8cb4995..95d655c2f320 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -30,25 +30,47 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener
private static final String TAG = "PipOverlayActivity";
private static final boolean DEBUG = false;
- private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 2000;
+ private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
private final PipManager mPipManager = PipManager.getInstance();
private final Handler mHandler = new Handler();
+ private View mGuideOverlayView;
+ private View mGuideButtonsView;
+ private final Runnable mHideGuideOverlayRunnable = new Runnable() {
+ public void run() {
+ mGuideOverlayView.setVisibility(View.INVISIBLE);
+ }
+ };
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_overlay);
+ mGuideOverlayView = findViewById(R.id.guide_overlay);
+ mGuideButtonsView = findViewById(R.id.guide_buttons);
mPipManager.addListener(this);
- final View overlayView = findViewById(R.id.guide_overlay);
- // TODO: apply animation
- overlayView.setVisibility(View.VISIBLE);
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- overlayView.setVisibility(View.INVISIBLE);
- }
- }, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // TODO: Implement animation for this
+ if (!mPipManager.isRecentsShown()) {
+ mGuideOverlayView.setVisibility(View.VISIBLE);
+ mGuideButtonsView.setVisibility(View.INVISIBLE);
+ } else {
+ mGuideOverlayView.setVisibility(View.INVISIBLE);
+ mGuideButtonsView.setVisibility(View.VISIBLE);
+ }
+ mHandler.removeCallbacks(mHideGuideOverlayRunnable);
+ mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mHandler.removeCallbacks(mHideGuideOverlayRunnable);
+ finish();
}
@Override
@@ -56,6 +78,8 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
mPipManager.removeListener(this);
+ mPipManager.resumePipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
}
@Override
@@ -72,4 +96,15 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener
public void onMoveToFullscreen() {
finish();
}
+
+ @Override
+ public void onPipResizeAboutToStart() {
+ finish();
+ mPipManager.suspendPipResizing(
+ PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
+ }
+
+ @Override
+ public void onMediaControllerChanged() {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 6aae9bd39a74..1d5ca04243a0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -25,6 +25,7 @@ import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -42,6 +43,7 @@ import android.os.SystemClock;
import android.provider.Settings.Global;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -49,7 +51,6 @@ import android.view.View;
import android.view.View.AccessibilityDelegate;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
-import android.view.View.OnLayoutChangeListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
@@ -67,6 +68,7 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerZenModePanel;
import com.android.systemui.volume.VolumeDialogController.State;
import com.android.systemui.volume.VolumeDialogController.StreamState;
@@ -90,39 +92,40 @@ public class VolumeDialog implements TunerService.Tunable {
public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
- private static final int WAIT_FOR_RIPPLE = 200;
private final Context mContext;
private final H mHandler = new H();
private final VolumeDialogController mController;
- private final CustomDialog mDialog;
- private final ViewGroup mDialogView;
- private final ViewGroup mDialogContentView;
- private final ImageButton mExpandButton;
- private final View mSettingsButton;
- private final List<VolumeRow> mRows = new ArrayList<VolumeRow>();
+ private CustomDialog mDialog;
+ private ViewGroup mDialogView;
+ private ViewGroup mDialogContentView;
+ private ViewGroup mVolumeRowContainer;
+ private ImageButton mExpandButton;
+ private final List<VolumeRow> mRows = new ArrayList<>();
private final SpTexts mSpTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
private final KeyguardManager mKeyguard;
private final AudioManager mAudioManager;
- private final int mExpandButtonAnimationDuration;
- private final ZenFooter mZenFooter;
+ private int mExpandButtonAnimationDuration;
+ private ZenFooter mZenFooter;
private final LayoutTransition mLayoutTransition;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
- private final VolumeDialogMotion mMotion;
+ private VolumeDialogMotion mMotion;
+ private final int mWindowType;
+ private final ZenModeController mZenModeController;
private boolean mShowing;
private boolean mExpanded;
+
private int mActiveStream;
private boolean mShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
- private int mExpandButtonRes;
private boolean mExpandButtonAnimationRunning;
private SafetyWarningDialog mSafetyWarning;
private Callback mCallback;
@@ -130,22 +133,43 @@ public class VolumeDialog implements TunerService.Tunable {
private boolean mPendingRecheckAll;
private long mCollapseTime;
private boolean mHovering = false;
- private int mLastActiveStream;
+ private int mDensity;
private boolean mShowFullZen;
- private final ZenModePanel mZenPanel;
+ private TunerZenModePanel mZenPanel;
public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
ZenModeController zenModeController, Callback callback) {
mContext = context;
mController = controller;
mCallback = callback;
+ mWindowType = windowType;
+ mZenModeController = zenModeController;
mSpTexts = new SpTexts(mContext);
mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
+ mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+ mLayoutTransition = new LayoutTransition();
+ mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+
+ initDialog();
+
+ mAccessibility.init();
+
+ controller.addCallback(mControllerCallbackH, mHandler);
+ controller.getState();
+ TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
+
+ final Configuration currentConfig = mContext.getResources().getConfiguration();
+ mDensity = currentConfig.densityDpi;
+ }
+ private void initDialog() {
mDialog = new CustomDialog(mContext);
+ mHovering = false;
+ mShowing = false;
final Window window = mDialog.getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
@@ -159,7 +183,7 @@ public class VolumeDialog implements TunerService.Tunable {
mDialog.setCanceledOnTouchOutside(true);
final Resources res = mContext.getResources();
final WindowManager.LayoutParams lp = window.getAttributes();
- lp.type = windowType;
+ lp.type = mWindowType;
lp.format = PixelFormat.TRANSLUCENT;
lp.setTitle(VolumeDialog.class.getSimpleName());
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
@@ -169,8 +193,7 @@ public class VolumeDialog implements TunerService.Tunable {
window.setAttributes(lp);
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
- mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
- mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+
mDialog.setContentView(R.layout.volume_dialog);
mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
mDialogView.setOnHoverListener(new View.OnHoverListener() {
@@ -184,57 +207,53 @@ public class VolumeDialog implements TunerService.Tunable {
}
});
mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
+ mVolumeRowContainer =
+ (ViewGroup) mDialogContentView.findViewById(R.id.volume_row_container);
+ mExpanded = false;
mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
mExpandButton.setOnClickListener(mClickExpand);
updateWindowWidthH();
updateExpandButtonH();
- mLayoutTransition = new LayoutTransition();
- mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+
mDialogContentView.setLayoutTransition(mLayoutTransition);
mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
new VolumeDialogMotion.Callback() {
- @Override
- public void onAnimatingChanged(boolean animating) {
- if (animating) return;
- if (mPendingStateChanged) {
- mHandler.sendEmptyMessage(H.STATE_CHANGED);
- mPendingStateChanged = false;
- }
- if (mPendingRecheckAll) {
- mHandler.sendEmptyMessage(H.RECHECK_ALL);
- mPendingRecheckAll = false;
- }
- }
- });
-
- addRow(AudioManager.STREAM_RING,
- R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
- addRow(AudioManager.STREAM_MUSIC,
- R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
- addRow(AudioManager.STREAM_ALARM,
- R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
- addRow(AudioManager.STREAM_VOICE_CALL,
- R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
- addRow(AudioManager.STREAM_BLUETOOTH_SCO,
- R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
- addRow(AudioManager.STREAM_SYSTEM,
- R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
-
- mSettingsButton = mDialog.findViewById(R.id.volume_settings_button);
- mSettingsButton.setOnClickListener(mClickSettings);
+ @Override
+ public void onAnimatingChanged(boolean animating) {
+ if (animating) return;
+ if (mPendingStateChanged) {
+ mHandler.sendEmptyMessage(H.STATE_CHANGED);
+ mPendingStateChanged = false;
+ }
+ if (mPendingRecheckAll) {
+ mHandler.sendEmptyMessage(H.RECHECK_ALL);
+ mPendingRecheckAll = false;
+ }
+ }
+ });
+
+ if (mRows.isEmpty()) {
+ addRow(AudioManager.STREAM_RING,
+ R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
+ addRow(AudioManager.STREAM_MUSIC,
+ R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
+ addRow(AudioManager.STREAM_ALARM,
+ R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
+ addRow(AudioManager.STREAM_VOICE_CALL,
+ R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
+ addRow(AudioManager.STREAM_BLUETOOTH_SCO,
+ R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
+ addRow(AudioManager.STREAM_SYSTEM,
+ R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
+ } else {
+ addExistingRows();
+ }
mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
- mZenFooter.init(zenModeController);
- mZenPanel = (ZenModePanel) mDialog.findViewById(R.id.zen_mode_panel);
- mZenPanel.addNoneButton();
- mZenPanel.init(zenModeController);
+ mZenFooter.init(mZenModeController);
+ mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
+ mZenPanel.init(mZenModeController);
mZenPanel.setCallback(mZenPanelCallback);
-
- mAccessibility.init();
-
- controller.addCallback(mControllerCallbackH, mHandler);
- controller.getState();
- TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
}
@Override
@@ -285,46 +304,38 @@ public class VolumeDialog implements TunerService.Tunable {
}
private void addRow(int stream, int iconRes, int iconMuteRes, boolean important) {
- final VolumeRow row = initRow(stream, iconRes, iconMuteRes, important);
+ VolumeRow row = new VolumeRow();
+ initRow(row, stream, iconRes, iconMuteRes, important);
if (!mRows.isEmpty()) {
- final View v = new View(mContext);
- v.setId(android.R.id.background);
- final int h = mContext.getResources()
- .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
- final LinearLayout.LayoutParams lp =
- new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
- mDialogContentView.addView(v, mDialogContentView.getChildCount() - 2, lp);
- row.space = v;
+ addSpacer(row);
}
- row.settingsButton.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) {
- final boolean moved = mLastActiveStream != mActiveStream ||
- oldLeft != left || oldTop != top;
- if (D.BUG) Log.d(TAG, "onLayoutChange moved=" + moved
- + " old=" + new Rect(oldLeft, oldTop, oldRight, oldBottom).toShortString()
- + "," + mLastActiveStream
- + " new=" + new Rect(left,top,right,bottom).toShortString()
- + "," + mActiveStream);
- mLastActiveStream = mActiveStream;
- if (moved) {
- for (int i = 0; i < mDialogContentView.getChildCount(); i++) {
- final View c = mDialogContentView.getChildAt(i);
- if (!c.isShown()) continue;
- if (c == row.view) {
- repositionExpandAnim(row);
- }
- return;
- }
- }
- }
- });
- // add new row just before the footer
- mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
+ mVolumeRowContainer.addView(row.view);
mRows.add(row);
}
+ private void addExistingRows() {
+ int N = mRows.size();
+ for (int i = 0; i < N; i++) {
+ final VolumeRow row = mRows.get(i);
+ initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important);
+ if (i > 0) {
+ addSpacer(row);
+ }
+ mVolumeRowContainer.addView(row.view);
+ }
+ }
+
+ private void addSpacer(VolumeRow row) {
+ final View v = new View(mContext);
+ v.setId(android.R.id.background);
+ final int h = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
+ final LinearLayout.LayoutParams lp =
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
+ mVolumeRowContainer.addView(v, lp);
+ row.space = v;
+ }
+
private boolean isAttached() {
return mDialogContentView != null && mDialogContentView.isAttachedToWindow();
}
@@ -345,18 +356,6 @@ public class VolumeDialog implements TunerService.Tunable {
return null;
}
- private void repositionExpandAnim(VolumeRow row) {
- final int[] loc = new int[2];
- row.settingsButton.getLocationInWindow(loc);
- final MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
- final int x = loc[0] - mlp.leftMargin;
- final int y = loc[1] - mlp.topMargin;
- if (D.BUG) Log.d(TAG, "repositionExpandAnim x=" + x + " y=" + y);
- mExpandButton.setTranslationX(x);
- mExpandButton.setTranslationY(y);
- mExpandButton.setTag((Integer) y);
- }
-
public void dump(PrintWriter writer) {
writer.println(VolumeDialog.class.getSimpleName() + " state:");
writer.print(" mShowing: "); writer.println(mShowing);
@@ -374,8 +373,8 @@ public class VolumeDialog implements TunerService.Tunable {
}
@SuppressLint("InflateParams")
- private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) {
- final VolumeRow row = new VolumeRow();
+ private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
+ boolean important) {
row.stream = stream;
row.iconRes = iconRes;
row.iconMuteRes = iconMuteRes;
@@ -442,9 +441,6 @@ public class VolumeDialog implements TunerService.Tunable {
row.userAttempt = 0; // reset the grace period, slider should update immediately
}
});
- row.settingsButton = (ImageButton) row.view.findViewById(R.id.volume_settings_button);
- row.settingsButton.setOnClickListener(mClickSettings);
- return row;
}
public void destroy() {
@@ -573,8 +569,6 @@ public class VolumeDialog implements TunerService.Tunable {
if (mExpandButtonAnimationRunning && isAttached()) return;
final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
: R.drawable.ic_volume_expand_animation;
- if (res == mExpandButtonRes) return;
- mExpandButtonRes = res;
if (hasTouchFeature()) {
mExpandButton.setImageResource(res);
} else {
@@ -606,16 +600,6 @@ public class VolumeDialog implements TunerService.Tunable {
final boolean visible = isVisibleH(row, isActive);
Util.setVisOrGone(row.view, visible);
Util.setVisOrGone(row.space, visible && mExpanded);
- final int expandButtonRes = mExpanded ? R.drawable.ic_volume_settings : 0;
- if (expandButtonRes != row.cachedExpandButtonRes) {
- row.cachedExpandButtonRes = expandButtonRes;
- if (expandButtonRes == 0) {
- row.settingsButton.setImageDrawable(null);
- } else {
- row.settingsButton.setImageResource(expandButtonRes);
- }
- }
- Util.setVisOrInvis(row.settingsButton, false);
updateVolumeRowHeaderVisibleH(row);
row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
updateVolumeRowSliderTintH(row, isActive);
@@ -629,8 +613,8 @@ public class VolumeDialog implements TunerService.Tunable {
if (row.ss == null || !row.ss.dynamic) continue;
if (!mDynamic.get(row.stream)) {
mRows.remove(i);
- mDialogContentView.removeView(row.view);
- mDialogContentView.removeView(row.space);
+ mVolumeRowContainer.removeView(row.view);
+ mVolumeRowContainer.removeView(row.space);
}
}
}
@@ -671,7 +655,7 @@ public class VolumeDialog implements TunerService.Tunable {
final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
&& (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
- && !mShowFullZen;
+ && !mZenPanel.isEditing();
if (wasVisible != visible && !visible) {
prepareForCollapse();
}
@@ -679,12 +663,21 @@ public class VolumeDialog implements TunerService.Tunable {
mZenFooter.update();
final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
- final boolean fullVisible = mShowFullZen && (mState.zenMode != Global.ZEN_MODE_OFF
- || mExpanded);
+ final boolean fullVisible = mShowFullZen && !visible;
if (fullWasVisible != fullVisible && !fullVisible) {
prepareForCollapse();
}
Util.setVisOrGone(mZenPanel, fullVisible);
+ if (fullVisible) {
+ mZenPanel.setZenState(mState.zenMode);
+ mZenPanel.setDoneListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ prepareForCollapse();
+ mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
+ }
+ });
+ }
}
private void updateVolumeRowH(VolumeRow row) {
@@ -902,6 +895,12 @@ public class VolumeDialog implements TunerService.Tunable {
@Override
public void onConfigurationChanged() {
+ Configuration newConfig = mContext.getResources().getConfiguration();
+ final int density = newConfig.densityDpi;
+ if (density != mDensity) {
+ mDialog.dismiss();
+ initDialog();
+ }
updateWindowWidthH();
mSpTexts.update();
mZenFooter.onConfigurationChanged();
@@ -954,21 +953,6 @@ public class VolumeDialog implements TunerService.Tunable {
}
};
- private final OnClickListener mClickSettings = new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSettingsButton.postDelayed(new Runnable() {
- @Override
- public void run() {
- Events.writeEvent(mContext, Events.EVENT_SETTINGS_CLICK);
- if (mCallback != null) {
- mCallback.onSettingsClicked();
- }
- }
- }, WAIT_FOR_RIPPLE);
- }
- };
-
private final class H extends Handler {
private static final int SHOW = 1;
private static final int DISMISS = 2;
@@ -978,6 +962,7 @@ public class VolumeDialog implements TunerService.Tunable {
private static final int RESCHEDULE_TIMEOUT = 6;
private static final int STATE_CHANGED = 7;
private static final int UPDATE_BOTTOM_MARGIN = 8;
+ private static final int UPDATE_FOOTER = 9;
public H() {
super(Looper.getMainLooper());
@@ -994,6 +979,7 @@ public class VolumeDialog implements TunerService.Tunable {
case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
case STATE_CHANGED: onStateChangedH(mState); break;
case UPDATE_BOTTOM_MARGIN: updateDialogBottomMarginH(); break;
+ case UPDATE_FOOTER: updateFooterH(); break;
}
}
}
@@ -1144,7 +1130,6 @@ public class VolumeDialog implements TunerService.Tunable {
private TextView header;
private ImageButton icon;
private SeekBar slider;
- private ImageButton settingsButton;
private int stream;
private StreamState ss;
private long userAttempt; // last user-driven slider change
@@ -1157,12 +1142,10 @@ public class VolumeDialog implements TunerService.Tunable {
private ColorStateList cachedSliderTint;
private int iconState; // from Events
private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
- private int cachedExpandButtonRes;
private int lastAudibleLevel = 1;
}
public interface Callback {
- void onSettingsClicked();
void onZenSettingsClicked();
void onZenPrioritySettingsClicked();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index d7635ad9acb1..3d338098fc2d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -168,11 +168,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private final VolumeDialog.Callback mVolumeDialogCallback = new VolumeDialog.Callback() {
@Override
- public void onSettingsClicked() {
- startSettings(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS));
- }
-
- @Override
public void onZenSettingsClicked() {
startSettings(ZenModePanel.ZEN_SETTINGS);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index 04339eb8e802..bbb70ed6bf47 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -43,7 +43,7 @@ public class VolumePrefs {
public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
- public static final boolean DEFAULT_SHOW_HEADERS = true;
+ public static final boolean DEFAULT_SHOW_HEADERS = false;
public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index a03e7f7d5029..c06b63bd8f66 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -139,9 +139,8 @@ public class ZenFooter extends LinearLayout {
}
public void onConfigurationChanged() {
- mEndNowButton.setText(mContext.getString(R.string.volume_zen_end_now));
- mSpTexts.update();
Util.setText(mEndNowButton, mContext.getString(R.string.volume_zen_end_now));
+ mSpTexts.update();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index e9594a3adb3b..6976c0b1d312 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -190,12 +190,6 @@ public class ZenModePanel extends LinearLayout {
mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
}
- public void addNoneButton() {
- mZenButtons.addButton(R.string.interruption_level_all_twoline,
- R.string.interruption_level_all,
- Global.ZEN_MODE_OFF);
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -526,8 +520,8 @@ public class ZenModePanel extends LinearLayout {
setToMidnight(nextAlarm);
if (weekRange.compareTo(nextAlarm) >= 0) {
- return ZenModeConfig.toNextAlarmCondition(mContext, now, nextAlarmMs,
- ActivityManager.getCurrentUser());
+ return ZenModeConfig.toNextAlarmCondition(mContext, now,
+ nextAlarmMs, ActivityManager.getCurrentUser());
}
}
return null;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 964688b509c8..c9c58050f367 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -29,9 +29,7 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay \
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
- $(call all-java-files-under, ../src) \
- $(call all-proto-files-under, ../src) \
- src/com/android/systemui/EventLogTags.logtags
+ $(call all-java-files-under, ../src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
frameworks/support/v7/preference/res \
@@ -53,7 +51,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ SystemUI-proto-tags
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 282560100cb4..5389c8047b26 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -20,6 +20,8 @@
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<application>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags
deleted file mode 120000
index 2f243d70449d..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/com/android/systemui/EventLogTags.logtags \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
new file mode 100644
index 000000000000..1d81fd478b52
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
@@ -0,0 +1,188 @@
+/*
+ * 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.qs;
+
+import android.view.View;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import org.mockito.Mockito;
+
+public class TouchAnimatorTests extends SysuiTestCase {
+
+ private Listener mTouchListener;
+ private View mTestView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mTestView = new View(getContext());
+ mTouchListener = Mockito.mock(Listener.class);
+ }
+
+ public void testSetValueFloat() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 50)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(25f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ public void testSetValueInt() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addInt(mTestView, "top", 0, 50)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0, mTestView.getTop());
+
+ animator.setPosition(.5f);
+ assertEquals(25, mTestView.getTop());
+
+ animator.setPosition(1);
+ assertEquals(50, mTestView.getTop());
+ }
+
+ public void testStartDelay() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 50)
+ .setStartDelay(.5f)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.75f);
+ assertEquals(25f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ public void testEndDelay() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 50)
+ .setEndDelay(.5f)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.25f);
+ assertEquals(25f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(50f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ public void testOnAnimationAtStartCallback() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .setListener(mTouchListener)
+ .build();
+
+ // Called on init.
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(1);
+
+ // Not called from same state.
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(1);
+
+ // Called after starting and moving back to start.
+ animator.setPosition(.5f);
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(2);
+
+ // Called when move from end to end.
+ animator.setPosition(1);
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(3);
+ }
+
+ public void testOnAnimationAtEndCallback() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .setListener(mTouchListener)
+ .build();
+
+ // Called on init.
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(1);
+
+ // Not called from same state.
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(1);
+
+ // Called after starting and moving back to end.
+ animator.setPosition(.5f);
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(2);
+
+ // Called when move from end to end.
+ animator.setPosition(0);
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(3);
+ }
+
+ public void testOnAnimationStartedCallback() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .setListener(mTouchListener)
+ .build();
+
+ // Called on init.
+ animator.setPosition(.5f);
+ verifyOnAnimationStarted(1);
+
+ // Not called from same state.
+ animator.setPosition(.6f);
+ verifyOnAnimationStarted(1);
+
+ // Called after going to end then moving again.
+ animator.setPosition(1);
+ animator.setPosition(.5f);
+ verifyOnAnimationStarted(2);
+
+ // Called after moving to start then moving again.
+ animator.setPosition(0);
+ animator.setPosition(.5f);
+ verifyOnAnimationStarted(3);
+ }
+
+ // TODO: Add test for interpolator.
+
+ private void verifyOnAnimationAtStart(int times) {
+ Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtStart();
+ }
+
+ private void verifyOnAnimationAtEnd(int times) {
+ Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtEnd();
+ }
+
+ private void verifyOnAnimationStarted(int times) {
+ Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationStarted();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
index c4ca039fab0c..18412519af50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -19,6 +19,9 @@ import android.content.ComponentName;
import android.os.Looper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.NetworkController;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -34,7 +37,12 @@ public class TileServicesTests extends SysuiTestCase {
protected void setUp() throws Exception {
super.setUp();
mManagers = new ArrayList<>();
- QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
+ final NetworkController networkController = Mockito.mock(NetworkController.class);
+ Mockito.when(networkController.getDataSaverController()).thenReturn(
+ Mockito.mock(DataSaverController.class));
+ QSTileHost host = new QSTileHost(mContext, null, null, null, null,
+ networkController, null,
+ Mockito.mock(HotspotController.class), null,
null, null, null, null, null, null, null);
mTileService = new TestTileServices(host, Looper.myLooper());
}
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 5cf37670f3ea..ebd538473c1d 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
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
@@ -31,14 +28,12 @@ import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
-
import com.android.internal.telephony.cdma.EriInfo;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
-
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -47,6 +42,9 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
public class NetworkControllerBaseTest extends SysuiTestCase {
private static final String TAG = "NetworkControllerBaseTest";
protected static final int DEFAULT_LEVEL = 2;
@@ -109,6 +107,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected void setupNetworkController() {
// For now just pretend to be the data sim, so we can test that too.
mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ when(mMockTm.getDataEnabled(mSubId)).thenReturn(true);
setDefaultSubId(mSubId);
setSubscriptions(mSubId);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
diff --git a/preloaded-classes b/preloaded-classes
index 2301c4119d38..be645d24c7fb 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,4 +1,3 @@
-# Classes which are preloaded by com.android.internal.os.ZygoteInit.
[B
[C
[D
@@ -10,6 +9,7 @@
[Landroid.animation.Keyframe$FloatKeyframe;
[Landroid.animation.Keyframe$IntKeyframe;
[Landroid.animation.Keyframe$ObjectKeyframe;
+[Landroid.animation.Keyframe;
[Landroid.animation.PropertyValuesHolder;
[Landroid.app.LoaderManagerImpl;
[Landroid.content.ContentProviderResult;
@@ -26,12 +26,16 @@
[Landroid.content.pm.ProviderInfo;
[Landroid.content.pm.ServiceInfo;
[Landroid.content.pm.Signature;
+[Landroid.content.res.Configuration;
[Landroid.content.res.StringBlock;
[Landroid.content.res.XmlBlock;
+[Landroid.database.Cursor;
[Landroid.database.CursorWindow;
[Landroid.database.sqlite.SQLiteConnection$Operation;
[Landroid.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus;
+[Landroid.graphics.Bitmap$CompressFormat;
[Landroid.graphics.Bitmap$Config;
+[Landroid.graphics.Bitmap;
[Landroid.graphics.Canvas$EdgeType;
[Landroid.graphics.FontFamily;
[Landroid.graphics.Interpolator$Result;
@@ -50,10 +54,12 @@
[Landroid.graphics.drawable.GradientDrawable$Orientation;
[Landroid.graphics.drawable.LayerDrawable$ChildDrawable;
[Landroid.graphics.drawable.RippleForeground;
+[Landroid.hardware.display.WifiDisplay;
[Landroid.hardware.soundtrigger.SoundTrigger$ConfidenceLevel;
[Landroid.hardware.soundtrigger.SoundTrigger$Keyphrase;
[Landroid.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionExtra;
[Landroid.icu.impl.ICUResourceBundle$OpenType;
+[Landroid.icu.impl.StandardPlural;
[Landroid.icu.impl.Trie2$ValueWidth;
[Landroid.icu.impl.UCharacterProperty$BinaryProperty;
[Landroid.icu.impl.UCharacterProperty$IntProperty;
@@ -67,17 +73,17 @@
[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.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.media.AudioDeviceInfo;
[Landroid.media.AudioGain;
-[Landroid.media.AudioPatch;
-[Landroid.media.AudioPort;
-[Landroid.media.AudioPortConfig;
-[Landroid.media.MediaTimeProvider$OnMediaTimeListener;
+[Landroid.net.Network;
[Landroid.net.NetworkInfo$DetailedState;
[Landroid.net.NetworkInfo$State;
[Landroid.net.Uri;
@@ -85,6 +91,7 @@
[Landroid.os.AsyncTask$Status;
[Landroid.os.MessageQueue$IdleHandler;
[Landroid.os.Parcel;
+[Landroid.os.ParcelFileDescriptor;
[Landroid.os.Parcelable;
[Landroid.os.PatternMatcher;
[Landroid.os.storage.StorageVolume;
@@ -102,6 +109,7 @@
[Landroid.text.method.TextKeyListener;
[Landroid.text.style.AlignmentSpan;
[Landroid.text.style.CharacterStyle;
+[Landroid.text.style.ClickableSpan;
[Landroid.text.style.LeadingMarginSpan;
[Landroid.text.style.LineBackgroundSpan;
[Landroid.text.style.LineHeightSpan;
@@ -114,9 +122,13 @@
[Landroid.text.style.URLSpan;
[Landroid.text.style.WrapTogetherSpan;
[Landroid.util.LongSparseArray;
-[Landroid.util.PathParser$PathDataNode;
+[Landroid.util.Pair;
+[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;
[Landroid.widget.Editor$TextRenderNode;
@@ -130,17 +142,19 @@
[Lcom.android.internal.telephony.PhoneConstants$State;
[Lcom.android.okhttp.CipherSuite;
[Lcom.android.okhttp.ConnectionSpec;
+[Lcom.android.okhttp.HttpUrl$Builder$ParseResult;
[Lcom.android.okhttp.Protocol;
[Lcom.android.okhttp.TlsVersion;
[Lcom.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
-[Lcom.android.org.bouncycastle.asn1.x500.RDN;
-[Lcom.android.org.bouncycastle.asn1.x509.GeneralName;
[Lcom.android.org.conscrypt.OpenSSLX509CertPath$Encoding;
[Lcom.android.org.conscrypt.OpenSSLX509Certificate;
[Ldalvik.system.DexPathList$Element;
+[Ljava.beans.PropertyChangeListener;
+[Ljava.io.File$PathStatus;
[Ljava.io.File;
[Ljava.io.FileDescriptor;
[Ljava.io.IOException;
+[Ljava.io.ObjectInputStream$HandleTable$HandleList;
[Ljava.io.ObjectStreamField;
[Ljava.lang.Byte;
[Ljava.lang.CharSequence;
@@ -159,9 +173,11 @@
[Ljava.lang.Thread$State;
[Ljava.lang.Thread;
[Ljava.lang.ThreadGroup;
+[Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;
[Ljava.lang.Throwable;
[Ljava.lang.Void;
[Ljava.lang.annotation.Annotation;
+[Ljava.lang.ref.WeakReference;
[Ljava.lang.reflect.AccessibleObject;
[Ljava.lang.reflect.Constructor;
[Ljava.lang.reflect.Field;
@@ -173,18 +189,24 @@
[Ljava.math.RoundingMode;
[Ljava.net.InetAddress;
[Ljava.net.Proxy$Type;
+[Ljava.nio.ByteBuffer;
+[Ljava.security.CryptoPrimitive;
+[Ljava.security.Principal;
[Ljava.security.Provider;
[Ljava.security.cert.Certificate;
[Ljava.security.cert.X509Certificate;
-[Ljava.text.Format$Field;
+[Ljava.text.DateFormat$Field;
+[Ljava.text.Normalizer$Form;
[Ljava.util.ArrayList;
+[Ljava.util.Enumeration;
+[Ljava.util.Formatter$Flags;
+[Ljava.util.Formatter$FormatString;
[Ljava.util.HashMap$HashMapEntry;
[Ljava.util.Hashtable$HashtableEntry;
+[Ljava.util.Locale$Category;
[Ljava.util.Locale;
[Ljava.util.Map$Entry;
[Ljava.util.TimerTask;
-[Ljava.util.TreeMap$Bound;
-[Ljava.util.TreeMap$Relation;
[Ljava.util.WeakHashMap$Entry;
[Ljava.util.concurrent.ConcurrentHashMap$Node;
[Ljava.util.concurrent.ConcurrentHashMap$Segment;
@@ -192,32 +214,40 @@
[Ljava.util.concurrent.TimeUnit;
[Ljava.util.logging.Handler;
[Ljava.util.regex.Pattern;
+[Ljavax.crypto.Cipher$InitType;
[Ljavax.crypto.Cipher$NeedToSet;
+[Ljavax.microedition.khronos.egl.EGLConfig;
[Ljavax.net.ssl.KeyManager;
+[Ljavax.net.ssl.SSLSession;
[Ljavax.net.ssl.TrustManager;
+[Ljavax.security.auth.x500.X500Principal;
[Ljavax.security.cert.X509Certificate;
+[Llibcore.io.ClassPathURLStreamHandler;
[Llibcore.reflect.AnnotationMember$DefaultValues;
[Llibcore.reflect.AnnotationMember;
-[Lorg.apache.harmony.security.asn1.ASN1Type;
-[Lorg.apache.harmony.security.utils.ObjectIdentifier;
[Lorg.apache.http.Header;
-[Lorg.apache.http.HeaderElement;
-[Lorg.apache.http.NameValuePair;
-[Lorg.apache.http.conn.routing.RouteInfo$LayerType;
-[Lorg.apache.http.conn.routing.RouteInfo$TunnelType;
[Lorg.json.JSONStringer$Scope;
[Lorg.kxml2.io.KXmlParser$ValueContext;
+[Lsun.misc.FormattedFloatingDecimal$Form;
+[Lsun.security.jca.ProviderConfig;
+[Lsun.security.jca.ServiceId;
+[Lsun.security.pkcs.SignerInfo;
+[Lsun.security.util.DerOutputStream;
+[Lsun.security.util.DerValue;
+[Lsun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint$Operator;
+[Lsun.security.util.ObjectIdentifier;
+[Lsun.security.x509.AVA;
+[Lsun.security.x509.RDN;
+[Lsun.util.logging.PlatformLogger$Level;
[S
[Z
[[B
-[[C
[[I
-[[Lcom.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+[[Ljava.lang.Byte;
[[Ljava.lang.Class;
[[Ljava.lang.Object;
[[Ljava.lang.String;
[[Ljava.lang.annotation.Annotation;
-[[Lorg.apache.harmony.security.utils.ObjectIdentifier;
[[S
[[[I
android.R$styleable
@@ -240,17 +270,22 @@ 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
android.animation.Animator
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$Builder
-android.animation.AnimatorSet$Dependency
-android.animation.AnimatorSet$DependencyListener
android.animation.AnimatorSet$Node
android.animation.ArgbEvaluator
android.animation.FloatEvaluator
@@ -272,10 +307,12 @@ 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
@@ -284,31 +321,34 @@ android.animation.StateListAnimator$Tuple
android.animation.TimeInterpolator
android.animation.TypeEvaluator
android.animation.ValueAnimator
-android.animation.ValueAnimator$AnimationHandler
-android.animation.ValueAnimator$AnimationHandler$1
-android.animation.ValueAnimator$AnimationHandler$2
android.animation.ValueAnimator$AnimatorUpdateListener
android.app.ActionBar
android.app.ActionBar$LayoutParams
android.app.Activity
android.app.Activity$HostCallbacks
android.app.ActivityManager
+android.app.ActivityManager$MemoryInfo
+android.app.ActivityManager$RecentTaskInfo
android.app.ActivityManager$RunningAppProcessInfo
android.app.ActivityManager$RunningAppProcessInfo$1
+android.app.ActivityManager$StackId
android.app.ActivityManager$TaskDescription
android.app.ActivityManager$TaskDescription$1
android.app.ActivityManagerNative
android.app.ActivityManagerNative$1
android.app.ActivityManagerProxy
+android.app.ActivityOptions
android.app.ActivityThread
android.app.ActivityThread$1
android.app.ActivityThread$2
android.app.ActivityThread$3
android.app.ActivityThread$ActivityClientRecord
+android.app.ActivityThread$ActivityConfigChangeData
android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
+android.app.ActivityThread$CreateBackupAgentData
android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$DropBoxReporter
android.app.ActivityThread$EventLoggingReporter
@@ -343,6 +383,7 @@ android.app.ContextImpl$ApplicationContentResolver
android.app.Dialog
android.app.Dialog$1
android.app.Dialog$ListenersHandler
+android.app.DialogFragment
android.app.DownloadManager
android.app.Fragment
android.app.Fragment$1
@@ -361,6 +402,8 @@ android.app.IAlarmManager
android.app.IAlarmManager$Stub
android.app.IAlarmManager$Stub$Proxy
android.app.IApplicationThread
+android.app.IBackupAgent
+android.app.IBackupAgent$Stub
android.app.IInstrumentationWatcher
android.app.IInstrumentationWatcher$Stub
android.app.INotificationManager
@@ -368,6 +411,8 @@ android.app.INotificationManager$Stub
android.app.INotificationManager$Stub$Proxy
android.app.IServiceConnection
android.app.IServiceConnection$Stub
+android.app.ITransientNotification
+android.app.ITransientNotification$Stub
android.app.IUiAutomationConnection
android.app.IUiAutomationConnection$Stub
android.app.Instrumentation
@@ -391,10 +436,11 @@ 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
@@ -481,11 +527,14 @@ android.app.SystemServiceRegistry$65
android.app.SystemServiceRegistry$66
android.app.SystemServiceRegistry$67
android.app.SystemServiceRegistry$68
+android.app.SystemServiceRegistry$69
android.app.SystemServiceRegistry$7
+android.app.SystemServiceRegistry$70
android.app.SystemServiceRegistry$8
android.app.SystemServiceRegistry$9
android.app.SystemServiceRegistry$CachedServiceFetcher
android.app.SystemServiceRegistry$ServiceFetcher
+android.app.SystemServiceRegistry$StaticOuterContextServiceFetcher
android.app.SystemServiceRegistry$StaticServiceFetcher
android.app.UiModeManager
android.app.WallpaperManager
@@ -493,12 +542,15 @@ android.app.admin.DevicePolicyManager
android.app.admin.IDevicePolicyManager
android.app.admin.IDevicePolicyManager$Stub
android.app.admin.IDevicePolicyManager$Stub$Proxy
+android.app.backup.BackupAgent
+android.app.backup.BackupAgent$BackupServiceBinder
+android.app.backup.BackupAgent$SharedPrefsSynchronizer
+android.app.backup.BackupAgentHelper
android.app.backup.BackupDataInput
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
@@ -514,12 +566,14 @@ android.app.usage.NetworkStatsManager
android.app.usage.UsageStatsManager
android.appwidget.AppWidgetManager
android.appwidget.AppWidgetProvider
+android.auditing.SecurityLog
+android.auditing.SecurityLog$SecurityEvent
+android.auditing.SecurityLog$SecurityEvent$1
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
@@ -531,8 +585,9 @@ android.content.AbstractThreadedSyncAdapter$SyncThread
android.content.ActivityNotFoundException
android.content.BroadcastReceiver
android.content.BroadcastReceiver$PendingResult
-android.content.BroadcastReceiver$PendingResult$1
android.content.ClipData
+android.content.ClipData$1
+android.content.ClipData$Item
android.content.ClipDescription
android.content.ClipDescription$1
android.content.ClipboardManager
@@ -545,10 +600,9 @@ android.content.ContentProvider$Transport
android.content.ContentProviderClient
android.content.ContentProviderNative
android.content.ContentProviderOperation
-android.content.ContentProviderOperation$1
+android.content.ContentProviderOperation$Builder
android.content.ContentProviderProxy
android.content.ContentProviderResult
-android.content.ContentProviderResult$1
android.content.ContentResolver
android.content.ContentResolver$CursorWrapperInner
android.content.ContentResolver$ParcelFileDescriptorInner
@@ -583,6 +637,7 @@ android.content.IntentFilter$MalformedMimeTypeException
android.content.IntentSender
android.content.IntentSender$SendIntentException
android.content.OperationApplicationException
+android.content.PeriodicSync
android.content.RestrictionsManager
android.content.ServiceConnection
android.content.SharedPreferences
@@ -620,6 +675,8 @@ android.content.pm.InstrumentationInfo$1
android.content.pm.LauncherApps
android.content.pm.PackageInfo
android.content.pm.PackageInfo$1
+android.content.pm.PackageInstaller
+android.content.pm.PackageInstaller$SessionInfo
android.content.pm.PackageItemInfo
android.content.pm.PackageManager
android.content.pm.PackageManager$NameNotFoundException
@@ -646,14 +703,17 @@ android.content.res.AssetManager
android.content.res.AssetManager$AssetInputStream
android.content.res.ColorStateList
android.content.res.ColorStateList$1
+android.content.res.ColorStateList$ColorStateListFactory
android.content.res.CompatibilityInfo
android.content.res.CompatibilityInfo$1
android.content.res.CompatibilityInfo$2
+android.content.res.ComplexColor
android.content.res.Configuration
android.content.res.Configuration$1
android.content.res.ConfigurationBoundResourceCache
android.content.res.ConstantState
android.content.res.DrawableCache
+android.content.res.GradientColor
android.content.res.ObbInfo
android.content.res.ObbInfo$1
android.content.res.ObbScanner
@@ -685,6 +745,7 @@ android.database.ContentObserver$Transport
android.database.CrossProcessCursor
android.database.CrossProcessCursorWrapper
android.database.Cursor
+android.database.CursorIndexOutOfBoundsException
android.database.CursorToBulkCursorAdaptor
android.database.CursorToBulkCursorAdaptor$ContentObserverProxy
android.database.CursorWindow
@@ -700,6 +761,8 @@ android.database.IContentObserver
android.database.IContentObserver$Stub
android.database.IContentObserver$Stub$Proxy
android.database.MatrixCursor
+android.database.MatrixCursor$RowBuilder
+android.database.MergeCursor
android.database.Observable
android.database.SQLException
android.database.sqlite.DatabaseObjectNotClosedException
@@ -712,11 +775,13 @@ android.database.sqlite.SQLiteConnection$PreparedStatementCache
android.database.sqlite.SQLiteConnectionPool
android.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus
android.database.sqlite.SQLiteConnectionPool$ConnectionWaiter
+android.database.sqlite.SQLiteConstraintException
android.database.sqlite.SQLiteCursor
android.database.sqlite.SQLiteCursorDriver
android.database.sqlite.SQLiteCustomFunction
android.database.sqlite.SQLiteDatabase
android.database.sqlite.SQLiteDatabase$1
+android.database.sqlite.SQLiteDatabase$CursorFactory
android.database.sqlite.SQLiteDatabaseConfiguration
android.database.sqlite.SQLiteDatabaseCorruptException
android.database.sqlite.SQLiteDatabaseLockedException
@@ -745,7 +810,7 @@ android.ddm.DdmRegister
android.graphics.AvoidXfermode
android.graphics.Bitmap
android.graphics.Bitmap$1
-android.graphics.Bitmap$BitmapFinalizer
+android.graphics.Bitmap$CompressFormat
android.graphics.Bitmap$Config
android.graphics.BitmapFactory
android.graphics.BitmapFactory$Options
@@ -754,11 +819,11 @@ android.graphics.BitmapShader
android.graphics.BlurMaskFilter
android.graphics.Camera
android.graphics.Canvas
-android.graphics.Canvas$CanvasFinalizer
android.graphics.Canvas$EdgeType
android.graphics.CanvasProperty
android.graphics.Color
android.graphics.ColorFilter
+android.graphics.ColorMatrix
android.graphics.ColorMatrixColorFilter
android.graphics.ComposePathEffect
android.graphics.ComposeShader
@@ -770,6 +835,7 @@ android.graphics.EmbossMaskFilter
android.graphics.FontFamily
android.graphics.FontListParser
android.graphics.FontListParser$Alias
+android.graphics.FontListParser$Axis
android.graphics.FontListParser$Config
android.graphics.FontListParser$Family
android.graphics.FontListParser$Font
@@ -808,6 +874,7 @@ android.graphics.Point
android.graphics.Point$1
android.graphics.PointF
android.graphics.PointF$1
+android.graphics.PorterDuff
android.graphics.PorterDuff$Mode
android.graphics.PorterDuffColorFilter
android.graphics.PorterDuffXfermode
@@ -836,11 +903,11 @@ android.graphics.drawable.Animatable
android.graphics.drawable.Animatable2
android.graphics.drawable.AnimatedStateListDrawable
android.graphics.drawable.AnimatedStateListDrawable$AnimatedStateListState
-android.graphics.drawable.AnimatedStateListDrawable$Transition
android.graphics.drawable.AnimatedVectorDrawable
android.graphics.drawable.AnimatedVectorDrawable$1
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
+android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT
android.graphics.drawable.AnimationDrawable
android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
@@ -852,7 +919,7 @@ android.graphics.drawable.Drawable$Callback
android.graphics.drawable.Drawable$ConstantState
android.graphics.drawable.DrawableContainer
android.graphics.drawable.DrawableContainer$DrawableContainerState
-android.graphics.drawable.DrawableContainer$DrawableContainerState$ConstantStateFuture
+android.graphics.drawable.DrawableInflater
android.graphics.drawable.DrawableWrapper
android.graphics.drawable.DrawableWrapper$DrawableWrapperState
android.graphics.drawable.GradientDrawable
@@ -892,9 +959,11 @@ android.graphics.drawable.TransitionDrawable
android.graphics.drawable.TransitionDrawable$TransitionState
android.graphics.drawable.VectorDrawable
android.graphics.drawable.VectorDrawable$VFullPath
+android.graphics.drawable.VectorDrawable$VFullPath$1
android.graphics.drawable.VectorDrawable$VGroup
+android.graphics.drawable.VectorDrawable$VGroup$1
+android.graphics.drawable.VectorDrawable$VObject
android.graphics.drawable.VectorDrawable$VPath
-android.graphics.drawable.VectorDrawable$VPathRenderer
android.graphics.drawable.VectorDrawable$VectorDrawableState
android.graphics.drawable.shapes.OvalShape
android.graphics.drawable.shapes.RectShape
@@ -913,7 +982,10 @@ android.hardware.SerialManager
android.hardware.SerialPort
android.hardware.SystemSensorManager
android.hardware.SystemSensorManager$BaseEventQueue
+android.hardware.camera2.CameraCharacteristics$Key
android.hardware.camera2.CameraManager
+android.hardware.camera2.CaptureRequest$Key
+android.hardware.camera2.CaptureResult$Key
android.hardware.camera2.DngCreator
android.hardware.camera2.impl.CameraMetadataNative
android.hardware.camera2.legacy.LegacyCameraDevice
@@ -928,6 +1000,12 @@ android.hardware.display.IDisplayManager$Stub
android.hardware.display.IDisplayManager$Stub$Proxy
android.hardware.display.IDisplayManagerCallback
android.hardware.display.IDisplayManagerCallback$Stub
+android.hardware.display.WifiDisplay
+android.hardware.display.WifiDisplay$1
+android.hardware.display.WifiDisplaySessionInfo
+android.hardware.display.WifiDisplaySessionInfo$1
+android.hardware.display.WifiDisplayStatus
+android.hardware.display.WifiDisplayStatus$1
android.hardware.fingerprint.FingerprintManager
android.hardware.hdmi.HdmiControlManager
android.hardware.input.IInputDevicesChangedListener
@@ -939,6 +1017,10 @@ android.hardware.input.InputDeviceIdentifier
android.hardware.input.InputDeviceIdentifier$1
android.hardware.input.InputManager
android.hardware.input.InputManager$InputDevicesChangedListener
+# These cannot be preloaded and need to be refactored into system server. b/17791590, b/21935130
+# android.hardware.location.ActivityRecognitionHardware
+# android.hardware.location.IActivityRecognitionHardware
+# android.hardware.location.IActivityRecognitionHardware$Stub
android.hardware.radio.RadioManager
android.hardware.radio.RadioManager$AmBandConfig
android.hardware.radio.RadioManager$AmBandConfig$1
@@ -963,6 +1045,8 @@ android.hardware.radio.RadioTuner
android.hardware.soundtrigger.SoundTrigger
android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel
android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel$1
+android.hardware.soundtrigger.SoundTrigger$GenericRecognitionEvent
+android.hardware.soundtrigger.SoundTrigger$GenericSoundModel
android.hardware.soundtrigger.SoundTrigger$Keyphrase
android.hardware.soundtrigger.SoundTrigger$Keyphrase$1
android.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionEvent
@@ -981,14 +1065,19 @@ 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.IUsbManager$Stub$Proxy
android.hardware.usb.UsbDevice
android.hardware.usb.UsbDeviceConnection
+android.hardware.usb.UsbInterface
android.hardware.usb.UsbManager
android.hardware.usb.UsbRequest
android.icu.impl.BMPSet
android.icu.impl.CacheBase
android.icu.impl.CalendarData
android.icu.impl.CalendarUtil
+android.icu.impl.CharTrie
android.icu.impl.ClassLoaderUtil
android.icu.impl.CurrencyData
android.icu.impl.CurrencyData$CurrencyDisplayInfo
@@ -1012,8 +1101,17 @@ android.icu.impl.ICUCurrencyMetaInfo$CurrencyCollector
android.icu.impl.ICUCurrencyMetaInfo$UniqueList
android.icu.impl.ICUData
android.icu.impl.ICUDebug
+android.icu.impl.ICULocaleService
+android.icu.impl.ICULocaleService$ICUResourceBundleFactory
+android.icu.impl.ICULocaleService$LocaleKey
+android.icu.impl.ICULocaleService$LocaleKeyFactory
+android.icu.impl.ICUNotifier
+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$AvailEntry
android.icu.impl.ICUResourceBundle$OpenType
android.icu.impl.ICUResourceBundle$WholeBundle
android.icu.impl.ICUResourceBundleImpl
@@ -1027,27 +1125,52 @@ android.icu.impl.ICUResourceBundleImpl$ResourceTable
android.icu.impl.ICUResourceBundleReader
android.icu.impl.ICUResourceBundleReader$Array
android.icu.impl.ICUResourceBundleReader$Array16
+android.icu.impl.ICUResourceBundleReader$Array32
android.icu.impl.ICUResourceBundleReader$Container
android.icu.impl.ICUResourceBundleReader$IsAcceptable
android.icu.impl.ICUResourceBundleReader$ReaderCache
-android.icu.impl.ICUResourceBundleReader$ReaderInfo
+android.icu.impl.ICUResourceBundleReader$ReaderCacheKey
android.icu.impl.ICUResourceBundleReader$ResourceCache
android.icu.impl.ICUResourceBundleReader$ResourceCache$Level
android.icu.impl.ICUResourceBundleReader$Table
android.icu.impl.ICUResourceBundleReader$Table16
android.icu.impl.ICUResourceBundleReader$Table1632
+android.icu.impl.ICUService
+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
+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
+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.SoftCache
android.icu.impl.SoftCache$SettableSoftReference
+android.icu.impl.StandardPlural
+android.icu.impl.StringPrepDataReader
+android.icu.impl.Trie
+android.icu.impl.Trie$DataManipulate
+android.icu.impl.Trie$DefaultGetFoldingOffset
android.icu.impl.Trie2
android.icu.impl.Trie2$1
android.icu.impl.Trie2$Range
@@ -1056,6 +1179,9 @@ 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
android.icu.impl.UCharacterProperty$1
android.icu.impl.UCharacterProperty$10
@@ -1090,10 +1216,22 @@ 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.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
@@ -1106,6 +1244,13 @@ 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.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
@@ -1129,9 +1274,12 @@ 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.DigitList
android.icu.text.DisplayContext
android.icu.text.DisplayContext$Type
+android.icu.text.IDNA
android.icu.text.MessageFormat
android.icu.text.MessageFormat$AppendableWrapper
android.icu.text.MessageFormat$Field
@@ -1140,13 +1288,48 @@ 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
+android.icu.text.Normalizer$ModeImpl
+android.icu.text.Normalizer$NFCMode
+android.icu.text.Normalizer$NFDMode
+android.icu.text.Normalizer$NFKCMode
+android.icu.text.Normalizer$NFKDMode
+android.icu.text.Normalizer$NFKDModeImpl
+android.icu.text.Normalizer$NONEMode
+android.icu.text.Normalizer$QuickCheckResult
+android.icu.text.Normalizer2
android.icu.text.NumberFormat
+android.icu.text.NumberFormat$Field
android.icu.text.NumberingSystem
+android.icu.text.PluralRanges
+android.icu.text.PluralRanges$Matrix
+android.icu.text.PluralRules
+android.icu.text.PluralRules$1
+android.icu.text.PluralRules$AndConstraint
+android.icu.text.PluralRules$BinaryConstraint
+android.icu.text.PluralRules$Constraint
+android.icu.text.PluralRules$Factory
+android.icu.text.PluralRules$FixedDecimal
+android.icu.text.PluralRules$FixedDecimalRange
+android.icu.text.PluralRules$FixedDecimalSamples
+android.icu.text.PluralRules$Operand
+android.icu.text.PluralRules$PluralType
+android.icu.text.PluralRules$RangeConstraint
+android.icu.text.PluralRules$Rule
+android.icu.text.PluralRules$RuleList
+android.icu.text.PluralRules$SampleType
+android.icu.text.PluralRules$SimpleTokenizer
android.icu.text.Replaceable
android.icu.text.ReplaceableString
+android.icu.text.RuleBasedCollator
android.icu.text.SimpleDateFormat
android.icu.text.SimpleDateFormat$PatternItem
+android.icu.text.StringPrep
+android.icu.text.StringPrepParseException
android.icu.text.UCharacterIterator
+android.icu.text.UFieldPosition
android.icu.text.UFormat
android.icu.text.UForwardCharacterIterator
android.icu.text.UTF16
@@ -1166,6 +1349,7 @@ android.icu.util.Calendar$PatternData
android.icu.util.Calendar$WeekData
android.icu.util.Calendar$WeekDataCache
android.icu.util.Currency
+android.icu.util.Currency$CurrencyUsage
android.icu.util.Currency$EquivalenceRelation
android.icu.util.Freezable
android.icu.util.GregorianCalendar
@@ -1174,6 +1358,7 @@ 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
@@ -1187,16 +1372,27 @@ android.icu.util.UResourceBundle$ResourceCacheKey
android.icu.util.UResourceBundleIterator
android.icu.util.UResourceTypeMismatchException
android.icu.util.VersionInfo
-android.inputmethodservice.ExtractEditText
android.location.CountryDetector
+android.location.GnssMeasurementCallbackTransport
+android.location.GnssMeasurementCallbackTransport$ListenerTransport
+android.location.GnssNavigationMessageCallbackTransport
+android.location.GnssNavigationMessageCallbackTransport$ListenerTransport
+android.location.IGnssMeasurementsListener
+android.location.IGnssMeasurementsListener$Stub
+android.location.IGnssNavigationMessageListener
+android.location.IGnssNavigationMessageListener$Stub
+android.location.ILocationManager
+android.location.ILocationManager$Stub
+android.location.ILocationManager$Stub$Proxy
+android.location.LocalListenerHelper
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
-android.media.AudioDeviceInfo
android.media.AudioDevicePort
android.media.AudioDevicePortConfig
android.media.AudioFormat
@@ -1205,31 +1401,45 @@ android.media.AudioGainConfig
android.media.AudioHandle
android.media.AudioManager
android.media.AudioManager$1
-android.media.AudioManager$FocusEventHandlerDelegate
-android.media.AudioManager$FocusEventHandlerDelegate$1
-android.media.AudioManager$OnAmPortUpdateListener
-android.media.AudioManager$OnAudioPortUpdateListener
+android.media.AudioManager$2
+android.media.AudioManager$OnAudioFocusChangeListener
+android.media.AudioManager$ServiceEventHandlerDelegate
+android.media.AudioManager$ServiceEventHandlerDelegate$1
android.media.AudioMixPort
android.media.AudioMixPortConfig
android.media.AudioPatch
android.media.AudioPort
android.media.AudioPortConfig
android.media.AudioPortEventHandler
-android.media.AudioPortEventHandler$1
android.media.AudioRecord
+android.media.AudioRoutesInfo
+android.media.AudioRoutesInfo$1
+android.media.AudioRouting
android.media.AudioSystem
+android.media.AudioTimestamp
android.media.AudioTrack
android.media.CamcorderProfile
android.media.CameraProfile
android.media.DecoderCapabilities
android.media.EncoderCapabilities
+android.media.ExifInterface
android.media.IAudioFocusDispatcher
android.media.IAudioFocusDispatcher$Stub
+android.media.IAudioRoutesObserver
+android.media.IAudioRoutesObserver$Stub
android.media.IAudioService
android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
android.media.IMediaHTTPConnection
android.media.IMediaHTTPConnection$Stub
+android.media.IMediaRouterClient
+android.media.IMediaRouterClient$Stub
+android.media.IMediaRouterService
+android.media.IMediaRouterService$Stub
+android.media.IRecordingConfigDispatcher
+android.media.IRecordingConfigDispatcher$Stub
+android.media.IRemoteVolumeObserver
+android.media.IRemoteVolumeObserver$Stub
android.media.Image
android.media.ImageReader
android.media.ImageReader$SurfaceImage
@@ -1245,37 +1455,46 @@ android.media.MediaHTTPConnection
android.media.MediaMetadataRetriever
android.media.MediaMuxer
android.media.MediaPlayer
-android.media.MediaPlayer$1
-android.media.MediaPlayer$EventHandler
android.media.MediaPlayer$OnCompletionListener
android.media.MediaPlayer$OnErrorListener
+android.media.MediaPlayer$OnPreparedListener
android.media.MediaPlayer$OnSeekCompleteListener
-android.media.MediaPlayer$OnSubtitleDataListener
-android.media.MediaPlayer$TimeProvider
-android.media.MediaPlayer$TimeProvider$EventHandler
android.media.MediaRecorder
android.media.MediaRouter
+android.media.MediaRouter$Callback
+android.media.MediaRouter$RouteCategory
+android.media.MediaRouter$RouteInfo
+android.media.MediaRouter$RouteInfo$1
+android.media.MediaRouter$Static
+android.media.MediaRouter$Static$1
+android.media.MediaRouter$Static$Client
+android.media.MediaRouter$VolumeChangeReceiver
+android.media.MediaRouter$WifiDisplayStatusChangedReceiver
+android.media.MediaRouterClientState
+android.media.MediaRouterClientState$1
android.media.MediaScanner
android.media.MediaSync
-android.media.MediaTimeProvider
-android.media.MediaTimeProvider$OnMediaTimeListener
android.media.PlaybackParams
android.media.PlaybackParams$1
android.media.RemoteDisplay
android.media.ResampleInputStream
android.media.SubtitleController$Listener
-android.media.SyncParams
+android.media.ThumbnailUtils
android.media.ToneGenerator
+android.media.audiofx.AcousticEchoCanceler
+android.media.audiofx.AudioEffect
android.media.audiopolicy.AudioMix
android.media.audiopolicy.AudioMixingRule
-android.media.audiopolicy.AudioMixingRule$AttributeMatchCriterion
+android.media.audiopolicy.AudioMixingRule$AudioMixMatchCriterion
android.media.midi.MidiManager
android.media.projection.MediaProjectionManager
android.media.session.MediaSessionManager
+android.media.soundtrigger.SoundTriggerManager
android.media.tv.TvInputManager
android.mtp.MtpDatabase
android.mtp.MtpDevice
android.mtp.MtpDeviceInfo
+android.mtp.MtpEvent
android.mtp.MtpObjectInfo
android.mtp.MtpPropertyGroup
android.mtp.MtpPropertyList
@@ -1283,6 +1502,8 @@ android.mtp.MtpServer
android.mtp.MtpStorage
android.mtp.MtpStorageInfo
android.net.ConnectivityManager
+android.net.ConnectivityManager$CallbackHandler
+android.net.ConnectivityManager$NetworkCallback
android.net.Credentials
android.net.DhcpResults
android.net.DhcpResults$1
@@ -1301,18 +1522,24 @@ android.net.LocalSocket
android.net.LocalSocketImpl
android.net.LocalSocketImpl$SocketInputStream
android.net.LocalSocketImpl$SocketOutputStream
+android.net.Network
+android.net.Network$1
+android.net.NetworkCapabilities
+android.net.NetworkCapabilities$1
android.net.NetworkInfo
android.net.NetworkInfo$1
android.net.NetworkInfo$DetailedState
android.net.NetworkInfo$State
android.net.NetworkPolicyManager
+android.net.NetworkRequest
+android.net.NetworkRequest$1
+android.net.NetworkRequest$Builder
android.net.NetworkScoreManager
android.net.NetworkStats
android.net.NetworkStats$1
android.net.NetworkUtils
android.net.Proxy
android.net.ProxyInfo
-android.net.ProxyInfo$1
android.net.RouteInfo
android.net.RouteInfo$1
android.net.SSLCertificateSocketFactory
@@ -1334,8 +1561,6 @@ android.net.Uri$PathPart
android.net.Uri$PathSegments
android.net.Uri$PathSegmentsBuilder
android.net.Uri$StringUri
-android.net.http.AndroidHttpClient
-android.net.http.AndroidHttpClient$1
android.net.nsd.NsdManager
android.net.wifi.IWifiManager
android.net.wifi.IWifiManager$Stub
@@ -1346,13 +1571,12 @@ android.net.wifi.SupplicantState$1
android.net.wifi.WifiInfo
android.net.wifi.WifiInfo$1
android.net.wifi.WifiManager
-android.net.wifi.WifiManager$ServiceHandler
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.p2p.WifiP2pManager
-android.net.wifi.passpoint.WifiPasspointManager
android.nfc.IAppCallback
android.nfc.IAppCallback$Stub
android.nfc.INfcAdapter
@@ -1360,13 +1584,10 @@ 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.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
@@ -1384,6 +1605,7 @@ android.opengl.GLES20
android.opengl.GLES30
android.opengl.GLES31
android.opengl.GLES31Ext
+android.opengl.GLES32
android.opengl.GLUtils
android.opengl.Matrix
android.opengl.Visibility
@@ -1408,6 +1630,9 @@ android.os.Bundle$1
android.os.CancellationSignal
android.os.CancellationSignal$OnCancelListener
android.os.CancellationSignal$Transport
+android.os.ConditionVariable
+android.os.CpuUsageInfo
+android.os.CpuUsageInfo$1
android.os.DeadObjectException
android.os.Debug
android.os.Debug$MemoryInfo
@@ -1421,6 +1646,7 @@ android.os.Handler
android.os.Handler$Callback
android.os.Handler$MessengerImpl
android.os.HandlerThread
+android.os.HardwarePropertiesManager
android.os.IBinder
android.os.IBinder$DeathRecipient
android.os.ICancellationSignal
@@ -1447,16 +1673,16 @@ android.os.MessageQueue
android.os.MessageQueue$IdleHandler
android.os.Messenger
android.os.Messenger$1
+android.os.OperationCanceledException
android.os.Parcel
android.os.Parcel$1
android.os.ParcelFileDescriptor
android.os.ParcelFileDescriptor$1
android.os.ParcelFileDescriptor$AutoCloseInputStream
+android.os.ParcelUuid
android.os.Parcelable
android.os.Parcelable$ClassLoaderCreator
android.os.Parcelable$Creator
-android.os.ParcelableParcel
-android.os.ParcelableParcel$1
android.os.PatternMatcher
android.os.PatternMatcher$1
android.os.PersistableBundle
@@ -1466,6 +1692,7 @@ android.os.PowerManager$WakeLock
android.os.PowerManager$WakeLock$1
android.os.Process
android.os.RemoteException
+android.os.ResultReceiver
android.os.SELinux
android.os.ServiceManager
android.os.ServiceManagerNative
@@ -1492,6 +1719,7 @@ android.os.StrictMode$StrictModeDiskReadViolation
android.os.StrictMode$StrictModeDiskWriteViolation
android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
+android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
android.os.StrictMode$ViolationInfo
android.os.StrictMode$VmPolicy
@@ -1500,6 +1728,7 @@ android.os.SystemClock
android.os.SystemProperties
android.os.Trace
android.os.Trace$1
+android.os.TransactionTooLargeException
android.os.UEventObserver
android.os.UserHandle
android.os.UserHandle$1
@@ -1512,7 +1741,9 @@ android.os.storage.IMountService$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
android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback
android.preference.PreferenceManager
android.preference.PreferenceManager$OnPreferenceTreeClickListener
@@ -1556,17 +1787,33 @@ android.provider.Settings$System$InclusiveFloatRangeValidator
android.provider.Settings$System$InclusiveIntegerRangeValidator
android.provider.Settings$System$Validator
android.renderscript.RenderScriptCacheDir
-android.security.IKeystoreService
-android.security.IKeystoreService$Stub
-android.security.IKeystoreService$Stub$Proxy
-android.security.KeyStore
-android.security.KeyStoreException
+android.security.FrameworkNetworkSecurityPolicy
+android.security.KeyChain
android.security.NetworkSecurityPolicy
android.security.keystore.AndroidKeyStoreBCWorkaroundProvider
-android.security.keystore.AndroidKeyStoreKey
android.security.keystore.AndroidKeyStoreProvider
-android.security.keystore.KeyStoreCryptoOperation
+android.security.net.config.ApplicationConfig
+android.security.net.config.CertificateSource
+android.security.net.config.CertificatesEntryRef
+android.security.net.config.ConfigNetworkSecurityPolicy
+android.security.net.config.ConfigSource
+android.security.net.config.DirectoryCertificateSource
+android.security.net.config.DirectoryCertificateSource$1
+android.security.net.config.DirectoryCertificateSource$3
+android.security.net.config.DirectoryCertificateSource$CertSelector
+android.security.net.config.ManifestConfigSource
+android.security.net.config.ManifestConfigSource$DefaultConfigSource
+android.security.net.config.NetworkSecurityConfig
+android.security.net.config.NetworkSecurityConfig$1
+android.security.net.config.NetworkSecurityConfig$Builder
android.security.net.config.NetworkSecurityConfigProvider
+android.security.net.config.NetworkSecurityTrustManager
+android.security.net.config.PinSet
+android.security.net.config.RootTrustManager
+android.security.net.config.RootTrustManagerFactorySpi
+android.security.net.config.SystemCertificateSource
+android.security.net.config.TrustedCertificateStoreAdapter
+android.security.net.config.UserCertificateSource
android.service.persistentdata.PersistentDataBlockManager
android.system.ErrnoException
android.system.GaiException
@@ -1586,6 +1833,7 @@ android.system.StructStatVfs
android.system.StructTimeval
android.system.StructUcred
android.system.StructUtsname
+android.system.UnixSocketAddress
android.telecom.TelecomManager
android.telephony.CarrierConfigManager
android.telephony.PhoneNumberUtils
@@ -1604,15 +1852,12 @@ android.text.Editable$Factory
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
android.text.Layout
android.text.Layout$Alignment
android.text.Layout$Directions
-android.text.Layout$Ellipsizer
android.text.MeasuredText
android.text.NoCopySpan
android.text.NoCopySpan$Concrete
@@ -1647,6 +1892,8 @@ 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
@@ -1669,13 +1916,17 @@ android.text.method.ScrollingMovementMethod
android.text.method.SingleLineTransformationMethod
android.text.method.TextKeyListener
android.text.method.TextKeyListener$Capitalize
+android.text.method.Touch
android.text.method.TransformationMethod
android.text.method.TransformationMethod2
android.text.style.AlignmentSpan
+android.text.style.BackgroundColorSpan
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
@@ -1687,6 +1938,7 @@ android.text.style.StyleSpan
android.text.style.SuggestionSpan
android.text.style.TabStopSpan
android.text.style.URLSpan
+android.text.style.UnderlineSpan
android.text.style.UpdateAppearance
android.text.style.UpdateLayout
android.text.style.WrapTogetherSpan
@@ -1710,6 +1962,7 @@ android.transition.PathMotion
android.transition.Scene
android.transition.Transition
android.transition.Transition$1
+android.transition.Transition$EpicenterCallback
android.transition.TransitionInflater
android.transition.TransitionManager
android.transition.TransitionSet
@@ -1720,6 +1973,7 @@ android.util.AndroidRuntimeException
android.util.ArrayMap
android.util.ArrayMap$1
android.util.ArraySet
+android.util.ArraySet$1
android.util.AttributeSet
android.util.Base64
android.util.Base64$Coder
@@ -1731,38 +1985,44 @@ android.util.EventLog
android.util.EventLog$Event
android.util.FloatProperty
android.util.IntProperty
+android.util.JsonReader
+android.util.LocaleList
+android.util.LocaleList$1
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
android.util.MapCollections
android.util.MapCollections$ArrayIterator
android.util.MapCollections$KeySet
-android.util.MapCollections$ValuesCollection
android.util.MathUtils
android.util.MutableInt
android.util.MutableLong
android.util.Pair
android.util.PathParser
-android.util.PathParser$ExtractFloatResult
-android.util.PathParser$PathDataNode
+android.util.PathParser$PathData
android.util.Patterns
android.util.Pools$Pool
android.util.Pools$SimplePool
android.util.Pools$SynchronizedPool
android.util.Printer
android.util.Property
+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
@@ -1785,6 +2045,8 @@ 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$Mode
android.view.Display$Mode$1
android.view.DisplayAdjustments
@@ -1792,11 +2054,14 @@ 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
android.view.FocusFinder$SequentialFocusComparator
android.view.FrameInfo
+android.view.FrameMetrics
+android.view.FrameMetricsObserver
android.view.FrameStats
android.view.GestureDetector
android.view.GestureDetector$GestureHandler
@@ -1807,9 +2072,9 @@ android.view.GestureDetector$SimpleOnGestureListener
android.view.GraphicBuffer
android.view.GraphicBuffer$1
android.view.Gravity
+android.view.HandlerActionQueue
+android.view.HandlerActionQueue$HandlerAction
android.view.HardwareLayer
-android.view.HardwareRenderer
-android.view.HardwareRenderer$HardwareDrawCallbacks
android.view.IAssetAtlas
android.view.IAssetAtlas$Stub
android.view.IAssetAtlas$Stub$Proxy
@@ -1833,6 +2098,7 @@ 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
@@ -1844,6 +2110,7 @@ android.view.InputQueue$FinishedInputEventCallback
android.view.KeyCharacterMap
android.view.KeyCharacterMap$1
android.view.KeyCharacterMap$FallbackAction
+android.view.KeyCharacterMap$KeyData
android.view.KeyEvent
android.view.KeyEvent$1
android.view.KeyEvent$Callback
@@ -1868,7 +2135,9 @@ android.view.PointerIcon$1
android.view.RenderNode
android.view.RenderNodeAnimator
android.view.RenderNodeAnimator$1
+android.view.RenderNodeAnimatorSetHelper
android.view.SearchEvent
+android.view.SoundEffectConstants
android.view.SubMenu
android.view.Surface
android.view.Surface$1
@@ -1876,11 +2145,14 @@ android.view.Surface$CompatibleCanvas
android.view.Surface$OutOfResourcesException
android.view.SurfaceControl
android.view.SurfaceControl$PhysicalDisplayInfo
+android.view.SurfaceHolder
android.view.SurfaceHolder$Callback
android.view.SurfaceHolder$Callback2
android.view.SurfaceSession
+android.view.SurfaceView
android.view.TextureView
android.view.ThreadedRenderer
+android.view.ThreadedRenderer$HardwareDrawCallbacks
android.view.ThreadedRenderer$ProcessInitializer
android.view.VelocityTracker
android.view.VelocityTracker$Estimator
@@ -1954,8 +2226,6 @@ android.view.ViewRootImpl$InvalidateOnAnimationRunnable
android.view.ViewRootImpl$NativePostImeInputStage
android.view.ViewRootImpl$NativePreImeInputStage
android.view.ViewRootImpl$QueuedInputEvent
-android.view.ViewRootImpl$RunQueue
-android.view.ViewRootImpl$RunQueue$HandlerAction
android.view.ViewRootImpl$SyntheticInputStage
android.view.ViewRootImpl$SyntheticJoystickHandler
android.view.ViewRootImpl$SyntheticKeyboardHandler
@@ -1982,10 +2252,13 @@ android.view.ViewTreeObserver$OnTouchModeChangeListener
android.view.Window
android.view.Window$Callback
android.view.Window$OnWindowDismissedCallback
+android.view.Window$WindowControllerCallback
android.view.WindowAnimationFrameStats
android.view.WindowAnimationFrameStats$1
+android.view.WindowCallbacks
android.view.WindowContentFrameStats
android.view.WindowContentFrameStats$1
+android.view.WindowId
android.view.WindowInsets
android.view.WindowLeaked
android.view.WindowManager
@@ -2006,6 +2279,9 @@ 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
@@ -2019,12 +2295,15 @@ android.view.animation.Animation$1
android.view.animation.Animation$2
android.view.animation.Animation$3
android.view.animation.Animation$AnimationListener
+android.view.animation.AnimationSet
android.view.animation.AnimationUtils
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.inputmethod.BaseInputConnection
@@ -2044,12 +2323,14 @@ android.view.inputmethod.InputMethodManager$FinishedInputEventCallback
android.view.inputmethod.InputMethodManager$H
android.view.inputmethod.InputMethodManager$ImeInputEventSender
android.view.inputmethod.InputMethodManager$PendingEvent
+android.view.inputmethod.InputMethodSubtype
android.view.textservice.SpellCheckerSession$SpellCheckerSessionListener
android.view.textservice.SpellCheckerSubtype
android.view.textservice.SpellCheckerSubtype$1
android.view.textservice.TextServicesManager
-android.webkit.IWebViewUpdateService
-android.webkit.IWebViewUpdateService$Stub
+android.webkit.MimeTypeMap
+android.webkit.URLUtil
+android.webkit.WebSettings
android.webkit.WebView
android.webkit.WebViewFactory
android.webkit.WebViewFactory$MissingWebViewPackageException
@@ -2065,8 +2346,8 @@ android.widget.AbsListView$SavedState
android.widget.AbsListView$SavedState$1
android.widget.AbsListView$SelectionBoundsAdjuster
android.widget.AbsListView$WindowRunnnable
+android.widget.AbsSeekBar
android.widget.AbsSpinner
-android.widget.AbsSpinner$RecycleBin
android.widget.AbsoluteLayout
android.widget.ActionMenuPresenter
android.widget.ActionMenuPresenter$1
@@ -2076,17 +2357,23 @@ android.widget.ActionMenuPresenter$OverflowMenuButton$1
android.widget.ActionMenuPresenter$PopupPresenterCallback
android.widget.ActionMenuView
android.widget.ActionMenuView$ActionMenuChildView
-android.widget.ActionMenuView$LayoutParams
android.widget.ActionMenuView$OnMenuItemClickListener
android.widget.Adapter
android.widget.AdapterView
android.widget.AdapterView$AdapterDataSetObserver
android.widget.AdapterView$OnItemClickListener
+android.widget.AdapterView$OnItemLongClickListener
android.widget.AdapterView$OnItemSelectedListener
android.widget.ArrayAdapter
+android.widget.AutoCompleteTextView
+android.widget.AutoCompleteTextView$DropDownItemClickListener
+android.widget.AutoCompleteTextView$MyWatcher
+android.widget.AutoCompleteTextView$PassThroughClickListener
android.widget.BaseAdapter
android.widget.Button
+android.widget.CheckBox
android.widget.Checkable
+android.widget.CheckedTextView
android.widget.CompoundButton
android.widget.CompoundButton$OnCheckedChangeListener
android.widget.EdgeEffect
@@ -2094,6 +2381,7 @@ android.widget.EditText
android.widget.Editor
android.widget.Editor$1
android.widget.Editor$2
+android.widget.Editor$3
android.widget.Editor$Blink
android.widget.Editor$CursorAnchorInfoNotifier
android.widget.Editor$EditOperation
@@ -2101,17 +2389,23 @@ android.widget.Editor$EditOperation$1
android.widget.Editor$InputContentType
android.widget.Editor$InputMethodState
android.widget.Editor$PositionListener
+android.widget.Editor$ProcessTextIntentActionsHandler
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
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
@@ -2119,7 +2413,6 @@ android.widget.LinearLayout
android.widget.LinearLayout$LayoutParams
android.widget.ListAdapter
android.widget.ListPopupWindow
-android.widget.ListPopupWindow$ForwardingListener
android.widget.ListPopupWindow$ListSelectorHider
android.widget.ListPopupWindow$PopupDataSetObserver
android.widget.ListPopupWindow$PopupScrollListener
@@ -2128,48 +2421,38 @@ 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
android.widget.PopupWindow
android.widget.PopupWindow$1
+android.widget.PopupWindow$2
android.widget.PopupWindow$OnDismissListener
android.widget.ProgressBar
+android.widget.ProgressBar$1
android.widget.ProgressBar$SavedState
android.widget.ProgressBar$SavedState$1
+android.widget.RadioButton
+android.widget.RatingBar
android.widget.RelativeLayout
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$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$SetDrawableParameters
-android.widget.RemoteViews$TextViewSizeAction
-android.widget.RemoteViews$ViewPaddingAction
android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
android.widget.RtlSpacingHelper
android.widget.ScrollBarDrawable
android.widget.ScrollView
-android.widget.ScrollView$SavedState
-android.widget.ScrollView$SavedState$1
android.widget.Scroller
android.widget.Scroller$ViscousFluidInterpolator
android.widget.SectionIndexer
+android.widget.SeekBar
android.widget.Space
android.widget.SpellChecker
android.widget.SpellChecker$SpellParser
android.widget.Spinner
-android.widget.Spinner$SpinnerPopup
android.widget.SpinnerAdapter
android.widget.TextView
-android.widget.TextView$2
android.widget.TextView$3
android.widget.TextView$BufferType
android.widget.TextView$ChangeWatcher
@@ -2177,13 +2460,17 @@ android.widget.TextView$CharWrapper
android.widget.TextView$Drawables
android.widget.TextView$OnEditorActionListener
android.widget.TextView$SavedState
-android.widget.TextView$SavedState$1
android.widget.ThemedSpinnerAdapter
+android.widget.Toast
+android.widget.Toast$TN
+android.widget.Toast$TN$1
+android.widget.Toast$TN$2
android.widget.Toolbar
android.widget.Toolbar$1
android.widget.Toolbar$2
android.widget.Toolbar$ExpandedActionViewMenuPresenter
android.widget.Toolbar$LayoutParams
+android.widget.ViewAnimator
android.widget.WrapperListAdapter
com.android.dex.Annotation
com.android.dex.ClassData
@@ -2216,19 +2503,10 @@ com.android.dex.util.ByteInput
com.android.dex.util.ByteOutput
com.android.dex.util.ExceptionWithContext
com.android.dex.util.FileUtils
-com.android.i18n.phonenumbers.CountryCodeToRegionCodeMap
-com.android.i18n.phonenumbers.MetadataLoader
com.android.i18n.phonenumbers.NumberParseException
-com.android.i18n.phonenumbers.PhoneNumberUtil
-com.android.i18n.phonenumbers.PhoneNumberUtil$1
-com.android.i18n.phonenumbers.RegexCache
-com.android.i18n.phonenumbers.RegexCache$LRUCache
-com.android.i18n.phonenumbers.RegexCache$LRUCache$1
com.android.internal.R$styleable
com.android.internal.app.AlertController
com.android.internal.app.AlertController$1
-com.android.internal.app.AlertController$2
-com.android.internal.app.AlertController$AlertParams
com.android.internal.app.AlertController$ButtonHandler
com.android.internal.app.IAppOpsService
com.android.internal.app.IAppOpsService$Stub
@@ -2236,15 +2514,13 @@ com.android.internal.app.IAppOpsService$Stub$Proxy
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
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.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.inputmethod.InputMethodUtils
com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
com.android.internal.logging.AndroidHandler$1
@@ -2252,6 +2528,7 @@ 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.LoggingPrintStream
com.android.internal.os.LoggingPrintStream$1
com.android.internal.os.RuntimeInit
@@ -2266,17 +2543,15 @@ 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.policy.DecorContext
+com.android.internal.policy.DecorView
+com.android.internal.policy.DecorView$ColorViewState
com.android.internal.policy.PhoneFallbackEventHandler
com.android.internal.policy.PhoneLayoutInflater
com.android.internal.policy.PhoneWindow
com.android.internal.policy.PhoneWindow$1
-com.android.internal.policy.PhoneWindow$ActionMenuPresenterCallback
-com.android.internal.policy.PhoneWindow$ColorViewState
-com.android.internal.policy.PhoneWindow$DecorView
-com.android.internal.policy.PhoneWindow$DialogMenuCallback
com.android.internal.policy.PhoneWindow$PanelFeatureState
-com.android.internal.policy.PhoneWindow$PanelFeatureState$SavedState
-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.telephony.ISub
@@ -2295,13 +2570,11 @@ 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.AsyncChannel
-com.android.internal.util.AsyncChannel$DeathMonitor
-com.android.internal.util.FastMath
com.android.internal.util.FastPrintWriter
com.android.internal.util.FastPrintWriter$DummyWriter
com.android.internal.util.FastXmlSerializer
com.android.internal.util.GrowingArrayUtils
+com.android.internal.util.LineBreakBufferedWriter
com.android.internal.util.Preconditions
com.android.internal.util.VirtualRefBasePtr
com.android.internal.util.XmlUtils
@@ -2339,25 +2612,16 @@ 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.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.ActionBarOverlayLayout
-com.android.internal.widget.ActionBarOverlayLayout$1
-com.android.internal.widget.ActionBarOverlayLayout$2
-com.android.internal.widget.ActionBarOverlayLayout$3
-com.android.internal.widget.ActionBarOverlayLayout$4
-com.android.internal.widget.ActionBarOverlayLayout$5
+com.android.internal.view.menu.ShowableListMenu
com.android.internal.widget.ActionBarOverlayLayout$ActionBarVisibilityCallback
-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.DecorContentParent
com.android.internal.widget.DecorToolbar
com.android.internal.widget.DialogTitle
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
@@ -2379,6 +2643,10 @@ com.android.okhttp.Handshake
com.android.okhttp.Headers
com.android.okhttp.Headers$Builder
com.android.okhttp.HttpHandler
+com.android.okhttp.HttpHandler$CleartextURLFilter
+com.android.okhttp.HttpUrl
+com.android.okhttp.HttpUrl$Builder
+com.android.okhttp.HttpUrl$Builder$ParseResult
com.android.okhttp.HttpsHandler
com.android.okhttp.OkHttpClient
com.android.okhttp.OkHttpClient$1
@@ -2400,6 +2668,7 @@ com.android.okhttp.internal.Network$1
com.android.okhttp.internal.OptionalMethod
com.android.okhttp.internal.Platform
com.android.okhttp.internal.RouteDatabase
+com.android.okhttp.internal.URLFilter
com.android.okhttp.internal.Util
com.android.okhttp.internal.Util$1
com.android.okhttp.internal.http.AuthenticatorAdapter
@@ -2421,8 +2690,6 @@ com.android.okhttp.internal.http.RequestLine
com.android.okhttp.internal.http.RetryableSink
com.android.okhttp.internal.http.RouteException
com.android.okhttp.internal.http.RouteSelector
-com.android.okhttp.internal.http.SocketConnector
-com.android.okhttp.internal.http.SocketConnector$ConnectedSocket
com.android.okhttp.internal.http.StatusLine
com.android.okhttp.internal.http.Transport
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection
@@ -2436,6 +2703,7 @@ com.android.okhttp.okio.AsyncTimeout$Watchdog
com.android.okhttp.okio.Buffer
com.android.okhttp.okio.BufferedSink
com.android.okhttp.okio.BufferedSource
+com.android.okhttp.okio.ForwardingTimeout
com.android.okhttp.okio.Okio
com.android.okhttp.okio.Okio$1
com.android.okhttp.okio.Okio$2
@@ -2451,75 +2719,20 @@ com.android.okhttp.okio.Source
com.android.okhttp.okio.Timeout
com.android.okhttp.okio.Timeout$1
com.android.okhttp.okio.Util
-com.android.org.bouncycastle.asn1.ASN1Boolean
-com.android.org.bouncycastle.asn1.ASN1Choice
com.android.org.bouncycastle.asn1.ASN1Encodable
-com.android.org.bouncycastle.asn1.ASN1EncodableVector
-com.android.org.bouncycastle.asn1.ASN1InputStream
-com.android.org.bouncycastle.asn1.ASN1Integer
-com.android.org.bouncycastle.asn1.ASN1Null
com.android.org.bouncycastle.asn1.ASN1Object
com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier
-com.android.org.bouncycastle.asn1.ASN1OctetString
-com.android.org.bouncycastle.asn1.ASN1OctetStringParser
-com.android.org.bouncycastle.asn1.ASN1OutputStream
+com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier$OidHandle
com.android.org.bouncycastle.asn1.ASN1Primitive
-com.android.org.bouncycastle.asn1.ASN1Sequence
-com.android.org.bouncycastle.asn1.ASN1SequenceParser
-com.android.org.bouncycastle.asn1.ASN1Set
-com.android.org.bouncycastle.asn1.ASN1StreamParser
-com.android.org.bouncycastle.asn1.ASN1String
-com.android.org.bouncycastle.asn1.ASN1TaggedObject
-com.android.org.bouncycastle.asn1.ASN1TaggedObjectParser
-com.android.org.bouncycastle.asn1.BERTags
-com.android.org.bouncycastle.asn1.DERBitString
-com.android.org.bouncycastle.asn1.DERFactory
-com.android.org.bouncycastle.asn1.DERIA5String
-com.android.org.bouncycastle.asn1.DERNull
-com.android.org.bouncycastle.asn1.DEROctetString
-com.android.org.bouncycastle.asn1.DEROutputStream
-com.android.org.bouncycastle.asn1.DERPrintableString
-com.android.org.bouncycastle.asn1.DERSequence
-com.android.org.bouncycastle.asn1.DERSet
-com.android.org.bouncycastle.asn1.DERTaggedObject
-com.android.org.bouncycastle.asn1.DERUTF8String
-com.android.org.bouncycastle.asn1.DLSequence
-com.android.org.bouncycastle.asn1.DLSet
-com.android.org.bouncycastle.asn1.DefiniteLengthInputStream
-com.android.org.bouncycastle.asn1.InMemoryRepresentable
-com.android.org.bouncycastle.asn1.IndefiniteLengthInputStream
-com.android.org.bouncycastle.asn1.LimitedInputStream
-com.android.org.bouncycastle.asn1.StreamUtil
+com.android.org.bouncycastle.asn1.OIDTokenizer
com.android.org.bouncycastle.asn1.bc.BCObjectIdentifiers
com.android.org.bouncycastle.asn1.iana.IANAObjectIdentifiers
+com.android.org.bouncycastle.asn1.misc.MiscObjectIdentifiers
com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers
com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers
com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
-com.android.org.bouncycastle.asn1.x500.AttributeTypeAndValue
-com.android.org.bouncycastle.asn1.x500.RDN
-com.android.org.bouncycastle.asn1.x500.X500Name
-com.android.org.bouncycastle.asn1.x500.X500NameStyle
-com.android.org.bouncycastle.asn1.x500.style.AbstractX500NameStyle
-com.android.org.bouncycastle.asn1.x500.style.BCStyle
-com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier
-com.android.org.bouncycastle.asn1.x509.BasicConstraints
-com.android.org.bouncycastle.asn1.x509.Extension
-com.android.org.bouncycastle.asn1.x509.GeneralName
-com.android.org.bouncycastle.asn1.x509.GeneralNames
-com.android.org.bouncycastle.asn1.x509.PolicyInformation
-com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
-com.android.org.bouncycastle.asn1.x509.X509Extension
com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers
com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers
-com.android.org.bouncycastle.crypto.Digest
-com.android.org.bouncycastle.crypto.ExtendedDigest
-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.jcajce.PKIXExtendedParameters
-com.android.org.bouncycastle.jcajce.PKIXExtendedParameters$Builder
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
@@ -2575,40 +2788,27 @@ com.android.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
com.android.org.bouncycastle.jcajce.util.BCJcaJceHelper
com.android.org.bouncycastle.jcajce.util.JcaJceHelper
com.android.org.bouncycastle.jcajce.util.ProviderJcaJceHelper
-com.android.org.bouncycastle.jce.exception.ExtException
com.android.org.bouncycastle.jce.interfaces.BCKeyStore
-com.android.org.bouncycastle.jce.provider.AnnotatedException
com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
com.android.org.bouncycastle.jce.provider.BouncyCastleProvider$1
com.android.org.bouncycastle.jce.provider.BouncyCastleProviderConfiguration
-com.android.org.bouncycastle.jce.provider.CertBlacklist
-com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities
-com.android.org.bouncycastle.jce.provider.PKIXCRLUtil
-com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
-com.android.org.bouncycastle.jce.provider.PKIXNameConstraintValidator
-com.android.org.bouncycastle.jce.provider.PKIXNameConstraintValidatorException
-com.android.org.bouncycastle.jce.provider.PKIXPolicyNode
-com.android.org.bouncycastle.jce.provider.PrincipalUtils
-com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities
com.android.org.bouncycastle.util.Arrays
com.android.org.bouncycastle.util.Encodable
com.android.org.bouncycastle.util.Strings
-com.android.org.bouncycastle.util.encoders.Encoder
-com.android.org.bouncycastle.util.encoders.Hex
-com.android.org.bouncycastle.util.encoders.HexEncoder
-com.android.org.bouncycastle.util.io.Streams
-com.android.org.bouncycastle.x509.ExtendedPKIXParameters
+com.android.org.bouncycastle.util.Strings$1
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.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.Hex
com.android.org.conscrypt.JSSEProvider
com.android.org.conscrypt.KeyManagerFactoryImpl
com.android.org.conscrypt.KeyManagerImpl
@@ -2624,14 +2824,17 @@ 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
com.android.org.conscrypt.OpenSSLKey
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.OpenSSLProvider
+com.android.org.conscrypt.OpenSSLRSAKeyFactory
com.android.org.conscrypt.OpenSSLRSAPublicKey
com.android.org.conscrypt.OpenSSLRandom
com.android.org.conscrypt.OpenSSLSessionImpl
@@ -2651,7 +2854,6 @@ com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException
com.android.org.conscrypt.PinEntryException
com.android.org.conscrypt.PinManagerException
com.android.org.conscrypt.Platform
-com.android.org.conscrypt.Platform$OpenSSLMapper
com.android.org.conscrypt.SSLClientSessionCache
com.android.org.conscrypt.SSLParametersImpl
com.android.org.conscrypt.SSLParametersImpl$AliasChooser
@@ -2660,12 +2862,10 @@ com.android.org.conscrypt.ServerSessionContext
com.android.org.conscrypt.TrustManagerFactoryImpl
com.android.org.conscrypt.TrustManagerImpl
com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
+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$2
-com.android.org.conscrypt.TrustedCertificateStore$CertSelector
com.android.org.conscrypt.util.ArrayUtils
com.android.server.NetworkManagementSocketTagger
com.android.server.NetworkManagementSocketTagger$1
@@ -2685,6 +2885,7 @@ dalvik.system.CloseGuard$DefaultReporter
dalvik.system.CloseGuard$Reporter
dalvik.system.DalvikLogHandler
dalvik.system.DalvikLogging
+dalvik.system.DexClassLoader
dalvik.system.DexFile
dalvik.system.DexFile$DFEnum
dalvik.system.DexPathList
@@ -2696,28 +2897,41 @@ 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
java.io.BufferedReader
java.io.BufferedWriter
java.io.ByteArrayInputStream
java.io.ByteArrayOutputStream
+java.io.CharArrayWriter
java.io.Closeable
java.io.DataInput
java.io.DataInputStream
java.io.DataOutput
java.io.DataOutputStream
java.io.EOFException
+java.io.ExpiringCache
+java.io.ExpiringCache$1
+java.io.ExpiringCache$Entry
java.io.Externalizable
java.io.File
+java.io.File$PathStatus
+java.io.File$TempDirectory
java.io.FileDescriptor
-java.io.FileFilter
java.io.FileInputStream
+java.io.FileInputStream$UseManualSkipException
java.io.FileNotFoundException
java.io.FileOutputStream
java.io.FileReader
+java.io.FileSystem
+java.io.FileWriter
+java.io.FilenameFilter
java.io.FilterInputStream
java.io.FilterOutputStream
java.io.FilterReader
@@ -2727,13 +2941,17 @@ java.io.InputStream
java.io.InputStreamReader
java.io.InterruptedIOException
java.io.InvalidObjectException
+java.io.NotSerializableException
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$PutField
java.io.ObjectStreamClass
-java.io.ObjectStreamClass$5
java.io.ObjectStreamConstants
java.io.ObjectStreamException
java.io.ObjectStreamField
@@ -2745,27 +2963,32 @@ java.io.PushbackInputStream
java.io.PushbackReader
java.io.RandomAccessFile
java.io.Reader
+java.io.SequenceInputStream
java.io.Serializable
java.io.SerializablePermission
-java.io.SerializationHandleMap
+java.io.StreamCorruptedException
java.io.StringReader
java.io.StringWriter
java.io.UTFDataFormatException
+java.io.UnixFileSystem
java.io.UnsupportedEncodingException
java.io.Writer
java.lang.AbstractMethodError
java.lang.AbstractStringBuilder
java.lang.Appendable
java.lang.ArrayIndexOutOfBoundsException
+java.lang.ArrayStoreException
java.lang.AssertionError
java.lang.AutoCloseable
java.lang.Boolean
java.lang.BootClassLoader
java.lang.Byte
+java.lang.Byte$ByteCache
java.lang.CaseMapper
java.lang.CaseMapper$1
java.lang.CharSequence
java.lang.Character
+java.lang.Character$CharacterCache
java.lang.Character$Subset
java.lang.Character$UnicodeBlock
java.lang.Class
@@ -2787,24 +3010,30 @@ java.lang.DexCache
java.lang.Double
java.lang.Enum
java.lang.Enum$1
+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.IllegalAccessException
java.lang.IllegalArgumentException
java.lang.IllegalStateException
java.lang.IllegalThreadStateException
java.lang.IncompatibleClassChangeError
java.lang.IndexOutOfBoundsException
+java.lang.InheritableThreadLocal
java.lang.InstantiationException
java.lang.Integer
-java.lang.IntegralToString
-java.lang.IntegralToString$1
+java.lang.Integer$IntegerCache
java.lang.InternalError
java.lang.InterruptedException
java.lang.Iterable
+java.lang.JavaLangAccess
java.lang.LinkageError
java.lang.Long
+java.lang.Long$LongCache
java.lang.Math
java.lang.Math$NoImagePreloadHolder
java.lang.NoClassDefFoundError
@@ -2818,16 +3047,19 @@ java.lang.NumberFormatException
java.lang.Object
java.lang.OutOfMemoryError
java.lang.Package
+java.lang.Process
+java.lang.ProcessEnvironment
java.lang.Readable
-java.lang.RealToString
-java.lang.RealToString$1
java.lang.ReflectiveOperationException
java.lang.Runnable
java.lang.Runtime
java.lang.RuntimeException
java.lang.RuntimePermission
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
@@ -2835,28 +3067,40 @@ java.lang.String
java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
+java.lang.StringCoding
java.lang.StringFactory
java.lang.StringIndexOutOfBoundsException
-java.lang.StringToReal
-java.lang.StringToReal$StringExponentPair
java.lang.System
java.lang.System$PropertiesWithNonOverrideableDefaults
java.lang.Thread
+java.lang.Thread$1
+java.lang.Thread$Caches
java.lang.Thread$State
java.lang.Thread$UncaughtExceptionHandler
+java.lang.Thread$WeakClassKey
java.lang.ThreadDeath
java.lang.ThreadGroup
java.lang.ThreadLocal
-java.lang.ThreadLocal$Values
+java.lang.ThreadLocal$ThreadLocalMap
+java.lang.ThreadLocal$ThreadLocalMap$Entry
java.lang.Throwable
-java.lang.TwoEnumerationsInOne
+java.lang.Throwable$PrintStreamOrWriter
+java.lang.Throwable$SentinelHolder
+java.lang.Throwable$WrappedPrintStream
+java.lang.Throwable$WrappedPrintWriter
+java.lang.TypeNotPresentException
+java.lang.UNIXProcess
java.lang.UnsatisfiedLinkError
java.lang.UnsupportedOperationException
java.lang.VMClassLoader
java.lang.VirtualMachineError
java.lang.Void
java.lang.annotation.Annotation
+java.lang.annotation.AnnotationTypeMismatchException
+java.lang.annotation.IncompleteAnnotationException
java.lang.annotation.Inherited
+java.lang.annotation.Retention
+java.lang.annotation.Target
java.lang.ref.FinalizerReference
java.lang.ref.FinalizerReference$Sentinel
java.lang.ref.PhantomReference
@@ -2871,7 +3115,6 @@ java.lang.reflect.AnnotatedElement
java.lang.reflect.Array
java.lang.reflect.Constructor
java.lang.reflect.Field
-java.lang.reflect.Field$1
java.lang.reflect.GenericArrayType
java.lang.reflect.GenericDeclaration
java.lang.reflect.InvocationHandler
@@ -2889,52 +3132,67 @@ java.lang.reflect.WildcardType
java.math.BigDecimal
java.math.BigInt
java.math.BigInteger
+java.math.BitLevel
+java.math.Multiplication
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.ContentHandler
java.net.CookieHandler
+java.net.DatagramPacket
+java.net.DatagramSocketImpl
java.net.HttpURLConnection
+java.net.IDN
java.net.Inet4Address
java.net.Inet6Address
+java.net.Inet6AddressImpl
java.net.InetAddress
+java.net.InetAddress$1
+java.net.InetAddress$InetAddressHolder
+java.net.InetAddressImpl
java.net.InetSocketAddress
-java.net.InetUnixAddress
+java.net.InetSocketAddress$InetSocketAddressHolder
java.net.JarURLConnection
java.net.MalformedURLException
+java.net.NetworkInterface
+java.net.Parts
+java.net.PlainDatagramSocketImpl
java.net.PlainSocketImpl
java.net.ProtocolException
java.net.Proxy
java.net.Proxy$Type
java.net.ProxySelector
-java.net.ProxySelectorImpl
java.net.ResponseCache
java.net.ServerSocket
java.net.Socket
java.net.SocketAddress
java.net.SocketException
java.net.SocketImpl
+java.net.SocketInputStream
java.net.SocketOptions
+java.net.SocketOutputStream
java.net.SocketTimeoutException
+java.net.SocksConsts
+java.net.SocksSocketImpl
+java.net.SocksSocketImpl$3
java.net.URI
-java.net.URI$1
-java.net.URI$PartEncoder
+java.net.URI$Parser
java.net.URISyntaxException
java.net.URL
java.net.URLConnection
-java.net.URLConnection$DefaultContentHandler
+java.net.URLDecoder
java.net.URLEncoder
-java.net.URLEncoder$1
java.net.URLStreamHandler
java.net.URLStreamHandlerFactory
java.net.UnknownHostException
+java.nio.Bits
java.nio.Buffer
java.nio.BufferOverflowException
java.nio.BufferUnderflowException
-java.nio.ByteArrayBuffer
java.nio.ByteBuffer
java.nio.ByteBufferAsCharBuffer
java.nio.ByteBufferAsDoubleBuffer
@@ -2943,42 +3201,43 @@ java.nio.ByteBufferAsIntBuffer
java.nio.ByteBufferAsLongBuffer
java.nio.ByteBufferAsShortBuffer
java.nio.ByteOrder
-java.nio.CharArrayBuffer
java.nio.CharBuffer
-java.nio.CharSequenceAdapter
java.nio.DirectByteBuffer
+java.nio.DirectByteBuffer$MemoryRef
java.nio.DoubleBuffer
-java.nio.FileChannelImpl
-java.nio.FileChannelImpl$1
-java.nio.FileChannelImpl$FileLockImpl
java.nio.FloatBuffer
+java.nio.HeapByteBuffer
+java.nio.HeapCharBuffer
java.nio.IntBuffer
java.nio.InvalidMarkException
java.nio.LongBuffer
java.nio.MappedByteBuffer
-java.nio.MemoryBlock
-java.nio.MemoryBlock$MemoryMappedBlock
-java.nio.MemoryBlock$NonMovableHeapBlock
-java.nio.MemoryBlock$UnmanagedBlock
java.nio.NIOAccess
-java.nio.NioUtils
java.nio.ReadOnlyBufferException
java.nio.ShortBuffer
+java.nio.StringCharBuffer
java.nio.channels.AsynchronousCloseException
java.nio.channels.ByteChannel
java.nio.channels.Channel
java.nio.channels.ClosedByInterruptException
java.nio.channels.ClosedChannelException
+java.nio.channels.DatagramChannel
java.nio.channels.FileChannel
java.nio.channels.FileChannel$MapMode
java.nio.channels.FileLock
java.nio.channels.GatheringByteChannel
java.nio.channels.InterruptibleChannel
+java.nio.channels.NetworkChannel
java.nio.channels.ReadableByteChannel
java.nio.channels.ScatteringByteChannel
+java.nio.channels.SeekableByteChannel
+java.nio.channels.SelectableChannel
+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.charset.CharacterCodingException
java.nio.charset.Charset
java.nio.charset.CharsetDecoder
@@ -2987,45 +3246,62 @@ java.nio.charset.CharsetEncoder
java.nio.charset.CharsetEncoderICU
java.nio.charset.CharsetICU
java.nio.charset.CoderResult
+java.nio.charset.CoderResult$1
+java.nio.charset.CoderResult$2
+java.nio.charset.CoderResult$Cache
java.nio.charset.CodingErrorAction
java.nio.charset.IllegalCharsetNameException
-java.nio.charset.ModifiedUtf8
java.nio.charset.StandardCharsets
java.nio.charset.UnsupportedCharsetException
+java.security.AccessControlContext
java.security.AccessControlException
java.security.AccessController
+java.security.AlgorithmConstraints
+java.security.AlgorithmParameters
+java.security.AlgorithmParametersSpi
java.security.BasicPermission
-java.security.DigestException
+java.security.BasicPermissionCollection
+java.security.CryptoPrimitive
java.security.GeneralSecurityException
java.security.Guard
java.security.InvalidAlgorithmParameterException
java.security.InvalidKeyException
+java.security.InvalidParameterException
java.security.Key
java.security.KeyException
+java.security.KeyFactory
java.security.KeyFactorySpi
java.security.KeyManagementException
+java.security.KeyPair
java.security.KeyStore
+java.security.KeyStore$1
+java.security.KeyStore$LoadStoreParameter
java.security.KeyStoreException
java.security.KeyStoreSpi
java.security.MessageDigest
-java.security.MessageDigest$MessageDigestImpl
+java.security.MessageDigest$Delegate
java.security.MessageDigestSpi
java.security.NoSuchAlgorithmException
java.security.NoSuchProviderException
java.security.Permission
+java.security.PermissionCollection
java.security.Principal
java.security.PrivateKey
java.security.PrivilegedAction
+java.security.PrivilegedActionException
+java.security.PrivilegedExceptionAction
java.security.ProtectionDomain
java.security.Provider
+java.security.Provider$EngineDescription
java.security.Provider$Service
+java.security.Provider$ServiceKey
+java.security.Provider$UString
java.security.PublicKey
java.security.SecureRandom
java.security.SecureRandomSpi
java.security.Security
-java.security.Security$SecurityDoor
java.security.Signature
-java.security.Signature$SignatureImpl
+java.security.Signature$Delegate
java.security.SignatureException
java.security.SignatureSpi
java.security.UnrecoverableEntryException
@@ -3033,15 +3309,14 @@ 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
java.security.cert.CertPathValidator
java.security.cert.CertPathValidatorException
java.security.cert.CertPathValidatorResult
java.security.cert.CertPathValidatorSpi
java.security.cert.CertSelector
-java.security.cert.CertStoreException
-java.security.cert.CertStoreParameters
java.security.cert.Certificate
java.security.cert.CertificateEncodingException
java.security.cert.CertificateException
@@ -3050,11 +3325,14 @@ java.security.cert.CertificateFactory
java.security.cert.CertificateFactorySpi
java.security.cert.CertificateNotYetValidException
java.security.cert.CertificateParsingException
+java.security.cert.Extension
java.security.cert.PKIXCertPathChecker
java.security.cert.PKIXCertPathValidatorResult
java.security.cert.PKIXParameters
+java.security.cert.PKIXRevocationChecker
java.security.cert.PolicyNode
java.security.cert.TrustAnchor
+java.security.cert.X509CRL
java.security.cert.X509CertSelector
java.security.cert.X509Certificate
java.security.cert.X509Extension
@@ -3064,51 +3342,70 @@ java.security.interfaces.ECKey
java.security.interfaces.ECPrivateKey
java.security.interfaces.ECPublicKey
java.security.interfaces.RSAKey
+java.security.interfaces.RSAPrivateCrtKey
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
+java.security.spec.ECPrivateKeySpec
+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.PKCS8EncodedKeySpec
+java.security.spec.RSAPrivateCrtKeySpec
+java.security.spec.RSAPrivateKeySpec
+java.security.spec.RSAPublicKeySpec
+java.security.spec.X509EncodedKeySpec
+java.sql.Timestamp
java.text.AttributedCharacterIterator$Attribute
-java.text.Bidi
-java.text.Bidi$Run
+java.text.CalendarBuilder
java.text.Collator
java.text.DateFormat
java.text.DateFormat$Field
java.text.DateFormatSymbols
java.text.DecimalFormat
java.text.DecimalFormatSymbols
+java.text.DontCareFieldPosition
+java.text.DontCareFieldPosition$1
java.text.FieldPosition
java.text.Format
java.text.Format$Field
+java.text.Format$FieldDelegate
+java.text.Normalizer
+java.text.Normalizer$Form
java.text.NumberFormat
-java.text.NumberFormat$Field
java.text.ParseException
java.text.ParsePosition
java.text.RuleBasedCollator
java.text.SimpleDateFormat
+java.text.spi.DateFormatProvider
+java.text.spi.DateFormatSymbolsProvider
+java.text.spi.DecimalFormatSymbolsProvider
+java.text.spi.NumberFormatProvider
java.util.AbstractCollection
java.util.AbstractList
-java.util.AbstractList$FullListIterator
-java.util.AbstractList$SimpleListIterator
-java.util.AbstractList$SubAbstractList
-java.util.AbstractList$SubAbstractListRandomAccess
+java.util.AbstractList$Itr
+java.util.AbstractList$ListItr
java.util.AbstractMap
java.util.AbstractMap$1
java.util.AbstractMap$2
-java.util.AbstractMap$2$1
+java.util.AbstractMap$SimpleImmutableEntry
java.util.AbstractQueue
java.util.AbstractSequentialList
java.util.AbstractSet
java.util.ArrayDeque
java.util.ArrayList
-java.util.ArrayList$ArrayListIterator
+java.util.ArrayList$Itr
+java.util.ArrayList$ListItr
+java.util.ArrayList$SubList
+java.util.ArrayList$SubList$1
java.util.Arrays
java.util.Arrays$ArrayList
java.util.BitSet
@@ -3117,7 +3414,6 @@ java.util.Collection
java.util.Collections
java.util.Collections$1
java.util.Collections$2
-java.util.Collections$3
java.util.Collections$AsLIFOQueue
java.util.Collections$CheckedCollection
java.util.Collections$CheckedList
@@ -3127,7 +3423,10 @@ java.util.Collections$CheckedSet
java.util.Collections$CheckedSortedMap
java.util.Collections$CheckedSortedSet
java.util.Collections$CopiesList
+java.util.Collections$EmptyEnumeration
+java.util.Collections$EmptyIterator
java.util.Collections$EmptyList
+java.util.Collections$EmptyListIterator
java.util.Collections$EmptyMap
java.util.Collections$EmptySet
java.util.Collections$ReverseComparator
@@ -3136,7 +3435,6 @@ java.util.Collections$SetFromMap
java.util.Collections$SingletonList
java.util.Collections$SingletonMap
java.util.Collections$SingletonSet
-java.util.Collections$SingletonSet$1
java.util.Collections$SynchronizedCollection
java.util.Collections$SynchronizedList
java.util.Collections$SynchronizedMap
@@ -3147,10 +3445,11 @@ java.util.Collections$SynchronizedSortedSet
java.util.Collections$UnmodifiableCollection
java.util.Collections$UnmodifiableCollection$1
java.util.Collections$UnmodifiableList
+java.util.Collections$UnmodifiableList$1
java.util.Collections$UnmodifiableMap
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableMapEntry
+java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry
java.util.Collections$UnmodifiableRandomAccessList
java.util.Collections$UnmodifiableSet
java.util.Collections$UnmodifiableSortedMap
@@ -3164,110 +3463,139 @@ java.util.Deque
java.util.Dictionary
java.util.DualPivotQuicksort
java.util.EnumMap
+java.util.EnumMap$1
+java.util.EnumMap$EnumMapIterator
java.util.EnumSet
java.util.Enumeration
java.util.EventListener
java.util.EventObject
java.util.Formattable
java.util.Formatter
-java.util.Formatter$1
-java.util.Formatter$CachedDecimalFormat
+java.util.Formatter$Conversion
+java.util.Formatter$FixedString
+java.util.Formatter$Flags
+java.util.Formatter$FormatSpecifier
java.util.Formatter$FormatSpecifierParser
-java.util.Formatter$FormatToken
+java.util.Formatter$FormatString
java.util.GregorianCalendar
java.util.HashMap
java.util.HashMap$EntryIterator
java.util.HashMap$EntrySet
java.util.HashMap$HashIterator
java.util.HashMap$HashMapEntry
+java.util.HashMap$Holder
java.util.HashMap$KeyIterator
java.util.HashMap$KeySet
java.util.HashMap$ValueIterator
java.util.HashMap$Values
java.util.HashSet
java.util.Hashtable
-java.util.Hashtable$HashIterator
+java.util.Hashtable$EntrySet
+java.util.Hashtable$Enumerator
java.util.Hashtable$HashtableEntry
-java.util.Hashtable$KeyEnumeration
-java.util.Hashtable$ValueIterator
-java.util.Hashtable$Values
+java.util.Hashtable$Holder
+java.util.Hashtable$KeySet
+java.util.Hashtable$ValueCollection
java.util.IdentityHashMap
+java.util.IdentityHashMap$EntryIterator
+java.util.IdentityHashMap$EntrySet
java.util.IdentityHashMap$IdentityHashMapIterator
+java.util.IdentityHashMap$KeySet
java.util.IllegalFormatException
java.util.IllformedLocaleException
java.util.Iterator
java.util.LinkedHashMap
java.util.LinkedHashMap$EntryIterator
java.util.LinkedHashMap$KeyIterator
-java.util.LinkedHashMap$LinkedEntry
java.util.LinkedHashMap$LinkedHashIterator
+java.util.LinkedHashMap$LinkedHashMapEntry
java.util.LinkedHashMap$ValueIterator
java.util.LinkedHashSet
java.util.LinkedList
-java.util.LinkedList$Link
-java.util.LinkedList$LinkIterator
+java.util.LinkedList$ListItr
+java.util.LinkedList$Node
java.util.List
java.util.ListIterator
java.util.Locale
java.util.Locale$Builder
-java.util.Locale$NoImagePreloadHolder
+java.util.Locale$Cache
+java.util.Locale$Category
+java.util.Locale$LocaleKey
java.util.Map
java.util.Map$Entry
-java.util.MapEntry
-java.util.MapEntry$Type
-java.util.MiniEnumSet
-java.util.MiniEnumSet$MiniEnumSetIterator
java.util.MissingResourceException
java.util.NavigableMap
java.util.NavigableSet
java.util.NoSuchElementException
java.util.Objects
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$MissingBundle
+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.Scanner
+java.util.ServiceLoader
+java.util.ServiceLoader$1
+java.util.ServiceLoader$LazyIterator
java.util.Set
java.util.SimpleTimeZone
java.util.SortedMap
java.util.SortedSet
java.util.Stack
java.util.StringTokenizer
+java.util.SubList
+java.util.TaskQueue
java.util.TimSort
java.util.TimeZone
java.util.Timer
-java.util.Timer$FinalizerHelper
-java.util.Timer$TimerImpl
-java.util.Timer$TimerImpl$TimerHeap
+java.util.Timer$1
java.util.TimerTask
+java.util.TimerThread
java.util.TreeMap
-java.util.TreeMap$1
-java.util.TreeMap$Bound
-java.util.TreeMap$Bound$1
-java.util.TreeMap$Bound$2
-java.util.TreeMap$Bound$3
-java.util.TreeMap$BoundedMap
-java.util.TreeMap$BoundedMap$BoundedIterator
+java.util.TreeMap$AscendingSubMap
+java.util.TreeMap$EntryIterator
java.util.TreeMap$EntrySet
-java.util.TreeMap$EntrySet$1
+java.util.TreeMap$KeyIterator
java.util.TreeMap$KeySet
-java.util.TreeMap$KeySet$1
-java.util.TreeMap$MapIterator
-java.util.TreeMap$Node
-java.util.TreeMap$Relation
+java.util.TreeMap$NavigableSubMap
+java.util.TreeMap$PrivateEntryIterator
+java.util.TreeMap$TreeMapEntry
+java.util.TreeMap$ValueIterator
+java.util.TreeMap$Values
java.util.TreeSet
java.util.UUID
+java.util.UUID$Holder
java.util.Vector
java.util.Vector$1
+java.util.Vector$Itr
java.util.WeakHashMap
-java.util.WeakHashMap$2
-java.util.WeakHashMap$2$1
java.util.WeakHashMap$Entry
-java.util.WeakHashMap$Entry$Type
+java.util.WeakHashMap$EntrySet
java.util.WeakHashMap$HashIterator
+java.util.WeakHashMap$Holder
+java.util.WeakHashMap$KeyIterator
+java.util.WeakHashMap$KeySet
+java.util.WeakHashMap$Values
+java.util.XMLUtils
java.util.concurrent.AbstractExecutorService
+java.util.concurrent.ArrayBlockingQueue
java.util.concurrent.BlockingQueue
java.util.concurrent.Callable
java.util.concurrent.CancellationException
@@ -3283,6 +3611,8 @@ 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
@@ -3340,6 +3670,8 @@ java.util.concurrent.atomic.AtomicBoolean
java.util.concurrent.atomic.AtomicInteger
java.util.concurrent.atomic.AtomicLong
java.util.concurrent.atomic.AtomicReference
+java.util.concurrent.atomic.AtomicReferenceFieldUpdater
+java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl
java.util.concurrent.locks.AbstractOwnableSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
@@ -3357,31 +3689,38 @@ 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.jar.Attributes
-java.util.jar.Attributes$Name
java.util.jar.JarEntry
java.util.jar.JarFile
-java.util.jar.JarFile$JarFileEnumerator
-java.util.logging.ConsoleHandler
+java.util.jar.JarFile$1
+java.util.jar.JarFile$JarFileEntry
java.util.logging.ErrorManager
-java.util.logging.Filter
java.util.logging.Formatter
java.util.logging.Handler
java.util.logging.Level
+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$Cleaner
+java.util.logging.LogManager$LogNode
+java.util.logging.LogManager$LoggerContext
+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$1
java.util.logging.LoggingPermission
-java.util.logging.SimpleFormatter
-java.util.logging.StreamHandler
+java.util.logging.LoggingProxyImpl
java.util.regex.MatchResult
java.util.regex.Matcher
java.util.regex.Pattern
java.util.regex.PatternSyntaxException
-java.util.regex.Splitter
+java.util.spi.LocaleServiceProvider
java.util.zip.Adler32
java.util.zip.CRC32
+java.util.zip.CheckedInputStream
java.util.zip.Checksum
java.util.zip.DataFormatException
java.util.zip.Deflater
@@ -3390,26 +3729,38 @@ java.util.zip.GZIPInputStream
java.util.zip.GZIPOutputStream
java.util.zip.Inflater
java.util.zip.InflaterInputStream
-java.util.zip.Zip64
+java.util.zip.ZStreamRef
+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$EocdRecord
-java.util.zip.ZipFile$RAFStream
-java.util.zip.ZipFile$ZipInflaterInputStream
+java.util.zip.ZipFile$ZipFileInflaterInputStream
+java.util.zip.ZipFile$ZipFileInputStream
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.Mac
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
javax.microedition.khronos.egl.EGL10
+javax.microedition.khronos.egl.EGLConfig
+javax.microedition.khronos.egl.EGLContext
+javax.microedition.khronos.egl.EGLDisplay
+javax.microedition.khronos.egl.EGLSurface
javax.microedition.khronos.opengles.GL
javax.microedition.khronos.opengles.GL10
javax.microedition.khronos.opengles.GL10Ext
@@ -3419,56 +3770,61 @@ javax.microedition.khronos.opengles.GL11ExtensionPack
javax.net.DefaultSocketFactory
javax.net.ServerSocketFactory
javax.net.SocketFactory
-javax.net.ssl.DistinguishedNameParser
+javax.net.ssl.ExtendedSSLSession
+javax.net.ssl.HandshakeCompletedEvent
javax.net.ssl.HandshakeCompletedListener
javax.net.ssl.HostnameVerifier
javax.net.ssl.HttpsURLConnection
javax.net.ssl.KeyManager
javax.net.ssl.KeyManagerFactory
+javax.net.ssl.KeyManagerFactory$1
javax.net.ssl.KeyManagerFactorySpi
javax.net.ssl.SSLContext
javax.net.ssl.SSLContextSpi
javax.net.ssl.SSLEngine
javax.net.ssl.SSLException
+javax.net.ssl.SSLHandshakeException
+javax.net.ssl.SSLParameters
javax.net.ssl.SSLPeerUnverifiedException
javax.net.ssl.SSLProtocolException
+javax.net.ssl.SSLServerSocket
javax.net.ssl.SSLServerSocketFactory
javax.net.ssl.SSLSession
+javax.net.ssl.SSLSessionBindingEvent
+javax.net.ssl.SSLSessionBindingListener
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
javax.net.ssl.TrustManagerFactorySpi
javax.net.ssl.X509ExtendedKeyManager
+javax.net.ssl.X509ExtendedTrustManager
javax.net.ssl.X509KeyManager
javax.net.ssl.X509TrustManager
+javax.security.auth.callback.UnsupportedCallbackException
javax.security.auth.x500.X500Principal
javax.security.cert.Certificate
javax.security.cert.CertificateException
javax.security.cert.X509Certificate
javax.xml.parsers.ParserConfigurationException
-libcore.icu.AlphabeticIndex
-libcore.icu.AlphabeticIndex$ImmutableIndex
+javax.xml.transform.TransformerConfigurationException
+javax.xml.transform.TransformerException
libcore.icu.DateIntervalFormat
-libcore.icu.DateIntervalFormat$FormatterCache
libcore.icu.DateUtilsBridge
libcore.icu.ICU
libcore.icu.LocaleData
-libcore.icu.NativeCollation
libcore.icu.NativeConverter
-libcore.icu.NativeDecimalFormat
-libcore.icu.NativeDecimalFormat$FieldPositionIterator
-libcore.icu.NativeIDN
-libcore.icu.NativeNormalizer
-libcore.icu.NativePluralRules
-libcore.icu.RuleBasedCollatorICU
libcore.icu.TimeZoneNames
-libcore.icu.Transliterator
libcore.internal.StringPool
libcore.io.AsynchronousCloseMonitor
libcore.io.BlockGuardOs
libcore.io.BufferIterator
+libcore.io.ClassPathURLStreamHandler
+libcore.io.ClassPathURLStreamHandler$ClassPathURLConnection
+libcore.io.ClassPathURLStreamHandler$ClassPathURLConnection$1
libcore.io.DropBox
libcore.io.DropBox$DefaultReporter
libcore.io.DropBox$Reporter
@@ -3476,7 +3832,6 @@ libcore.io.EventLogger
libcore.io.EventLogger$DefaultReporter
libcore.io.EventLogger$Reporter
libcore.io.ForwardingOs
-libcore.io.HeapBufferIterator
libcore.io.IoBridge
libcore.io.IoUtils
libcore.io.IoUtils$FileReader
@@ -3486,19 +3841,13 @@ libcore.io.MemoryMappedFile
libcore.io.NioBufferIterator
libcore.io.Os
libcore.io.Posix
-libcore.io.Streams
libcore.math.MathUtils
libcore.net.NetworkSecurityPolicy
+libcore.net.NetworkSecurityPolicy$DefaultNetworkSecurityPolicy
libcore.net.UriCodec
libcore.net.event.NetworkEventDispatcher
libcore.net.event.NetworkEventListener
-libcore.net.url.FileHandler
-libcore.net.url.FileURLConnection
-libcore.net.url.FileURLConnection$1
-libcore.net.url.JarHandler
-libcore.net.url.JarURLConnectionImpl
-libcore.net.url.JarURLConnectionImpl$JarURLConnectionInputStream
-libcore.net.url.UrlUtils
+libcore.reflect.AnnotatedElements
libcore.reflect.AnnotationAccess
libcore.reflect.AnnotationFactory
libcore.reflect.AnnotationMember
@@ -3508,13 +3857,15 @@ libcore.reflect.InternalNames
libcore.reflect.ListOfTypes
libcore.reflect.ListOfVariables
libcore.reflect.ParameterizedTypeImpl
+libcore.reflect.TypeVariableImpl
libcore.reflect.Types
libcore.util.BasicLruCache
libcore.util.CharsetUtils
libcore.util.CollectionUtils
-libcore.util.CollectionUtils$1
-libcore.util.CollectionUtils$1$1
libcore.util.EmptyArray
+libcore.util.NativeAllocationRegistry
+libcore.util.NativeAllocationRegistry$CleanerRunner
+libcore.util.NativeAllocationRegistry$CleanerThunk
libcore.util.Objects
libcore.util.ZoneInfo
libcore.util.ZoneInfo$CheckedArithmeticException
@@ -3522,280 +3873,66 @@ libcore.util.ZoneInfo$WallTime
libcore.util.ZoneInfoDB
libcore.util.ZoneInfoDB$TzData
libcore.util.ZoneInfoDB$TzData$1
-org.apache.commons.logging.Log
-org.apache.commons.logging.LogFactory
-org.apache.commons.logging.impl.Jdk14Logger
-org.apache.commons.logging.impl.WeakHashtable
org.apache.harmony.dalvik.NativeTestTarget
org.apache.harmony.dalvik.ddmc.Chunk
org.apache.harmony.dalvik.ddmc.ChunkHandler
org.apache.harmony.dalvik.ddmc.DdmServer
org.apache.harmony.dalvik.ddmc.DdmVmInternal
org.apache.harmony.luni.internal.util.TimezoneGetter
-org.apache.harmony.security.asn1.ASN1Any
-org.apache.harmony.security.asn1.ASN1Choice
-org.apache.harmony.security.asn1.ASN1Constants
-org.apache.harmony.security.asn1.ASN1Constructed
-org.apache.harmony.security.asn1.ASN1Oid
-org.apache.harmony.security.asn1.ASN1Oid$1
-org.apache.harmony.security.asn1.ASN1Primitive
-org.apache.harmony.security.asn1.ASN1Sequence
-org.apache.harmony.security.asn1.ASN1SequenceOf
-org.apache.harmony.security.asn1.ASN1SetOf
-org.apache.harmony.security.asn1.ASN1StringType
-org.apache.harmony.security.asn1.ASN1StringType$1
-org.apache.harmony.security.asn1.ASN1StringType$2
-org.apache.harmony.security.asn1.ASN1StringType$3
-org.apache.harmony.security.asn1.ASN1StringType$4
-org.apache.harmony.security.asn1.ASN1StringType$5
-org.apache.harmony.security.asn1.ASN1StringType$6
-org.apache.harmony.security.asn1.ASN1StringType$7
-org.apache.harmony.security.asn1.ASN1StringType$ASN1StringUTF8Type
-org.apache.harmony.security.asn1.ASN1Type
-org.apache.harmony.security.asn1.ASN1TypeCollection
-org.apache.harmony.security.asn1.ASN1ValueCollection
-org.apache.harmony.security.asn1.BerInputStream
-org.apache.harmony.security.asn1.BerOutputStream
-org.apache.harmony.security.asn1.DerInputStream
-org.apache.harmony.security.asn1.DerOutputStream
-org.apache.harmony.security.provider.crypto.CryptoProvider
-org.apache.harmony.security.utils.AlgNameMapper
-org.apache.harmony.security.utils.AlgNameMapperSource
-org.apache.harmony.security.utils.ObjectIdentifier
-org.apache.harmony.security.x501.AttributeTypeAndValue
-org.apache.harmony.security.x501.AttributeTypeAndValue$1
-org.apache.harmony.security.x501.AttributeTypeAndValue$2
-org.apache.harmony.security.x501.AttributeTypeAndValueComparator
-org.apache.harmony.security.x501.AttributeValue
-org.apache.harmony.security.x501.DirectoryString
-org.apache.harmony.security.x501.DirectoryString$1
-org.apache.harmony.security.x501.Name
-org.apache.harmony.security.x501.Name$1
org.apache.harmony.xml.ExpatAttributes
org.apache.harmony.xml.ExpatParser
-org.apache.http.ConnectionReuseStrategy
-org.apache.http.FormattedHeader
org.apache.http.Header
-org.apache.http.HeaderElement
-org.apache.http.HeaderElementIterator
org.apache.http.HeaderIterator
-org.apache.http.HttpClientConnection
-org.apache.http.HttpConnection
-org.apache.http.HttpConnectionMetrics
org.apache.http.HttpEntity
org.apache.http.HttpEntityEnclosingRequest
org.apache.http.HttpException
org.apache.http.HttpHost
-org.apache.http.HttpInetConnection
org.apache.http.HttpMessage
org.apache.http.HttpRequest
-org.apache.http.HttpRequestInterceptor
org.apache.http.HttpResponse
-org.apache.http.HttpResponseFactory
-org.apache.http.HttpResponseInterceptor
org.apache.http.HttpVersion
org.apache.http.NameValuePair
-org.apache.http.ParseException
org.apache.http.ProtocolException
org.apache.http.ProtocolVersion
org.apache.http.ReasonPhraseCatalog
-org.apache.http.RequestLine
org.apache.http.StatusLine
-org.apache.http.auth.AuthSchemeFactory
-org.apache.http.auth.AuthSchemeRegistry
-org.apache.http.auth.AuthState
-org.apache.http.auth.AuthenticationException
-org.apache.http.client.AuthenticationHandler
-org.apache.http.client.CookieStore
-org.apache.http.client.CredentialsProvider
+org.apache.http.client.ClientProtocolException
org.apache.http.client.HttpClient
-org.apache.http.client.HttpRequestRetryHandler
-org.apache.http.client.RedirectHandler
-org.apache.http.client.RequestDirector
org.apache.http.client.ResponseHandler
-org.apache.http.client.UserTokenHandler
org.apache.http.client.methods.AbortableHttpRequest
org.apache.http.client.methods.HttpEntityEnclosingRequestBase
org.apache.http.client.methods.HttpGet
org.apache.http.client.methods.HttpPost
org.apache.http.client.methods.HttpRequestBase
org.apache.http.client.methods.HttpUriRequest
-org.apache.http.client.params.HttpClientParams
-org.apache.http.client.protocol.RequestAddCookies
-org.apache.http.client.protocol.RequestDefaultHeaders
-org.apache.http.client.protocol.RequestProxyAuthentication
-org.apache.http.client.protocol.RequestTargetAuthentication
-org.apache.http.client.protocol.ResponseProcessCookies
-org.apache.http.client.utils.URIUtils
-org.apache.http.conn.BasicManagedEntity
+org.apache.http.client.utils.URLEncodedUtils
org.apache.http.conn.ClientConnectionManager
-org.apache.http.conn.ClientConnectionOperator
-org.apache.http.conn.ClientConnectionRequest
org.apache.http.conn.ConnectTimeoutException
-org.apache.http.conn.ConnectionKeepAliveStrategy
-org.apache.http.conn.ConnectionReleaseTrigger
-org.apache.http.conn.EofSensorInputStream
-org.apache.http.conn.EofSensorWatcher
-org.apache.http.conn.ManagedClientConnection
-org.apache.http.conn.OperatedClientConnection
org.apache.http.conn.params.ConnManagerPNames
org.apache.http.conn.params.ConnManagerParams
org.apache.http.conn.params.ConnManagerParams$1
org.apache.http.conn.params.ConnPerRoute
-org.apache.http.conn.params.ConnPerRouteBean
-org.apache.http.conn.params.ConnRoutePNames
-org.apache.http.conn.params.ConnRouteParams
-org.apache.http.conn.routing.BasicRouteDirector
-org.apache.http.conn.routing.HttpRoute
-org.apache.http.conn.routing.HttpRouteDirector
-org.apache.http.conn.routing.HttpRoutePlanner
-org.apache.http.conn.routing.RouteInfo
-org.apache.http.conn.routing.RouteInfo$LayerType
-org.apache.http.conn.routing.RouteInfo$TunnelType
-org.apache.http.conn.routing.RouteTracker
org.apache.http.conn.scheme.LayeredSocketFactory
-org.apache.http.conn.scheme.PlainSocketFactory
-org.apache.http.conn.scheme.Scheme
-org.apache.http.conn.scheme.SchemeRegistry
org.apache.http.conn.scheme.SocketFactory
-org.apache.http.conn.ssl.AbstractVerifier
-org.apache.http.conn.ssl.AllowAllHostnameVerifier
-org.apache.http.conn.ssl.BrowserCompatHostnameVerifier
-org.apache.http.conn.ssl.SSLSocketFactory
-org.apache.http.conn.ssl.StrictHostnameVerifier
-org.apache.http.conn.ssl.X509HostnameVerifier
-org.apache.http.cookie.CookieSpecFactory
-org.apache.http.cookie.CookieSpecRegistry
-org.apache.http.cookie.MalformedCookieException
org.apache.http.entity.AbstractHttpEntity
org.apache.http.entity.BasicHttpEntity
org.apache.http.entity.ByteArrayEntity
-org.apache.http.entity.ContentLengthStrategy
-org.apache.http.entity.HttpEntityWrapper
-org.apache.http.impl.AbstractHttpClientConnection
-org.apache.http.impl.DefaultConnectionReuseStrategy
-org.apache.http.impl.DefaultHttpResponseFactory
-org.apache.http.impl.EnglishReasonPhraseCatalog
-org.apache.http.impl.HttpConnectionMetricsImpl
-org.apache.http.impl.SocketHttpClientConnection
-org.apache.http.impl.auth.BasicSchemeFactory
-org.apache.http.impl.auth.DigestSchemeFactory
-org.apache.http.impl.client.AbstractAuthenticationHandler
-org.apache.http.impl.client.AbstractHttpClient
-org.apache.http.impl.client.BasicCredentialsProvider
-org.apache.http.impl.client.ClientParamsStack
-org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy
-org.apache.http.impl.client.DefaultHttpClient
-org.apache.http.impl.client.DefaultHttpRequestRetryHandler
-org.apache.http.impl.client.DefaultProxyAuthenticationHandler
-org.apache.http.impl.client.DefaultRedirectHandler
-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.RequestWrapper
-org.apache.http.impl.client.RoutedRequest
-org.apache.http.impl.client.TunnelRefusedException
-org.apache.http.impl.conn.AbstractClientConnAdapter
-org.apache.http.impl.conn.AbstractPoolEntry
-org.apache.http.impl.conn.AbstractPooledConnAdapter
-org.apache.http.impl.conn.DefaultClientConnection
-org.apache.http.impl.conn.DefaultClientConnectionOperator
-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.tsccm.AbstractConnPool
-org.apache.http.impl.conn.tsccm.BasicPoolEntry
-org.apache.http.impl.conn.tsccm.BasicPoolEntryRef
-org.apache.http.impl.conn.tsccm.BasicPooledConnAdapter
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1
-org.apache.http.impl.conn.tsccm.PoolEntryRequest
-org.apache.http.impl.conn.tsccm.RefQueueHandler
-org.apache.http.impl.conn.tsccm.RefQueueWorker
-org.apache.http.impl.conn.tsccm.RouteSpecificPool
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1
-org.apache.http.impl.conn.tsccm.WaitingThreadAborter
-org.apache.http.impl.cookie.BestMatchSpecFactory
-org.apache.http.impl.cookie.BrowserCompatSpecFactory
org.apache.http.impl.cookie.DateParseException
-org.apache.http.impl.cookie.NetscapeDraftSpecFactory
-org.apache.http.impl.cookie.RFC2109SpecFactory
-org.apache.http.impl.cookie.RFC2965SpecFactory
-org.apache.http.impl.entity.EntityDeserializer
-org.apache.http.impl.entity.EntitySerializer
-org.apache.http.impl.entity.LaxContentLengthStrategy
-org.apache.http.impl.entity.StrictContentLengthStrategy
-org.apache.http.impl.io.AbstractMessageParser
-org.apache.http.impl.io.AbstractMessageWriter
-org.apache.http.impl.io.AbstractSessionInputBuffer
-org.apache.http.impl.io.AbstractSessionOutputBuffer
-org.apache.http.impl.io.ChunkedInputStream
-org.apache.http.impl.io.ContentLengthOutputStream
-org.apache.http.impl.io.HttpRequestWriter
-org.apache.http.impl.io.HttpTransportMetricsImpl
-org.apache.http.impl.io.SocketInputBuffer
-org.apache.http.impl.io.SocketOutputBuffer
-org.apache.http.io.HttpMessageParser
-org.apache.http.io.HttpMessageWriter
-org.apache.http.io.HttpTransportMetrics
-org.apache.http.io.SessionInputBuffer
-org.apache.http.io.SessionOutputBuffer
+org.apache.http.impl.cookie.DateUtils
org.apache.http.message.AbstractHttpMessage
org.apache.http.message.BasicHeader
-org.apache.http.message.BasicHeaderElement
-org.apache.http.message.BasicHeaderElementIterator
-org.apache.http.message.BasicHeaderValueParser
org.apache.http.message.BasicHttpResponse
-org.apache.http.message.BasicLineFormatter
-org.apache.http.message.BasicLineParser
-org.apache.http.message.BasicListHeaderIterator
org.apache.http.message.BasicNameValuePair
-org.apache.http.message.BasicRequestLine
org.apache.http.message.BasicStatusLine
-org.apache.http.message.BufferedHeader
org.apache.http.message.HeaderGroup
-org.apache.http.message.HeaderValueParser
-org.apache.http.message.LineFormatter
-org.apache.http.message.LineParser
-org.apache.http.message.ParserCursor
org.apache.http.params.AbstractHttpParams
org.apache.http.params.BasicHttpParams
org.apache.http.params.CoreConnectionPNames
-org.apache.http.params.CoreProtocolPNames
org.apache.http.params.HttpConnectionParams
org.apache.http.params.HttpParams
-org.apache.http.params.HttpProtocolParams
-org.apache.http.protocol.BasicHttpContext
-org.apache.http.protocol.BasicHttpProcessor
-org.apache.http.protocol.HTTP
org.apache.http.protocol.HttpContext
-org.apache.http.protocol.HttpProcessor
-org.apache.http.protocol.HttpRequestExecutor
-org.apache.http.protocol.HttpRequestInterceptorList
-org.apache.http.protocol.HttpResponseInterceptorList
-org.apache.http.protocol.RequestConnControl
-org.apache.http.protocol.RequestContent
-org.apache.http.protocol.RequestExpectContinue
-org.apache.http.protocol.RequestTargetHost
-org.apache.http.protocol.RequestUserAgent
-org.apache.http.util.ByteArrayBuffer
-org.apache.http.util.CharArrayBuffer
-org.apache.http.util.LangUtils
-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
@@ -3817,9 +3954,218 @@ 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.misc.Cleaner
+sun.misc.CompoundEnumeration
+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.REException
sun.misc.Unsafe
+sun.misc.VM
+sun.misc.Version
+sun.net.ConnectionResetException
+sun.net.NetHooks
+sun.net.NetProperties
+sun.net.NetProperties$1
+sun.net.spi.DefaultProxySelector
+sun.net.spi.DefaultProxySelector$1
+sun.net.spi.DefaultProxySelector$2
+sun.net.spi.DefaultProxySelector$NonProxyInfo
+sun.net.spi.nameservice.NameService
+sun.net.util.IPAddressUtil
+sun.net.www.ParseUtil
+sun.net.www.protocol.file.Handler
+sun.net.www.protocol.jar.Handler
+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
+sun.nio.ch.FileDispatcherImpl
+sun.nio.ch.FileKey
+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.SelChImpl
+sun.nio.ch.ServerSocketChannelImpl
+sun.nio.ch.SharedFileLockTable
+sun.nio.ch.SharedFileLockTable$FileLockReference
+sun.nio.ch.SocketChannelImpl
+sun.nio.ch.Util
+sun.nio.ch.Util$1
+sun.nio.cs.ArrayDecoder
+sun.nio.cs.ArrayEncoder
+sun.nio.cs.StreamDecoder
+sun.nio.cs.StreamEncoder
+sun.nio.cs.ThreadLocalCoders
+sun.nio.cs.ThreadLocalCoders$1
+sun.nio.cs.ThreadLocalCoders$2
+sun.nio.cs.ThreadLocalCoders$Cache
+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
+sun.security.jca.ProviderConfig$2
+sun.security.jca.ProviderList
+sun.security.jca.ProviderList$1
+sun.security.jca.ProviderList$2
+sun.security.jca.ProviderList$3
+sun.security.jca.ProviderList$ServiceList
+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
+sun.security.provider.certpath.AdaptableX509CertSelector
+sun.security.provider.certpath.AlgorithmChecker
+sun.security.provider.certpath.BasicChecker
+sun.security.provider.certpath.CertPathHelper
+sun.security.provider.certpath.ConstraintsChecker
+sun.security.provider.certpath.KeyChecker
+sun.security.provider.certpath.PKIX
+sun.security.provider.certpath.PKIX$ValidatorParams
+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.BitArray
+sun.security.util.ByteArrayLexOrder
+sun.security.util.ByteArrayTagOrder
+sun.security.util.Cache
+sun.security.util.Cache$EqualByteArray
+sun.security.util.Debug
+sun.security.util.DerEncoder
+sun.security.util.DerIndefLenConverter
+sun.security.util.DerInputBuffer
+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
+sun.security.util.KeyUtil
+sun.security.util.Length
+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
+sun.security.x509.AlgorithmId
+sun.security.x509.AuthorityInfoAccessExtension
+sun.security.x509.AuthorityKeyIdentifierExtension
+sun.security.x509.BasicConstraintsExtension
+sun.security.x509.CRLDistributionPointsExtension
+sun.security.x509.CRLNumberExtension
+sun.security.x509.CRLReasonCodeExtension
+sun.security.x509.CertAttrSet
+sun.security.x509.CertificateAlgorithmId
+sun.security.x509.CertificateExtensions
+sun.security.x509.CertificateIssuerExtension
+sun.security.x509.CertificatePoliciesExtension
+sun.security.x509.CertificatePolicyId
+sun.security.x509.CertificateSerialNumber
+sun.security.x509.CertificateValidity
+sun.security.x509.CertificateVersion
+sun.security.x509.CertificateX509Key
+sun.security.x509.DNSName
+sun.security.x509.DeltaCRLIndicatorExtension
+sun.security.x509.DistributionPoint
+sun.security.x509.ExtendedKeyUsageExtension
+sun.security.x509.Extension
+sun.security.x509.FreshestCRLExtension
+sun.security.x509.GeneralName
+sun.security.x509.GeneralNameInterface
+sun.security.x509.GeneralNames
+sun.security.x509.InhibitAnyPolicyExtension
+sun.security.x509.IssuerAlternativeNameExtension
+sun.security.x509.IssuingDistributionPointExtension
+sun.security.x509.KeyIdentifier
+sun.security.x509.KeyUsageExtension
+sun.security.x509.NameConstraintsExtension
+sun.security.x509.NetscapeCertTypeExtension
+sun.security.x509.OCSPNoCheckExtension
+sun.security.x509.OIDMap
+sun.security.x509.OIDMap$OIDInfo
+sun.security.x509.PKIXExtensions
+sun.security.x509.PolicyConstraintsExtension
+sun.security.x509.PolicyInformation
+sun.security.x509.PolicyMappingsExtension
+sun.security.x509.PrivateKeyUsageExtension
+sun.security.x509.RDN
+sun.security.x509.SerialNumber
+sun.security.x509.SubjectAlternativeNameExtension
+sun.security.x509.SubjectInfoAccessExtension
+sun.security.x509.SubjectKeyIdentifierExtension
+sun.security.x509.URIName
+sun.security.x509.X500Name
+sun.security.x509.X500Name$1
+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.Gregorian
+sun.util.calendar.Gregorian$Date
+sun.util.calendar.JulianCalendar
+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
+sun.util.logging.PlatformLogger
+sun.util.logging.PlatformLogger$1
+sun.util.logging.PlatformLogger$Level
diff --git a/proto/jarjar-rules.txt b/proto/jarjar-rules.txt
index 0c77c2a4a41f..50220b42b9dc 100644
--- a/proto/jarjar-rules.txt
+++ b/proto/jarjar-rules.txt
@@ -1 +1,2 @@
-rule com.google.** com.android.@1
+rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
+
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 3327ec4f712f..471feef15e6c 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -318,10 +318,10 @@ message MetricsEvent {
OVERVIEW_HISTORY = 275;
// Logged when the user pages through overview.
- ACTION_OVERVIEW_PAGE = 276;
+ OVERVIEW_PAGE = 276;
// Logged when the user launches a task from overview.
- ACTION_OVERVIEW_SELECT = 277;
+ OVERVIEW_SELECT = 277;
// Logged when the user views the emergency info.
ACTION_VIEW_EMERGENCY_INFO = 278;
@@ -353,5 +353,130 @@ message MetricsEvent {
// Logged when the user undocks a previously docked window by long pressing recents while in
// docked mode.
ACTION_WINDOW_UNDOCK_LONGPRESS = 286;
+
+ // Logged when the user scrolls through overview manually
+ OVERVIEW_SCROLL = 287;
+
+ // Logged when the overview times out automatically selecting an app
+ OVERVIEW_SELECT_TIMEOUT = 288;
+
+ // Logged when a user dismisses a task in overview
+ OVERVIEW_DISMISS = 289;
+
+ // Logged when the user modifying the notification importance slider.
+ ACTION_MODIFY_IMPORTANCE_SLIDER = 290;
+
+ // Logged when the user saves a modification to notification importance. Negative numbers
+ // indicate the user lowered the importance; positive means they increased it.
+ ACTION_SAVE_IMPORTANCE = 291;
+
+ // Interactive bug report initiated from power menu.
+ ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292;
+
+ // Full bug report initiated from power menu.
+ ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293;
+
+ // Interactive bug report initiated from Settings.
+ ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
+
+ // Full bug report initiated from Settings.
+ ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
+
+ // Bug report canceled using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
+
+ // Bug report details screen open using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297;
+
+ // Additional Bug report screen shot taken using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298;
+
+ // Bug report shared by user using system notification.
+ ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
+
+ // User changed bug report name using the details screen.
+ ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300;
+
+ // User changed bug report title using the details screen.
+ ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301;
+
+ // User changed bug report description using the details screen.
+ ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302;
+
+ // Changes made on bug report details screen were saved by user.
+ ACTION_BUGREPORT_DETAILS_SAVED = 303;
+
+ // Changes made on bug report details screen were canceled by user.
+ ACTION_BUGREPORT_DETAILS_CANCELED = 304;
+
+ // Tuner: Open/close calibrate dialog.
+ TUNER_CALIBRATE_DISPLAY = 305;
+
+ // Tuner: Open/close color and appearance.
+ TUNER_COLOR_AND_APPEARANCE = 306;
+
+ // Tuner: Apply calibrate dialog.
+ ACTION_TUNER_CALIBRATE_DISPLAY_CHANGED = 307;
+
+ // Tuner: Open/close night mode.
+ TUNER_NIGHT_MODE = 308;
+
+ // Tuner: Change night mode.
+ ACTION_TUNER_NIGHT_MODE = 309;
+
+ // Tuner: Change night mode auto.
+ ACTION_TUNER_NIGHT_MODE_AUTO = 310;
+
+ // Tuner: Change night mode adjust dark theme.
+ ACTION_TUNER_NIGHT_MODE_ADJUST_DARK_THEME = 311;
+
+ // Tuner: Change night mode adjust tint.
+ ACTION_TUNER_NIGHT_MODE_ADJUST_TINT = 312;
+
+ // Tuner: Change night mode adjust brightness.
+ ACTION_TUNER_NIGHT_MODE_ADJUST_BRIGHTNESS = 313;
+
+ // Tuner: Change do not disturb in volume panel.
+ ACTION_TUNER_DO_NOT_DISTURB_VOLUME_PANEL = 314;
+
+ // Tuner: Change do not disturb volume buttons shortcut.
+ ACTION_TUNER_DO_NOT_DISTURB_VOLUME_SHORTCUT = 315;
+
+ // Logs the action the user takes when an app crashed.
+ ACTION_APP_CRASH = 316;
+
+ // Logs the action the user takes when an app ANR'd.
+ ACTION_APP_ANR = 317;
+
+ // Logged when a user double taps the overview button to launch the previous task
+ OVERVIEW_LAUNCH_PREVIOUS_TASK = 318;
+
+ // Logged when we execute an app transition. This indicates the total delay from startActivity
+ // until the app transition is starting to animate, in milliseconds.
+ APP_TRANSITION_DELAY_MS = 319;
+
+ // Logged when we execute an app transition. This indicates the reason why the transition
+ // started. Must be one of ActivityManagerInternal.APP_TRANSITION_* reasons.
+ APP_TRANSITION_REASON = 320;
+
+ // Logged when we execute an app transition and we drew a starting window. This indicates the
+ // delay from startActivity until the starting window was drawn.
+ APP_TRANSITION_STARTING_WINDOW_DELAY_MS = 321;
+
+ // Logged when we execute an app transition and all windows of the app got drawn. This indicates
+ // the delay from startActivity until all windows have been drawn.
+ APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS = 322;
+
+ // Logged when we execute an app transition. This indicates the component name of the current
+ // transition.
+ APP_TRANSITION_COMPONENT_NAME = 323;
+
+ // Logged when we execute an app transition. This indicates whether the process was already
+ // running.
+ APP_TRANSITION_PROCESS_RUNNING = 324;
+
+ // Logged when we execute an app transition. This indicates the device uptime in seconds when
+ // the transition was executed.
+ APP_TRANSITION_DEVICE_UPTIME_SECONDS = 325;
}
}
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 3dff37bb4505..3bef19e01e8e 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -2346,62 +2346,75 @@ nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _kernels,
ALOGD("nScriptGroupCreate, con(%p)", (RsContext)con);
}
+ jlong id = 0;
+
+ RsScriptKernelID* kernelsPtr;
jint kernelsLen = _env->GetArrayLength(_kernels);
jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
+
+ RsScriptKernelID* srcPtr;
+ jint srcLen = _env->GetArrayLength(_src);
+ jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
+
+ RsScriptKernelID* dstkPtr;
+ jint dstkLen = _env->GetArrayLength(_dstk);
+ jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
+
+ RsScriptKernelID* dstfPtr;
+ jint dstfLen = _env->GetArrayLength(_dstf);
+ jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
+
+ RsType* typesPtr;
+ jint typesLen = _env->GetArrayLength(_types);
+ jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
+
if (jKernelsPtr == nullptr) {
ALOGE("Failed to get Java array elements: kernels");
- return 0;
+ goto cleanup;
+ }
+ if (jSrcPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: src");
+ goto cleanup;
+ }
+ if (jDstkPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: dstk");
+ goto cleanup;
+ }
+ if (jDstfPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: dstf");
+ goto cleanup;
}
- RsScriptKernelID* kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
+ if (jTypesPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: types");
+ goto cleanup;
+ }
+
+ kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
for(int i = 0; i < kernelsLen; ++i) {
kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
}
- jint srcLen = _env->GetArrayLength(_src);
- jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
- if (jSrcPtr == nullptr) {
- ALOGE("Failed to get Java array elements: src");
- return 0;
- }
- RsScriptKernelID* srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
+ srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
for(int i = 0; i < srcLen; ++i) {
srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
}
- jint dstkLen = _env->GetArrayLength(_dstk);
- jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
- if (jDstkPtr == nullptr) {
- ALOGE("Failed to get Java array elements: dstk");
- return 0;
- }
- RsScriptKernelID* dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
+ dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
for(int i = 0; i < dstkLen; ++i) {
dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
}
- jint dstfLen = _env->GetArrayLength(_dstf);
- jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
- if (jDstfPtr == nullptr) {
- ALOGE("Failed to get Java array elements: dstf");
- return 0;
- }
- RsScriptKernelID* dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
+ dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
for(int i = 0; i < dstfLen; ++i) {
dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
}
- jint typesLen = _env->GetArrayLength(_types);
- jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
- if (jTypesPtr == nullptr) {
- ALOGE("Failed to get Java array elements: types");
- return 0;
- }
- RsType* typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
+ typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
for(int i = 0; i < typesLen; ++i) {
typesPtr[i] = (RsType)jTypesPtr[i];
}
- jlong id = (jlong)(uintptr_t)rsScriptGroupCreate((RsContext)con,
+ id = (jlong)(uintptr_t)rsScriptGroupCreate((RsContext)con,
(RsScriptKernelID *)kernelsPtr, kernelsLen * sizeof(RsScriptKernelID),
(RsScriptKernelID *)srcPtr, srcLen * sizeof(RsScriptKernelID),
(RsScriptKernelID *)dstkPtr, dstkLen * sizeof(RsScriptKernelID),
@@ -2413,11 +2426,24 @@ nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _kernels,
free(dstkPtr);
free(dstfPtr);
free(typesPtr);
- _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
- _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
- _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
- _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
- _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
+
+cleanup:
+ if (jKernelsPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
+ }
+ if (jSrcPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
+ }
+ if (jDstkPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
+ }
+ if (jDstfPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
+ }
+ if (jTypesPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
+ }
+
return id;
}
@@ -2662,45 +2688,61 @@ nMeshCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _vtx, jlongArray
ALOGD("nMeshCreate, con(%p)", (RsContext)con);
}
+ jlong id = 0;
+
+ RsAllocation* vtxPtr;
jint vtxLen = _env->GetArrayLength(_vtx);
jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, nullptr);
+
+ RsAllocation* idxPtr;
+ jint idxLen = _env->GetArrayLength(_idx);
+ jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
+
+ jint primLen = _env->GetArrayLength(_prim);
+ jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
+
if (jVtxPtr == nullptr) {
ALOGE("Failed to get Java array elements: vtx");
- return 0;
+ goto cleanupMesh;
+ }
+ if (jIdxPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: idx");
+ goto cleanupMesh;
+ }
+ if (primPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: prim");
+ goto cleanupMesh;
}
- RsAllocation* vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
+
+ vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
for(int i = 0; i < vtxLen; ++i) {
vtxPtr[i] = (RsAllocation)(uintptr_t)jVtxPtr[i];
}
- jint idxLen = _env->GetArrayLength(_idx);
- jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
- if (jIdxPtr == nullptr) {
- ALOGE("Failed to get Java array elements: idx");
- return 0;
- }
- RsAllocation* idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
+ idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
for(int i = 0; i < idxLen; ++i) {
idxPtr[i] = (RsAllocation)(uintptr_t)jIdxPtr[i];
}
- jint primLen = _env->GetArrayLength(_prim);
- jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
- if (primPtr == nullptr) {
- ALOGE("Failed to get Java array elements: prim");
- return 0;
- }
-
- jlong id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
- (RsAllocation *)vtxPtr, vtxLen,
- (RsAllocation *)idxPtr, idxLen,
- (uint32_t *)primPtr, primLen);
+ id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
+ (RsAllocation *)vtxPtr, vtxLen,
+ (RsAllocation *)idxPtr, idxLen,
+ (uint32_t *)primPtr, primLen);
free(vtxPtr);
free(idxPtr);
- _env->ReleaseLongArrayElements(_vtx, jVtxPtr, 0);
- _env->ReleaseLongArrayElements(_idx, jIdxPtr, 0);
- _env->ReleaseIntArrayElements(_prim, primPtr, 0);
+
+cleanupMesh:
+ if (jVtxPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_vtx, jVtxPtr, 0);
+ }
+ if (jIdxPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_idx, jIdxPtr, 0);
+ }
+ if (primPtr != nullptr) {
+ _env->ReleaseIntArrayElements(_prim, primPtr, 0);
+ }
+
return id;
}
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
index d98fc281dfb7..ce89aa7697ae 100644
--- a/services/accessibility/Android.mk
+++ b/services/accessibility/Android.mk
@@ -7,4 +7,6 @@ LOCAL_MODULE := services.accessibility
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index b79a7ba69b4e..ad70853f13ba 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -110,9 +110,25 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
// The minimal score for accepting a predicted gesture.
private static final float MIN_PREDICTION_SCORE = 2.0f;
+ // Distance a finger must travel before we decide if it is a gesture or not.
private static final int GESTURE_CONFIRM_MM = 10;
- private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 1000;
- private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 500;
+
+ // Time threshold used to determine if an interaction is a gesture or not.
+ // If the first movement of 1cm takes longer than this value, we assume it's
+ // a slow movement, and therefore not a gesture.
+ //
+ // This value was determined by measuring the time for the first 1cm
+ // 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, 150ms seems the best value to decide what
+ // kind of interaction it is.
+ 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
+ // cancelled.
+ private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 500;
AccessibilityGestureDetector(Context context, Listener listener) {
mListener = listener;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 3335315f6c01..3e7466fdfa7d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -275,6 +275,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private void processBatchedEvents(long frameNanos) {
MotionEventHolder current = mEventQueue;
+ if (current == null) {
+ return;
+ }
while (current.next != null) {
current = current.next;
}
@@ -403,6 +406,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
private void disableFeatures() {
+ // Give the features a chance to process any batched events so we'll keep a consistent
+ // event stream
+ processBatchedEvents(Long.MAX_VALUE);
if (mMotionEventInjector != null) {
mAms.setMotionEventInjector(null);
mMotionEventInjector.onDestroy();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c35a73a4c1a1..acd57b17081a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -52,7 +52,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -95,6 +94,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
@@ -352,6 +352,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
// user change and unlock
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
@@ -362,6 +363,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
@@ -654,7 +657,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
userState.mUiAutomationFlags = flags;
userState.mIsAccessibilityEnabled = true;
userState.mInstalledServices.add(accessibilityServiceInfo);
- if (userState.isUiAutomationSuppressingOtherServices()) {
+ if ((flags & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0) {
// Set the temporary state.
userState.mIsTouchExplorationEnabled = false;
userState.mIsEnhancedWebAccessibilityEnabled = false;
@@ -901,6 +904,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ private void unlockUser(int userId) {
+ synchronized (mLock) {
+ UserState userState = getUserStateLocked(userId);
+ onUserStateChangedLocked(userState);
+ }
+ }
+
private void removeUser(int userId) {
synchronized (mLock) {
mUserStates.remove(userId);
@@ -1003,8 +1013,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
new Intent(AccessibilityService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES
- | PackageManager.GET_META_DATA
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+ | PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
mCurrentUserId);
for (int i = 0, count = installedServices.size(); i < count; i++) {
@@ -1237,6 +1248,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void manageServicesLocked(UserState userState) {
Map<ComponentName, Service> componentNameToServiceMap =
userState.mComponentNameToServiceMap;
+ boolean isUnlocked = mContext.getSystemService(UserManager.class)
+ .isUserUnlocked(userState.mUserId);
boolean isEnabled = userState.mIsAccessibilityEnabled;
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
@@ -1245,6 +1258,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
installedService.getId());
Service service = componentNameToServiceMap.get(componentName);
+ // Ignore non-encryption-aware services until user is unlocked
+ if (!isUnlocked && !installedService.isEncryptionAware()) {
+ Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
+ continue;
+ }
+
if (isEnabled) {
// Wait for the binding if it is in process.
if (userState.mBindingServices.contains(componentName)) {
@@ -1273,7 +1292,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
// No enabled installed services => disable accessibility to avoid
// sending accessibility events with no recipient across processes.
- if (isEnabled && userState.mBoundServices.isEmpty()
+ if (isEnabled && isUnlocked && userState.mBoundServices.isEmpty()
&& userState.mBindingServices.isEmpty()) {
userState.mIsAccessibilityEnabled = false;
final long identity = Binder.clearCallingIdentity();
@@ -1749,14 +1768,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void updateMagnificationLocked(UserState userState) {
final int userId = userState.mUserId;
if (userId == mCurrentUserId && mMagnificationController != null) {
- if (userHasMagnificationServicesLocked(userState)) {
+ if (userState.mIsDisplayMagnificationEnabled ||
+ userHasMagnificationServicesLocked(userState)) {
mMagnificationController.setUserId(userState.mUserId);
} else {
// If the user no longer has any magnification-controlling
// services and is not using magnification gestures, then
// reset the state to normal.
- if (!userState.mIsDisplayMagnificationEnabled
- && mMagnificationController.resetIfNeeded(true)) {
+ if (mMagnificationController.resetIfNeeded(true)) {
// Animations are still running, so wait until we receive a
// callback verifying that we've reset magnification.
mUnregisterMagnificationOnReset = true;
@@ -2163,8 +2182,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mIntent = new Intent().setComponent(mComponentName);
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.accessibility_binding_label);
- mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
- mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+ final long idendtity = Binder.clearCallingIdentity();
+ try {
+ mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+ } finally {
+ Binder.restoreCallingIdentity(idendtity);
+ }
}
setDynamicallyConfigurableProperties(accessibilityServiceInfo);
}
@@ -2755,6 +2779,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
showGlobalActions();
} return true;
+ case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: {
+ toggleSplitScreen();
+ } return true;
}
return false;
} finally {
@@ -3226,6 +3253,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mWindowManagerService.showGlobalActions();
}
+ private void toggleSplitScreen() {
+ LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen();
+ }
+
private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
if (DEBUG) {
Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
@@ -3442,11 +3473,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
- case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
- case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+ case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
+ case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
+ return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER;
+ }
+
case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 9e6cd002e889..3ecff405d756 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -467,17 +467,18 @@ class TouchExplorer implements EventStreamTransformation, AccessibilityGestureDe
if (mCurrentState == STATE_GESTURE_DETECTING) {
endGestureDetection();
} else if (mCurrentState == STATE_TOUCH_EXPLORING) {
- final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
- final int pointerIdBits = (1 << pointerId);
-
- // Cache the event until we discern exploration from gesturing.
- mSendHoverEnterAndMoveDelayed.addEvent(event);
-
- // We have just decided that the user is touch,
- // exploring so start sending events.
- mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
- mSendHoverExitDelayed.cancel();
- sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+ // If the finger is still moving, pass the event on.
+ if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+ final int pointerIdBits = (1 << pointerId);
+
+ // We have just decided that the user is touch,
+ // exploring so start sending events.
+ mSendHoverEnterAndMoveDelayed.addEvent(event);
+ mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
+ mSendHoverExitDelayed.cancel();
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+ }
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 29801b3cb8d9..f537d182035e 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -159,7 +159,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
reloadWidgetsMaskedStateForUser(userId);
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
synchronized (mLock) {
- reloadWidgetQuietModeMaskedStateLocked(userId);
+ reloadWidgetProfileUnavailableMaskedStateLocked(userId);
}
} else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -353,7 +353,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void onPackageBroadcastReceived(Intent intent, int userId) {
- if (!mUserManager.isUserUnlocked(userId)) return;
+ if (!mUserManager.isUserUnlocked(userId) ||
+ isProfileWithLockedParent(userId)) {
+ return;
+ }
final String action = intent.getAction();
boolean added = false;
@@ -432,17 +435,20 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
/**
* Reload all widgets' masked state for the given user and its associated profiles, including
- * due to quiet mode and package suspension.
+ * due to user not being available and package suspension.
*/
private void reloadWidgetsMaskedStateForUser(int userId) {
- if (!mUserManager.isUserUnlocked(userId)) return;
+ if (!mUserManager.isUserUnlocked(userId) ||
+ isProfileWithLockedParent(userId)) {
+ return;
+ }
synchronized (mLock) {
reloadWidgetPackageSuspensionMaskedStateLocked(userId);
List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
if (profiles != null) {
for (int i = 0; i < profiles.size(); i++) {
UserInfo user = profiles.get(i);
- reloadWidgetQuietModeMaskedStateLocked(user.id);
+ reloadWidgetProfileUnavailableMaskedStateLocked(user.id);
reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
}
}
@@ -450,17 +456,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
/**
- * Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
+ * Mask/unmask widgets in the given profile, depending on the quiet state
+ * or locked state of the profile.
*/
- private void reloadWidgetQuietModeMaskedStateLocked(int profileId) {
- if (!mUserManager.isUserUnlocked(profileId)) return;
+ private void reloadWidgetProfileUnavailableMaskedStateLocked(int profileId) {
final long identity = Binder.clearCallingIdentity();
try {
- UserInfo user = mUserManager.getUserInfo(profileId);
- if (!user.isManagedProfile()) {
+ if (!isProfileWithUnlockedParent(profileId)) {
return;
}
- boolean shouldMask = user.isQuietModeEnabled();
+ UserInfo user = mUserManager.getUserInfo(profileId);
+ boolean shouldMask = user.isQuietModeEnabled() ||
+ !mUserManager.isUserUnlocked(user.getUserHandle());
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
Provider provider = mProviders.get(i);
@@ -468,7 +475,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (providerUserId != profileId) {
continue;
}
- if (provider.setMaskedByQuietProfileLocked(shouldMask)) {
+ if (provider.setMaskedByProfileUnavailabledLocked(shouldMask)) {
if (provider.isMaskedLocked()) {
maskWidgetsViewsLocked(provider);
} else {
@@ -493,9 +500,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
continue;
}
try {
- ApplicationInfo ai = mPackageManager.getApplicationInfo(
- provider.info.provider.getPackageName(), 0, provider.getUserId());
- boolean suspended = (ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+ boolean suspended = mPackageManager.isPackageSuspendedForUser(
+ provider.info.provider.getPackageName(), provider.getUserId());
if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
if (provider.isMaskedLocked()) {
maskWidgetsViewsLocked(provider);
@@ -538,8 +544,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
- private void maskWidgetsViewsLocked(Provider provider) {
- Bitmap iconBitmap = null;
+ private Bitmap createMaskedWidgetBitmap(Provider provider) {
+ final long identity = Binder.clearCallingIdentity();
try {
// Load the unbadged application icon and pass it to the widget to appear on
// the masked view.
@@ -549,11 +555,20 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
PackageManager pm = userContext.getPackageManager();
Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
// Create a bitmap of the icon which is what the widget's remoteview requires.
- iconBitmap = mIconUtilities.createIconBitmap(icon);
+ return mIconUtilities.createIconBitmap(icon);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Fail to get application icon", e);
// Provider package removed, no need to mask its views as its state will be
// purged very soon.
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void maskWidgetsViewsLocked(Provider provider) {
+ Bitmap iconBitmap = createMaskedWidgetBitmap(provider);
+ if (iconBitmap == null) {
return;
}
@@ -597,7 +612,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
throw new IllegalStateException(
"User " + userId + " must be unlocked for widgets to be available");
}
-
+ if (isProfileWithLockedParent(userId)) {
+ throw new IllegalStateException(
+ "Profile " + userId + " must have unlocked parent");
+ }
final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
// Careful lad, we may have already loaded the state for some
@@ -2321,7 +2339,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
final PackageManager pm = mContext.getPackageManager();
final int userId = UserHandle.getUserId(providerId.uid);
final ApplicationInfo app = pm.getApplicationInfoAsUser(activityInfo.packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+ 0, userId);
resources = pm.getResourcesForApplication(app);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2424,9 +2442,16 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
int flags = PackageManager.GET_META_DATA;
// We really need packages to be around and parsed to know if they
- // provide widgets, and we only load widgets after user is unlocked.
+ // provide widgets.
flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+ // Widget hosts that are non-crypto aware may be hosting widgets
+ // from a profile that is still locked, so let them see those
+ // widgets.
+ if (isProfileWithUnlockedParent(userId)) {
+ flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+ }
+
// Widgets referencing shared libraries need to have their
// dependencies loaded.
flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
@@ -2442,8 +2467,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void onUserUnlocked(int userId) {
+ if (isProfileWithLockedParent(userId)) {
+ return;
+ }
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
+ reloadWidgetsMaskedStateForUser(userId);
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
@@ -2581,6 +2610,17 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mWidgetPackages.put(userId, packages = new ArraySet<String>());
}
packages.add(widget.provider.info.provider.getPackageName());
+
+ // If we are adding a widget it might be for a provider that
+ // is currently masked, if so mask the widget.
+ if (widget.provider.isMaskedLocked()) {
+ Bitmap bitmap = createMaskedWidgetBitmap(widget.provider);
+ if (bitmap != null) {
+ widget.replaceWithMaskedViewsLocked(mContext, bitmap);
+ }
+ } else {
+ widget.clearMaskedViewsLocked();
+ }
}
/**
@@ -3278,6 +3318,35 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
+ private boolean isProfileWithLockedParent(int userId) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ UserInfo parentInfo = mUserManager.getProfileParent(userId);
+ if (parentInfo != null
+ && !mUserManager.isUserUnlocked(parentInfo.getUserHandle())) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return false;
+ }
+
+ private boolean isProfileWithUnlockedParent(int userId) {
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ UserInfo parentInfo = mUserManager.getProfileParent(userId);
+ if (parentInfo != null
+ && mUserManager.isUserUnlocked(parentInfo.getUserHandle())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private final class CallbackHandler extends Handler {
public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1;
public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2;
@@ -3555,7 +3624,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
PendingIntent broadcast;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
- boolean maskedByQuietProfile;
+ boolean maskedByProfileUnavailable;
boolean maskedBySuspendedPackage;
int tag = TAG_UNDEFINED; // for use while saving state (the index)
@@ -3588,9 +3657,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
// returns true if the provider's masked state is changed as a result
- public boolean setMaskedByQuietProfileLocked(boolean masked) {
+ public boolean setMaskedByProfileUnavailabledLocked(boolean masked) {
boolean oldMaskedState = isMaskedLocked();
- maskedByQuietProfile = masked;
+ maskedByProfileUnavailable = masked;
return isMaskedLocked() != oldMaskedState;
}
@@ -3602,7 +3671,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
public boolean isMaskedLocked() {
- return maskedByQuietProfile || maskedBySuspendedPackage;
+ return maskedByProfileUnavailable || maskedBySuspendedPackage;
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5e948b117b4e..f1a9c44ffe6c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.backup;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
@@ -87,6 +89,7 @@ import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StringBuilderPrinter;
@@ -142,6 +145,7 @@ import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
@@ -167,6 +171,10 @@ public class BackupManagerService {
static final boolean MORE_DEBUG = false;
static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
+ // File containing backup-enabled state. Contains a single byte;
+ // nonzero == enabled. File missing or contains a zero byte == disabled.
+ static final String BACKUP_ENABLE_FILE = "backup_enabled";
+
// System-private key used for backing up an app's widget state. Must
// begin with U+FFxx by convention (we reserve all keys starting
// with U+FF00 or higher for system use).
@@ -189,7 +197,8 @@ public class BackupManagerService {
// 1 : initial release
// 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection
// 3 : introduced "_meta" metadata file; no other format change per se
- static final int BACKUP_FILE_VERSION = 3;
+ // 4 : added support for new device-encrypted storage locations
+ static final int BACKUP_FILE_VERSION = 4;
static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
static final int BACKUP_PW_FILE_VERSION = 2;
static final String BACKUP_METADATA_FILENAME = "_meta";
@@ -345,15 +354,34 @@ public class BackupManagerService {
}
@Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_SYSTEM_SERVICES_READY) {
- sInstance.initialize(UserHandle.USER_SYSTEM);
- } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- ContentResolver r = sInstance.mContext.getContentResolver();
- boolean areEnabled = Settings.Secure.getInt(r,
- Settings.Secure.BACKUP_ENABLED, 0) != 0;
+ public void onUnlockUser(int userId) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ sInstance.initialize(userId);
+
+ // Migrate legacy setting
+ if (!backupSettingMigrated(userId)) {
+ if (DEBUG) {
+ Slog.i(TAG, "Backup enable apparently not migrated");
+ }
+ final ContentResolver r = sInstance.mContext.getContentResolver();
+ final int enableState = Settings.Secure.getIntForUser(r,
+ Settings.Secure.BACKUP_ENABLED, -1, userId);
+ if (enableState >= 0) {
+ if (DEBUG) {
+ Slog.i(TAG, "Migrating enable state " + (enableState != 0));
+ }
+ writeBackupEnableState(enableState != 0, userId);
+ Settings.Secure.putStringForUser(r,
+ Settings.Secure.BACKUP_ENABLED, null, userId);
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "Backup not yet configured; retaining null enable state");
+ }
+ }
+ }
+
try {
- sInstance.setBackupEnabled(areEnabled);
+ sInstance.setBackupEnabled(readBackupEnableState(userId));
} catch (RemoteException e) {
// can't happen; it's a local object
}
@@ -786,8 +814,9 @@ public class BackupManagerService {
case MSG_OP_COMPLETE:
{
try {
- BackupRestoreTask task = (BackupRestoreTask) msg.obj;
- task.operationComplete(msg.arg1);
+ Pair<BackupRestoreTask, Long> taskWithResult =
+ (Pair<BackupRestoreTask, Long>) msg.obj;
+ taskWithResult.first.operationComplete(taskWithResult.second);
} catch (ClassCastException e) {
Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
}
@@ -1044,7 +1073,7 @@ public class BackupManagerService {
// If Encrypted file systems is enabled or disabled, this call will return the
// correct directory.
- mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
+ mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
@@ -2416,7 +2445,7 @@ public class BackupManagerService {
PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES);
if (!appIsEligibleForBackup(packageInfo.applicationInfo)) {
- sendBackupOnResult(observer, packageName,
+ sendBackupOnPackageResult(observer, packageName,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
@@ -2426,7 +2455,8 @@ public class BackupManagerService {
kvBackupList.add(packageInfo.packageName);
}
} catch (NameNotFoundException e) {
- sendBackupOnResult(observer, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
+ sendBackupOnPackageResult(observer, packageName,
+ BackupManager.ERROR_PACKAGE_NOT_FOUND);
}
}
EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
@@ -2459,7 +2489,7 @@ public class BackupManagerService {
void execute();
// An operation that wanted a callback has completed
- void operationComplete(int result);
+ void operationComplete(long result);
// An operation that wanted a callback has timed out
void handleTimeout();
@@ -2758,8 +2788,8 @@ public class BackupManagerService {
addBackupTrace("skipping - not eligible, completion is noop");
// Shouldn't happen in case of requested backup, as pre-check was done in
// #requestBackup(), except to app update done concurrently
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -2773,8 +2803,8 @@ public class BackupManagerService {
addBackupTrace("skipping - fullBackupOnly, completion is noop");
// Shouldn't happen in case of requested backup, as pre-check was done in
// #requestBackup()
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -2784,8 +2814,8 @@ public class BackupManagerService {
// and not yet launched out of that state, so just as it won't
// receive broadcasts, we won't run it for backup.
addBackupTrace("skipping - stopped");
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -2833,14 +2863,14 @@ public class BackupManagerService {
dataChangedImpl(request.packageName);
mStatus = BackupTransport.TRANSPORT_OK;
if (mQueue.isEmpty()) nextState = BackupState.FINAL;
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_AGENT_FAILURE);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_AGENT_FAILURE);
} else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
// Failed lookup of the app, so we couldn't bring up an agent, but
// we're otherwise fine. Just drop it and go on to the next as usual.
mStatus = BackupTransport.TRANSPORT_OK;
- sendBackupOnResult(mObserver, mCurrentPackage.packageName,
- BackupManager.ERROR_PACKAGE_NOT_FOUND);
+ sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
+ BackupManager.ERROR_PACKAGE_NOT_FOUND);
} else {
// Transport-level failure means we reenqueue everything
revertAndEndBackup();
@@ -3094,7 +3124,7 @@ public class BackupManagerService {
}
@Override
- public void operationComplete(int unusedResult) {
+ public void operationComplete(long unusedResult) {
// The agent reported back to us!
if (mBackupData == null) {
@@ -3132,7 +3162,7 @@ public class BackupManagerService {
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
"bad key");
mBackupHandler.removeMessages(MSG_TIMEOUT);
- sendBackupOnResult(mObserver, pkgName,
+ sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_AGENT_FAILURE);
agentErrorCleanup();
// agentErrorCleanup() implicitly executes next state properly
@@ -3207,7 +3237,7 @@ public class BackupManagerService {
// with the new state file it just created.
mBackupDataName.delete();
mNewStateName.renameTo(mSavedStateName);
- sendBackupOnResult(mObserver, pkgName, BackupManager.SUCCESS);
+ sendBackupOnPackageResult(mObserver, pkgName, BackupManager.SUCCESS);
EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
logBackupComplete(pkgName);
} else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
@@ -3215,20 +3245,22 @@ public class BackupManagerService {
// back but proceed with running the rest of the queue.
mBackupDataName.delete();
mNewStateName.delete();
- sendBackupOnResult(mObserver, pkgName,
+ sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
} else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- sendBackupOnResult(mObserver, pkgName,
+ sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
} else {
// Actual transport-level failure to communicate the data to the backend
- sendBackupOnResult(mObserver, pkgName, BackupManager.ERROR_TRANSPORT_ABORTED);
+ sendBackupOnPackageResult(mObserver, pkgName,
+ BackupManager.ERROR_TRANSPORT_ABORTED);
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
}
} catch (Exception e) {
- sendBackupOnResult(mObserver, pkgName, BackupManager.ERROR_TRANSPORT_ABORTED);
+ sendBackupOnPackageResult(mObserver, pkgName,
+ BackupManager.ERROR_TRANSPORT_ABORTED);
Slog.e(TAG, "Transport error backing up " + pkgName, e);
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
mStatus = BackupTransport.TRANSPORT_ERROR;
@@ -3491,18 +3523,18 @@ public class BackupManagerService {
*/
int preflightFullBackup(PackageInfo pkg, IBackupAgent agent);
- long expectedSize();
+ long getExpectedSizeOrErrorCode();
};
class FullBackupEngine {
OutputStream mOutput;
FullBackupPreflight mPreflightHook;
- IFullBackupRestoreObserver mObserver;
IBackupAgent mAgent;
File mFilesDir;
File mManifestFile;
File mMetadataFile;
boolean mIncludeApks;
+ PackageInfo mPkg;
class FullBackupRunner implements Runnable {
PackageInfo mPackage;
@@ -3514,8 +3546,8 @@ public class BackupManagerService {
boolean mWriteManifest;
FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
- int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
- throws IOException {
+ int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
+ throws IOException {
mPackage = pack;
mWidgetData = widgetData;
mAgent = agent;
@@ -3571,76 +3603,78 @@ public class BackupManagerService {
}
}
- FullBackupEngine(OutputStream output, String packageName, FullBackupPreflight preflightHook,
- boolean alsoApks) {
+ FullBackupEngine(OutputStream output, FullBackupPreflight preflightHook, PackageInfo pkg,
+ boolean alsoApks) {
mOutput = output;
mPreflightHook = preflightHook;
+ mPkg = pkg;
mIncludeApks = alsoApks;
mFilesDir = new File("/data/system");
mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
}
- public int backupOnePackage(PackageInfo pkg) throws RemoteException {
- int result = BackupTransport.TRANSPORT_OK;
- Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
+ public int preflightCheck() throws RemoteException {
+ if (mPreflightHook == null) {
+ if (MORE_DEBUG) {
+ Slog.v(TAG, "No preflight check");
+ }
+ return BackupTransport.TRANSPORT_OK;
+ }
+ if (initializeAgent()) {
+ int result = mPreflightHook.preflightFullBackup(mPkg, mAgent);
+ if (MORE_DEBUG) {
+ Slog.v(TAG, "preflight returned " + result);
+ }
+ return result;
+ } else {
+ Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
+ return BackupTransport.AGENT_ERROR;
+ }
+ }
- mAgent = bindToAgentSynchronous(pkg.applicationInfo,
- IApplicationThread.BACKUP_MODE_FULL);
- if (mAgent != null) {
+ public int backupOnePackage() throws RemoteException {
+ int result = BackupTransport.AGENT_ERROR;
+
+ if (initializeAgent()) {
ParcelFileDescriptor[] pipes = null;
try {
- // Call the preflight hook, if any
- if (mPreflightHook != null) {
- result = mPreflightHook.preflightFullBackup(pkg, mAgent);
- if (MORE_DEBUG) {
- Slog.v(TAG, "preflight returned " + result);
- }
- }
-
- // If we're still good to go after preflighting, start moving data
- if (result == BackupTransport.TRANSPORT_OK) {
- pipes = ParcelFileDescriptor.createPipe();
+ pipes = ParcelFileDescriptor.createPipe();
- ApplicationInfo app = pkg.applicationInfo;
- final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final boolean sendApk = mIncludeApks
- && !isSharedStorage
- && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
- && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
- (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+ ApplicationInfo app = mPkg.applicationInfo;
+ final boolean isSharedStorage =
+ mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
+ final boolean sendApk = mIncludeApks
+ && !isSharedStorage
+ && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
+ && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
+ (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
- // TODO: http://b/22388012
- byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
- UserHandle.USER_SYSTEM);
+ // TODO: http://b/22388012
+ byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName,
+ UserHandle.USER_SYSTEM);
- final int token = generateToken();
- FullBackupRunner runner = new FullBackupRunner(pkg, mAgent, pipes[1],
- token, sendApk, !isSharedStorage, widgetBlob);
- pipes[1].close(); // the runner has dup'd it
- pipes[1] = null;
- Thread t = new Thread(runner, "app-data-runner");
- t.start();
+ final int token = generateToken();
+ FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1],
+ token, sendApk, !isSharedStorage, widgetBlob);
+ pipes[1].close(); // the runner has dup'd it
+ pipes[1] = null;
+ Thread t = new Thread(runner, "app-data-runner");
+ t.start();
- // Now pull data from the app and stuff it into the output
- try {
- routeSocketDataToOutput(pipes[0], mOutput);
- } catch (IOException e) {
- Slog.i(TAG, "Caught exception reading from agent", e);
- result = BackupTransport.AGENT_ERROR;
- }
+ // Now pull data from the app and stuff it into the output
+ routeSocketDataToOutput(pipes[0], mOutput);
- if (!waitUntilOperationComplete(token)) {
- Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
- result = BackupTransport.AGENT_ERROR;
- } else {
- if (MORE_DEBUG) {
- Slog.d(TAG, "Full package backup success: " + pkg.packageName);
- }
+ if (!waitUntilOperationComplete(token)) {
+ Slog.e(TAG, "Full backup failed on package " + mPkg.packageName);
+ } else {
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Full package backup success: " + mPkg.packageName);
}
+ result = BackupTransport.TRANSPORT_OK;
}
} catch (IOException e) {
- Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+ Slog.e(TAG, "Error backing up " + mPkg.packageName, e);
result = BackupTransport.AGENT_ERROR;
} finally {
try {
@@ -3656,15 +3690,14 @@ public class BackupManagerService {
}
}
} else {
- Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
- result = BackupTransport.AGENT_ERROR;
+ Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
}
- tearDown(pkg);
+ tearDown();
return result;
}
public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
- if (mAgent != null) {
+ if (initializeAgent()) {
try {
mAgent.doQuotaExceeded(backupDataBytes, quotaBytes);
} catch (RemoteException e) {
@@ -3673,6 +3706,17 @@ public class BackupManagerService {
}
}
+ private boolean initializeAgent() {
+ if (mAgent == null) {
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName);
+ }
+ mAgent = bindToAgentSynchronous(mPkg.applicationInfo,
+ IApplicationThread.BACKUP_MODE_FULL);
+ }
+ return mAgent != null;
+ }
+
private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
// Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
// TODO: handle backing up split APKs
@@ -3789,9 +3833,9 @@ public class BackupManagerService {
destination.setLastModified(0);
}
- private void tearDown(PackageInfo pkg) {
- if (pkg != null) {
- final ApplicationInfo app = pkg.applicationInfo;
+ private void tearDown() {
+ if (mPkg != null) {
+ final ApplicationInfo app = mPkg.applicationInfo;
if (app != null) {
tearDownAgentAndKill(app);
}
@@ -4160,9 +4204,10 @@ public class BackupManagerService {
final boolean isSharedStorage =
pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- mBackupEngine = new FullBackupEngine(out, pkg.packageName, null, mIncludeApks);
+ mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks);
sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
- mBackupEngine.backupOnePackage(pkg);
+ // Don't need to check preflight result as there is no preflight hook.
+ mBackupEngine.backupOnePackage();
// after the app's agent runs to handle its private filesystem
// contents, back up any OBB content it has on its behalf.
@@ -4238,7 +4283,7 @@ public class BackupManagerService {
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring ineligible package " + pkg);
}
- sendBackupOnResult(mBackupObserver, pkg,
+ sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
} else if (!appGetsFullBackup(info)) {
@@ -4248,7 +4293,7 @@ public class BackupManagerService {
Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+ pkg);
}
- sendBackupOnResult(mBackupObserver, pkg,
+ sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
} else if (appIsStopped(info.applicationInfo)) {
@@ -4258,7 +4303,7 @@ public class BackupManagerService {
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring stopped package " + pkg);
}
- sendBackupOnResult(mBackupObserver, pkg,
+ sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
@@ -4281,8 +4326,8 @@ public class BackupManagerService {
// Pipe through which we write data to the transport
ParcelFileDescriptor[] transportPipes = null;
- PackageInfo currentPackage;
long backoff = 0;
+ int backupRunStatus = BackupManager.SUCCESS;
try {
if (!mEnabled || !mProvisioned) {
@@ -4292,14 +4337,14 @@ public class BackupManagerService {
+ " p=" + mProvisioned + "; ignoring");
}
mUpdateSchedule = false;
- sendBackupFinished(mBackupObserver, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
return;
}
IBackupTransport transport = getTransport(mCurrentTransport);
if (transport == null) {
Slog.w(TAG, "Transport not present; full data backup not performed");
- sendBackupFinished(mBackupObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
+ backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
return;
}
@@ -4307,21 +4352,20 @@ public class BackupManagerService {
final int N = mPackages.size();
final byte[] buffer = new byte[8192];
for (int i = 0; i < N; i++) {
- currentPackage = mPackages.get(i);
+ PackageInfo currentPackage = mPackages.get(i);
+ String packageName = currentPackage.packageName;
if (DEBUG) {
- Slog.i(TAG, "Initiating full-data transport backup of "
- + currentPackage.packageName);
+ Slog.i(TAG, "Initiating full-data transport backup of " + packageName);
}
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE,
- currentPackage.packageName);
+ EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName);
transportPipes = ParcelFileDescriptor.createPipe();
// Tell the transport the data's coming
int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
- int result = transport.performFullBackup(currentPackage,
+ int backupPackageStatus = transport.performFullBackup(currentPackage,
transportPipes[0], flags);
- if (result == BackupTransport.TRANSPORT_OK) {
+ if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
// The transport has its own copy of the read end of the pipe,
// so close ours now
transportPipes[0].close();
@@ -4329,10 +4373,9 @@ public class BackupManagerService {
// Now set up the backup engine / data source end of things
enginePipes = ParcelFileDescriptor.createPipe();
- CountDownLatch runnerLatch = new CountDownLatch(1);
SinglePackageBackupRunner backupRunner =
new SinglePackageBackupRunner(enginePipes[1], currentPackage,
- transport, runnerLatch);
+ transport);
// The runner dup'd the pipe half, so we close it here
enginePipes[1].close();
enginePipes[1] = null;
@@ -4348,49 +4391,55 @@ public class BackupManagerService {
FileOutputStream out = new FileOutputStream(
transportPipes[1].getFileDescriptor());
long totalRead = 0;
- final long expectedSize = backupRunner.expectedSize();
- if (expectedSize < 0) {
- result = BackupTransport.AGENT_ERROR;
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.ERROR_AGENT_FAILURE);
- }
- int nRead = 0;
- do {
- if (!mKeepRunning.get()) {
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Full backup task told to stop");
- }
- break;
- }
- nRead = in.read(buffer);
+ final long preflightResult = backupRunner.getPreflightResultBlocking();
+ // Preflight result is negative if some error happened on preflight.
+ if (preflightResult < 0) {
if (MORE_DEBUG) {
- Slog.v(TAG, "in.read(buffer) from app: " + nRead);
+ Slog.d(TAG, "Backup error after preflight of package "
+ + packageName + ": " + preflightResult
+ + ", not running backup.");
}
- if (nRead > 0) {
- out.write(buffer, 0, nRead);
- result = transport.sendBackupData(nRead);
- totalRead += nRead;
- if (mBackupObserver != null && expectedSize > 0) {
- sendBackupOnUpdate(mBackupObserver, currentPackage.packageName,
- new BackupProgress(expectedSize, totalRead));
+ backupPackageStatus = (int) preflightResult;
+ } else {
+ int nRead = 0;
+ do {
+ if (!mKeepRunning.get()) {
+ if (DEBUG_SCHEDULING) {
+ Slog.i(TAG, "Full backup task told to stop");
+ }
+ break;
}
- }
- } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
+ nRead = in.read(buffer);
+ if (MORE_DEBUG) {
+ Slog.v(TAG, "in.read(buffer) from app: " + nRead);
+ }
+ if (nRead > 0) {
+ out.write(buffer, 0, nRead);
+ backupPackageStatus = transport.sendBackupData(nRead);
+ totalRead += nRead;
+ if (mBackupObserver != null && preflightResult > 0) {
+ sendBackupOnUpdate(mBackupObserver, packageName,
+ new BackupProgress(preflightResult, totalRead));
+ }
+ }
+ } while (nRead > 0
+ && backupPackageStatus == BackupTransport.TRANSPORT_OK);
- if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- long quota = transport.getBackupQuota(currentPackage.packageName, true);
- if (MORE_DEBUG) {
- Slog.d(TAG, "Package hit quota limit " + currentPackage.packageName
+ // Despite preflight succeeded, package still can hit quota on flight.
+ if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+ long quota = transport.getBackupQuota(packageName, true);
+ Slog.w(TAG, "Package hit quota limit in-flight " + packageName
+ ": " + totalRead + " of " + quota);
+ backupRunner.sendQuotaExceeded(totalRead, quota);
}
- backupRunner.sendQuotaExceeded(totalRead, quota);
}
+
// If we've lost our running criteria, tell the transport to cancel
// and roll back this (partial) backup payload; otherwise tell it
// that we've reached the clean finish state.
if (!mKeepRunning.get()) {
- result = BackupTransport.TRANSPORT_ERROR;
+ backupPackageStatus = BackupTransport.TRANSPORT_ERROR;
transport.cancelFullBackup();
} else {
// If we were otherwise in a good state, now interpret the final
@@ -4398,18 +4447,28 @@ public class BackupManagerService {
// failure case already, preserve that result and ignore whatever
// finishBackup() reports.
final int finishResult = transport.finishBackup();
- if (result == BackupTransport.TRANSPORT_OK) {
- result = finishResult;
+ if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
+ backupPackageStatus = finishResult;
}
}
+ // We still could fail in backup runner thread, getting result from there.
+ int backupRunnerResult = backupRunner.getBackupResultBlocking();
+ if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR
+ && backupRunnerResult != BackupTransport.TRANSPORT_OK) {
+ // If there was an error in runner thread and
+ // not TRANSPORT_ERROR here, overwrite it.
+ backupPackageStatus = backupRunnerResult;
+ }
+
if (MORE_DEBUG) {
- Slog.i(TAG, "Done trying to send backup data: result=" + result);
+ Slog.i(TAG, "Done trying to send backup data: result="
+ + backupPackageStatus);
}
- if (result != BackupTransport.TRANSPORT_OK) {
- Slog.e(TAG, "Error " + result
- + " backing up " + currentPackage.packageName);
+ if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
+ Slog.e(TAG, "Error " + backupPackageStatus + " backing up "
+ + packageName);
}
// Also ask the transport how long it wants us to wait before
@@ -4424,55 +4483,61 @@ public class BackupManagerService {
// Roll this package to the end of the backup queue if we're
// in a queue-driven mode (regardless of success/failure)
if (mUpdateSchedule) {
- enqueueFullBackup(currentPackage.packageName,
- System.currentTimeMillis());
+ enqueueFullBackup(packageName, System.currentTimeMillis());
}
- if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+ if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+ sendBackupOnPackageResult(mBackupObserver, packageName,
+ BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
if (DEBUG) {
- Slog.i(TAG, "Transport rejected backup of "
- + currentPackage.packageName
+ Slog.i(TAG, "Transport rejected backup of " + packageName
+ ", skipping");
}
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE,
- currentPackage.packageName, "transport rejected");
- // do nothing, clean up, and continue looping
- } else if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
- Slog.w(TAG, "Transport quota exceeded; aborting backup: " + result);
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
- currentPackage.packageName);
- return;
- } else if (result != BackupTransport.TRANSPORT_OK) {
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+ EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName,
+ "transport rejected");
+ // Do nothing, clean up, and continue looping.
+ } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+ sendBackupOnPackageResult(mBackupObserver, packageName,
+ BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+ if (DEBUG) {
+ Slog.i(TAG, "Transport quota exceeded for package: " + packageName);
+ EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
+ packageName);
+ }
+ // Do nothing, clean up, and continue looping.
+ } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) {
+ sendBackupOnPackageResult(mBackupObserver, packageName,
+ BackupManager.ERROR_AGENT_FAILURE);
+ Slog.w(TAG, "Application failure for package: " + packageName);
+ EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
+ // Do nothing, clean up, and continue looping.
+ } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
+ sendBackupOnPackageResult(mBackupObserver, packageName,
BackupManager.ERROR_TRANSPORT_ABORTED);
- Slog.w(TAG, "Transport failed; aborting backup: " + result);
+ Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus);
EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
+ // Abort entire backup pass.
+ backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
return;
} else {
// Success!
- sendBackupOnResult(mBackupObserver, currentPackage.packageName,
- BackupManager.SUCCESS);
- EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
- currentPackage.packageName);
- logBackupComplete(currentPackage.packageName);
+ sendBackupOnPackageResult(mBackupObserver, packageName,
+ BackupManager.SUCCESS);
+ EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName);
+ logBackupComplete(packageName);
}
cleanUpPipes(transportPipes);
cleanUpPipes(enginePipes);
- currentPackage = null;
- }
-
- sendBackupFinished(mBackupObserver, BackupManager.SUCCESS);
- if (DEBUG) {
- Slog.i(TAG, "Full backup completed.");
}
} catch (Exception e) {
- sendBackupFinished(mBackupObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
+ backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
Slog.w(TAG, "Exception trying full transport backup", e);
} finally {
+ if (DEBUG) {
+ Slog.i(TAG, "Full backup completed with status: " + backupRunStatus);
+ }
+ sendBackupFinished(mBackupObserver, backupRunStatus);
+
cleanUpPipes(transportPipes);
cleanUpPipes(enginePipes);
@@ -4524,7 +4589,7 @@ public class BackupManagerService {
// a standalone thread. The runner owns this half of the pipe, and closes
// it to indicate EOD to the other end.
class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
- final AtomicInteger mResult = new AtomicInteger();
+ final AtomicLong mResult = new AtomicLong();
final CountDownLatch mLatch = new CountDownLatch(1);
final IBackupTransport mTransport;
@@ -4546,7 +4611,11 @@ public class BackupManagerService {
// now wait to get our result back
mLatch.await();
- int totalSize = mResult.get();
+ long totalSize = mResult.get();
+ // If preflight timeouted, mResult will contain error code as int.
+ if (totalSize < 0) {
+ return (int) totalSize;
+ }
if (MORE_DEBUG) {
Slog.v(TAG, "Got preflight response; size=" + totalSize);
}
@@ -4573,7 +4642,7 @@ public class BackupManagerService {
}
@Override
- public void operationComplete(int result) {
+ public void operationComplete(long result) {
// got the callback, and our preflightFullBackup() method is waiting for the result
if (MORE_DEBUG) {
Slog.i(TAG, "Preflight op complete, result=" + result);
@@ -4592,7 +4661,7 @@ public class BackupManagerService {
}
@Override
- public long expectedSize() {
+ public long getExpectedSizeOrErrorCode() {
try {
mLatch.await();
return mResult.get();
@@ -4606,28 +4675,41 @@ public class BackupManagerService {
final ParcelFileDescriptor mOutput;
final PackageInfo mTarget;
final FullBackupPreflight mPreflight;
- final CountDownLatch mLatch;
+ final CountDownLatch mPreflightLatch;
+ final CountDownLatch mBackupLatch;
private FullBackupEngine mEngine;
+ private volatile int mPreflightResult;
+ private volatile int mBackupResult;
SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
- IBackupTransport transport, CountDownLatch latch) throws IOException {
+ IBackupTransport transport) throws IOException {
mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
mTarget = target;
mPreflight = new SinglePackageBackupPreflight(transport);
- mLatch = latch;
+ mPreflightLatch = new CountDownLatch(1);
+ mBackupLatch = new CountDownLatch(1);
+ mPreflightResult = BackupTransport.TRANSPORT_OK;
+ mBackupResult = BackupTransport.TRANSPORT_OK;
}
@Override
public void run() {
+ FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
+ mEngine = new FullBackupEngine(out, mPreflight, mTarget, false);
try {
- FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
- mEngine = new FullBackupEngine(out, mTarget.packageName,
- mPreflight, false);
- mEngine.backupOnePackage(mTarget);
+ try {
+ mPreflightResult = mEngine.preflightCheck();
+ } finally {
+ mPreflightLatch.countDown();
+ }
+ // If there is no error on preflight, continue backup.
+ if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
+ mBackupResult = mEngine.backupOnePackage();
+ }
} catch (Exception e) {
- Slog.e(TAG, "Exception during full package backup of " + mTarget);
+ Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName);
} finally {
- mLatch.countDown();
+ mBackupLatch.countDown();
try {
mOutput.close();
} catch (IOException e) {
@@ -4640,8 +4722,28 @@ public class BackupManagerService {
mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes);
}
- long expectedSize() {
- return mPreflight.expectedSize();
+ // If preflight succeeded, returns positive number - preflight size,
+ // otherwise return negative error code.
+ long getPreflightResultBlocking() {
+ try {
+ mPreflightLatch.await();
+ if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
+ return mPreflight.getExpectedSizeOrErrorCode();
+ } else {
+ return mPreflightResult;
+ }
+ } catch (InterruptedException e) {
+ return BackupTransport.AGENT_ERROR;
+ }
+ }
+
+ int getBackupResultBlocking() {
+ try {
+ mBackupLatch.await();
+ return mBackupResult;
+ } catch (InterruptedException e) {
+ return BackupTransport.AGENT_ERROR;
+ }
}
}
}
@@ -4852,7 +4954,9 @@ public class BackupManagerService {
continue;
}
- headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
+ final int privFlags = appInfo.applicationInfo.privateFlags;
+ headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
+ && mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
if (headBusy) {
final long nextEligible = System.currentTimeMillis()
@@ -8550,7 +8654,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
@Override
- public void operationComplete(int unusedResult) {
+ public void operationComplete(long unusedResult) {
if (MORE_DEBUG) {
Slog.i(TAG, "operationComplete() during restore: target="
+ mCurrentPackage.packageName
@@ -9233,6 +9337,58 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
}
+ private static boolean backupSettingMigrated(int userId) {
+ File base = new File(Environment.getDataDirectory(), "backup");
+ File enableFile = new File(base, BACKUP_ENABLE_FILE);
+ return enableFile.exists();
+ }
+
+ private static boolean readBackupEnableState(int userId) {
+ File base = new File(Environment.getDataDirectory(), "backup");
+ File enableFile = new File(base, BACKUP_ENABLE_FILE);
+ if (enableFile.exists()) {
+ try (FileInputStream fin = new FileInputStream(enableFile)) {
+ int state = fin.read();
+ return state != 0;
+ } catch (IOException e) {
+ // can't read the file; fall through to assume disabled
+ Slog.e(TAG, "Cannot read enable state; assuming disabled");
+ }
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
+ }
+ }
+ return false;
+ }
+
+ private static void writeBackupEnableState(boolean enable, int userId) {
+ File base = new File(Environment.getDataDirectory(), "backup");
+ File enableFile = new File(base, BACKUP_ENABLE_FILE);
+ File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
+ FileOutputStream fout = null;
+ try {
+ fout = new FileOutputStream(stage);
+ fout.write(enable ? 1 : 0);
+ fout.close();
+ stage.renameTo(enableFile);
+ // will be synced immediately by the try-with-resources call to close()
+ } catch (IOException|RuntimeException e) {
+ // Whoops; looks like we're doomed. Roll everything out, disabled,
+ // including the legacy state.
+ Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: "
+ + e.getMessage());
+
+ final ContentResolver r = sInstance.mContext.getContentResolver();
+ Settings.Secure.putStringForUser(r,
+ Settings.Secure.BACKUP_ENABLED, null, userId);
+ enableFile.delete();
+ stage.delete();
+ } finally {
+ IoUtils.closeQuietly(fout);
+ }
+ }
+
// Enable/disable backups
public void setBackupEnabled(boolean enable) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
@@ -9244,8 +9400,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
try {
boolean wasEnabled = mEnabled;
synchronized (this) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
+ writeBackupEnableState(enable, UserHandle.USER_SYSTEM);
mEnabled = enable;
}
@@ -9635,9 +9790,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
// The completion callback, if any, is invoked on the handler
if (op != null && op.callback != null) {
- Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
- // NB: this cannot distinguish between results > 2 gig
- msg.arg1 = (result > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) result;
+ Pair<BackupRestoreTask, Long> callbackAndResult = Pair.create(op.callback, result);
+ Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, callbackAndResult);
mBackupHandler.sendMessage(msg);
}
}
@@ -10129,7 +10283,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
}
- private static void sendBackupOnResult(IBackupObserver observer, String packageName,
+ private static void sendBackupOnPackageResult(IBackupObserver observer, String packageName,
int status) {
if (observer != null) {
try {
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index bbf881be102f..e74526338a8f 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -54,7 +54,7 @@ public class Trampoline extends IBackupManager.Stub {
public Trampoline(Context context) {
mContext = context;
- File dir = new File(Environment.getSecureDataDirectory(), "backup");
+ File dir = new File(Environment.getDataDirectory(), "backup");
dir.mkdirs();
mSuppressFile = new File(dir, BACKUP_SUPPRESS_FILENAME);
mGlobalDisable = SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index a4455e91f294..32f2d593f670 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -31,6 +31,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
@@ -67,6 +68,7 @@ import com.android.internal.app.IAppOpsCallback;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import libcore.util.EmptyArray;
@@ -103,9 +105,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
};
- final SparseArray<UidState> mUidStates = new SparseArray<>();
+ private final SparseArray<UidState> mUidStates = new SparseArray<>();
- private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
+ /** These are app op restrictions imposed per user from various parties */
+ private final ArrayMap<IBinder, SparseArray<boolean[]>> mOpUserRestrictions = new ArrayMap<>();
private static final class UidState {
public final int uid;
@@ -882,6 +885,11 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public int checkAudioOperation(int code, int usage, int uid, String packageName) {
+ if (isPackageSuspendedForUser(packageName, uid)) {
+ Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
+ return AppOpsManager.MODE_IGNORED;
+ }
+
synchronized (this) {
final int mode = checkRestrictionLocked(code, usage, uid, packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
@@ -891,6 +899,15 @@ public class AppOpsService extends IAppOpsService.Stub {
return checkOperation(code, uid, packageName);
}
+ private boolean isPackageSuspendedForUser(String pkg, int uid) {
+ try {
+ return AppGlobals.getPackageManager().isPackageSuspendedForUser(
+ pkg, UserHandle.getUserId(uid));
+ } catch (RemoteException re) {
+ throw new SecurityException("Could not talk to package manager service");
+ }
+ }
+
private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
if (usageRestrictions != null) {
@@ -1249,17 +1266,21 @@ public class AppOpsService extends IAppOpsService.Stub {
private boolean isOpRestricted(int uid, int code, String packageName) {
int userHandle = UserHandle.getUserId(uid);
- boolean[] opRestrictions = mOpRestrictions.get(userHandle);
- if ((opRestrictions != null) && opRestrictions[code]) {
- if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
- synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
- if ((ops != null) && ops.isPrivileged) {
- return false;
+ final int restrictionSetCount = mOpUserRestrictions.size();
+ for (int i = 0; i < restrictionSetCount; i++) {
+ SparseArray<boolean[]> perUserRestrictions = mOpUserRestrictions.valueAt(i);
+ boolean[] opRestrictions = perUserRestrictions.get(userHandle);
+ if (opRestrictions != null && opRestrictions[code]) {
+ if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+ synchronized (this) {
+ Ops ops = getOpsLocked(uid, packageName, true);
+ if ((ops != null) && ops.isPrivileged) {
+ return false;
+ }
}
}
+ return true;
}
- return true;
}
return false;
}
@@ -2035,27 +2056,123 @@ public class AppOpsService extends IAppOpsService.Stub {
}
@Override
- public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
+ public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
checkSystemUid("setUserRestrictions");
- boolean[] opRestrictions = mOpRestrictions.get(userHandle);
- if (opRestrictions == null) {
- opRestrictions = new boolean[AppOpsManager._NUM_OP];
- mOpRestrictions.put(userHandle, opRestrictions);
- }
+ Preconditions.checkNotNull(token);
+ final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
for (int i = 0; i < opRestrictions.length; ++i) {
String restriction = AppOpsManager.opToRestriction(i);
- if (restriction != null) {
- opRestrictions[i] = restrictions.getBoolean(restriction, false);
- } else {
- opRestrictions[i] = false;
+ final boolean restricted = restriction != null
+ && restrictions.getBoolean(restriction, false);
+ setUserRestrictionNoCheck(i, restricted, token, userHandle);
+ }
+ }
+
+ @Override
+ public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle) {
+ if (Binder.getCallingPid() != Process.myPid()) {
+ mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ }
+ if (userHandle != UserHandle.getCallingUserId()) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission
+ .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission
+ .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
+ + " INTERACT_ACROSS_USERS to interact cross user ");
}
}
+ verifyIncomingOp(code);
+ Preconditions.checkNotNull(token);
+ setUserRestrictionNoCheck(code, restricted, token, userHandle);
+ }
+
+ private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
+ int userHandle) {
+ final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
+ if (opRestrictions[code] == restricted) {
+ return;
+ }
+ opRestrictions[code] = restricted;
+ if (!restricted) {
+ pruneUserRestrictionsForToken(token, userHandle);
+ }
+
+ final ArrayList<Callback> clonedCallbacks;
+ synchronized (this) {
+ ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
+ if (callbacks == null) {
+ return;
+ }
+ clonedCallbacks = new ArrayList<>(callbacks);
+ }
+
+ // There are components watching for mode changes such as window manager
+ // and location manager which are in our process. The callbacks in these
+ // components may require permissions our remote caller does not have.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int callbackCount = clonedCallbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Callback callback = clonedCallbacks.get(i);
+ try {
+ callback.mCallback.opChanged(code, -1, null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error dispatching op op change", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
public void removeUser(int userHandle) throws RemoteException {
checkSystemUid("removeUser");
- mOpRestrictions.remove(userHandle);
+ final int tokenCount = mOpUserRestrictions.size();
+ for (int i = tokenCount - 1; i >= 0; i--) {
+ SparseArray<boolean[]> opRestrictions = mOpUserRestrictions.valueAt(i);
+ if (opRestrictions != null) {
+ opRestrictions.remove(userHandle);
+ if (opRestrictions.size() <= 0) {
+ mOpUserRestrictions.removeAt(i);
+ }
+ }
+ }
+ }
+
+
+ private void pruneUserRestrictionsForToken(IBinder token, int userHandle) {
+ SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token);
+ if (perTokenRestrictions != null) {
+ final boolean[] opRestrictions = perTokenRestrictions.get(userHandle);
+ if (opRestrictions != null) {
+ for (boolean restriction : opRestrictions) {
+ if (restriction) {
+ return;
+ }
+ }
+ perTokenRestrictions.remove(userHandle);
+ if (perTokenRestrictions.size() <= 0) {
+ mOpUserRestrictions.remove(token);
+ }
+ }
+ }
+ }
+
+ private boolean[] getOrCreateUserRestrictionsForToken(IBinder token, int userHandle) {
+ SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token);
+ if (perTokenRestrictions == null) {
+ perTokenRestrictions = new SparseArray<>();
+ mOpUserRestrictions.put(token, perTokenRestrictions);
+ }
+ boolean[] opRestrictions = perTokenRestrictions.get(userHandle);
+ if (opRestrictions == null) {
+ opRestrictions = new boolean[AppOpsManager._NUM_OP];
+ perTokenRestrictions.put(userHandle, opRestrictions);
+ }
+ return opRestrictions;
}
private void checkSystemUid(String function) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 499b706a2b87..8cfeb748ccee 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1671,15 +1671,23 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
@Override
- public void dump(FileDescriptor fd, PrintWriter writer, String args[]) {
- if (mBluetoothBinder == null) {
- writer.println("Bluetooth Service not connected");
- } else {
- try {
- mBluetoothBinder.dump(fd, args);
- } catch (RemoteException re) {
- writer.println("RemoteException while calling Bluetooth Service");
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+ String errorMsg = null;
+ if (mBluetoothBinder == null) {
+ errorMsg = "Bluetooth Service not connected";
+ } else {
+ try {
+ mBluetoothBinder.dump(fd, args);
+ } catch (RemoteException re) {
+ errorMsg = "RemoteException while calling Bluetooth Service";
+ }
+ }
+ if (errorMsg != null) {
+ // Silently return if we are extracting metrics in Protobuf format
+ if ((args.length > 0) && args[0].startsWith("--proto"))
+ return;
+ writer.println(errorMsg);
}
- }
}
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 423ef84dd625..62fa7d5af754 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -132,7 +132,8 @@ public class DeviceIdleController extends SystemService
private Intent mLightIdleIntent;
private Display mCurDisplay;
private AnyMotionDetector mAnyMotionDetector;
- private boolean mEnabled;
+ private boolean mLightEnabled;
+ private boolean mDeepEnabled;
private boolean mForceIdle;
private boolean mScreenOn;
private boolean mCharging;
@@ -179,7 +180,7 @@ public class DeviceIdleController extends SystemService
private static final int LIGHT_STATE_IDLE = 2;
/** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
private static final int LIGHT_STATE_IDLE_MAINTENANCE = 3;
- /** Device light idle state is overriden, now applying full doze state. */
+ /** Device light idle state is overriden, now applying deep doze state. */
private static final int LIGHT_STATE_OVERRIDE = 4;
private static String lightStateToString(int state) {
switch (state) {
@@ -288,8 +289,8 @@ public class DeviceIdleController extends SystemService
private static final int EVENT_NORMAL = 1;
private static final int EVENT_LIGHT_IDLE = 2;
private static final int EVENT_LIGHT_MAINTENANCE = 3;
- private static final int EVENT_FULL_IDLE = 4;
- private static final int EVENT_FULL_MAINTENANCE = 5;
+ private static final int EVENT_DEEP_IDLE = 4;
+ private static final int EVENT_DEEP_MAINTENANCE = 5;
private int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
private long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
@@ -835,13 +836,13 @@ public class DeviceIdleController extends SystemService
case MSG_REPORT_IDLE_ON:
case MSG_REPORT_IDLE_ON_LIGHT: {
EventLogTags.writeDeviceIdleOnStart();
- final boolean fullChanged;
+ final boolean deepChanged;
final boolean lightChanged;
if (msg.what == MSG_REPORT_IDLE_ON) {
- fullChanged = mLocalPowerManager.setDeviceIdleMode(true);
+ deepChanged = mLocalPowerManager.setDeviceIdleMode(true);
lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
} else {
- fullChanged = mLocalPowerManager.setDeviceIdleMode(false);
+ deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
lightChanged = mLocalPowerManager.setLightDeviceIdleMode(true);
}
try {
@@ -851,7 +852,7 @@ public class DeviceIdleController extends SystemService
: BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());
} catch (RemoteException e) {
}
- if (fullChanged) {
+ if (deepChanged) {
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
}
if (lightChanged) {
@@ -861,7 +862,7 @@ public class DeviceIdleController extends SystemService
} break;
case MSG_REPORT_IDLE_OFF: {
EventLogTags.writeDeviceIdleOffStart("unknown");
- final boolean fullChanged = mLocalPowerManager.setDeviceIdleMode(false);
+ final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
@@ -869,7 +870,7 @@ public class DeviceIdleController extends SystemService
null, Process.myUid());
} catch (RemoteException e) {
}
- if (fullChanged) {
+ if (deepChanged) {
incActiveIdleOps();
getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,
null, mIdleStartedDoneReceiver, null, 0, null, null);
@@ -889,7 +890,7 @@ public class DeviceIdleController extends SystemService
int activeUid = msg.arg1;
EventLogTags.writeDeviceIdleOffStart(
activeReason != null ? activeReason : "unknown");
- final boolean fullChanged = mLocalPowerManager.setDeviceIdleMode(false);
+ final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);
final boolean lightChanged = mLocalPowerManager.setLightDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
@@ -897,7 +898,7 @@ public class DeviceIdleController extends SystemService
activeReason, activeUid);
} catch (RemoteException e) {
}
- if (fullChanged) {
+ if (deepChanged) {
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
}
if (lightChanged) {
@@ -1102,7 +1103,7 @@ public class DeviceIdleController extends SystemService
final PackageManager pm = getContext().getPackageManager();
synchronized (this) {
- mEnabled = getContext().getResources().getBoolean(
+ mLightEnabled = mDeepEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableAutoPowerModes);
SystemConfig sysConfig = SystemConfig.getInstance();
ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();
@@ -1262,6 +1263,12 @@ public class DeviceIdleController extends SystemService
return false;
}
+ public boolean getPowerSaveWhitelistAppInternal(String name) {
+ synchronized (this) {
+ return mPowerSaveWhitelistUserApps.containsKey(name);
+ }
+ }
+
public String[] getSystemPowerWhitelistExceptIdleInternal() {
synchronized (this) {
int size = mPowerSaveWhitelistAppsExceptIdle.size();
@@ -1544,17 +1551,17 @@ public class DeviceIdleController extends SystemService
void becomeInactiveIfAppropriateLocked() {
if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
- if (((!mScreenOn && !mCharging) || mForceIdle) && mEnabled) {
+ if ((!mScreenOn && !mCharging) || mForceIdle) {
// Screen has turned off; we are now going to become inactive and start
// waiting to see if we will ultimately go idle.
- if (mState == STATE_ACTIVE) {
+ if (mState == STATE_ACTIVE && mDeepEnabled) {
mState = STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
resetIdleManagementLocked();
scheduleAlarmLocked(mInactiveTimeout, false);
EventLogTags.writeDeviceIdle(mState, "no activity");
}
- if (mLightState == LIGHT_STATE_ACTIVE) {
+ if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
mLightState = LIGHT_STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
@@ -1588,7 +1595,7 @@ public class DeviceIdleController extends SystemService
void stepLightIdleStateLocked(String reason) {
if (mLightState == LIGHT_STATE_OVERRIDE) {
- // If we are already in full device idle mode, then
+ // If we are already in deep device idle mode, then
// there is nothing left to do for light mode.
return;
}
@@ -1725,7 +1732,7 @@ public class DeviceIdleController extends SystemService
cancelLightAlarmLocked();
}
EventLogTags.writeDeviceIdle(mState, reason);
- addEvent(EVENT_FULL_IDLE);
+ addEvent(EVENT_DEEP_IDLE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
case STATE_IDLE:
@@ -1738,7 +1745,7 @@ public class DeviceIdleController extends SystemService
(long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
mState = STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdle(mState, reason);
- addEvent(EVENT_FULL_MAINTENANCE);
+ addEvent(EVENT_DEEP_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
}
@@ -1871,7 +1878,7 @@ public class DeviceIdleController extends SystemService
becomeInactive = true;
}
if (mLightState == LIGHT_STATE_OVERRIDE) {
- // We went out of light idle mode because we had started full idle mode... let's
+ // We went out of light idle mode because we had started deep idle mode... let's
// now go back and reset things so we resume light idling if appropriate.
mLightState = STATE_ACTIVE;
EventLogTags.writeDeviceIdleLight(mLightState, type);
@@ -2177,11 +2184,11 @@ public class DeviceIdleController extends SystemService
pw.println(" force-idle");
pw.println(" Force directly into idle mode, regardless of other device state.");
pw.println(" Use \"step\" to get out.");
- pw.println(" disable");
+ pw.println(" disable [light|deep|all]");
pw.println(" Completely disable device idle mode.");
- pw.println(" enable");
+ pw.println(" enable [light|deep|all]");
pw.println(" Re-enable device idle mode after it had previously been disabled.");
- pw.println(" enabled");
+ pw.println(" enabled [light|deep|all]");
pw.println(" Print 1 if device idle mode is currently enabled, else 0.");
pw.println(" whitelist");
pw.println(" Print currently whitelisted apps.");
@@ -2241,7 +2248,7 @@ public class DeviceIdleController extends SystemService
synchronized (this) {
long token = Binder.clearCallingIdentity();
try {
- if (!mEnabled) {
+ if (!mDeepEnabled) {
pw.println("Unable to go idle; not enabled");
return -1;
}
@@ -2268,11 +2275,32 @@ public class DeviceIdleController extends SystemService
null);
synchronized (this) {
long token = Binder.clearCallingIdentity();
+ String arg = shell.getNextArg();
try {
- if (mEnabled) {
- mEnabled = false;
- becomeActiveLocked("disabled", Process.myUid());
- pw.println("Idle mode disabled");
+ boolean becomeActive = false;
+ boolean valid = false;
+ if (arg == null || "deep".equals(arg) || "all".equals(arg)) {
+ valid = true;
+ if (mDeepEnabled) {
+ mDeepEnabled = false;
+ becomeActive = true;
+ pw.println("Deep idle mode disabled");
+ }
+ }
+ if (arg == null || "light".equals(arg) || "all".equals(arg)) {
+ valid = true;
+ if (mLightEnabled) {
+ mLightEnabled = false;
+ becomeActive = true;
+ pw.println("Light idle mode disabled");
+ }
+ }
+ if (becomeActive) {
+ becomeActiveLocked((arg == null ? "all" : arg) + "-disabled",
+ Process.myUid());
+ }
+ if (!valid) {
+ pw.println("Unknown idle mode: " + arg);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -2283,12 +2311,31 @@ public class DeviceIdleController extends SystemService
null);
synchronized (this) {
long token = Binder.clearCallingIdentity();
+ String arg = shell.getNextArg();
try {
- exitForceIdleLocked();
- if (!mEnabled) {
- mEnabled = true;
+ boolean becomeInactive = false;
+ boolean valid = false;
+ if (arg == null || "deep".equals(arg) || "all".equals(arg)) {
+ valid = true;
+ if (!mDeepEnabled) {
+ mDeepEnabled = true;
+ becomeInactive = true;
+ pw.println("Deep idle mode enabled");
+ }
+ }
+ if (arg == null || "light".equals(arg) || "all".equals(arg)) {
+ valid = true;
+ if (!mLightEnabled) {
+ mLightEnabled = true;
+ becomeInactive = true;
+ pw.println("Light idle mode enable");
+ }
+ }
+ if (becomeInactive) {
becomeInactiveIfAppropriateLocked();
- pw.println("Idle mode enabled");
+ }
+ if (!valid) {
+ pw.println("Unknown idle mode: " + arg);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -2296,7 +2343,16 @@ public class DeviceIdleController extends SystemService
}
} else if ("enabled".equals(cmd)) {
synchronized (this) {
- pw.println(mEnabled ? "1" : " 0");
+ String arg = shell.getNextArg();
+ if (arg == null || "all".equals(arg)) {
+ pw.println(mDeepEnabled && mLightEnabled ? "1" : 0);
+ } else if ("deep".equals(arg)) {
+ pw.println(mDeepEnabled ? "1" : 0);
+ } else if ("light".equals(arg)) {
+ pw.println(mLightEnabled ? "1" : 0);
+ } else {
+ pw.println("Unknown idle mode: " + arg);
+ }
}
} else if ("whitelist".equals(cmd)) {
long token = Binder.clearCallingIdentity();
@@ -2307,8 +2363,8 @@ public class DeviceIdleController extends SystemService
android.Manifest.permission.DEVICE_POWER, null);
do {
if (arg.length() < 1 || (arg.charAt(0) != '-'
- && arg.charAt(0) != '+')) {
- pw.println("Package must be prefixed with + or -: " + arg);
+ && arg.charAt(0) != '+' && arg.charAt(0) != '=')) {
+ pw.println("Package must be prefixed with +, -, or =: " + arg);
return -1;
}
char op = arg.charAt(0);
@@ -2319,10 +2375,12 @@ public class DeviceIdleController extends SystemService
} else {
pw.println("Unknown package: " + pkg);
}
- } else {
+ } else if (op == '-') {
if (removePowerSaveWhitelistAppInternal(pkg)) {
pw.println("Removed: " + pkg);
}
+ } else {
+ pw.println(getPowerSaveWhitelistAppInternal(pkg));
}
} while ((arg=shell.getNextArg()) != null);
} else {
@@ -2433,8 +2491,8 @@ public class DeviceIdleController extends SystemService
case EVENT_NORMAL: label = " normal"; break;
case EVENT_LIGHT_IDLE: label = " light-idle"; break;
case EVENT_LIGHT_MAINTENANCE: label = "light-maint"; break;
- case EVENT_FULL_IDLE: label = " full-idle"; break;
- case EVENT_FULL_MAINTENANCE: label = " full-maint"; break;
+ case EVENT_DEEP_IDLE: label = " deep-idle"; break;
+ case EVENT_DEEP_MAINTENANCE: label = " deep-maint"; break;
default: label = " ??"; break;
}
pw.print(" ");
@@ -2511,7 +2569,8 @@ public class DeviceIdleController extends SystemService
}
}
- pw.print(" mEnabled="); pw.println(mEnabled);
+ pw.print(" mLightEnabled="); pw.print(mLightEnabled);
+ pw.print(" mDeepEnabled="); pw.println(mDeepEnabled);
pw.print(" mForceIdle="); pw.println(mForceIdle);
pw.print(" mMotionSensor="); pw.println(mMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
new file mode 100644
index 000000000000..cc21e99371e4
--- /dev/null
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.CpuUsageInfo;
+import android.os.IHardwarePropertiesManager;
+
+import java.util.Arrays;
+
+/**
+ * Service for {@link HardwarePropertiesManager}
+ */
+public class HardwarePropertiesManagerService extends IHardwarePropertiesManager.Stub {
+
+ private static native void nativeInit();
+
+ private static native float[] nativeGetFanSpeeds();
+ private static native float[] nativeGetDeviceTemperatures(int type);
+ private static native CpuUsageInfo[] nativeGetCpuUsages();
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ public HardwarePropertiesManagerService(Context context) {
+ mContext = context;
+ synchronized (mLock) {
+ nativeInit();
+ }
+ }
+
+ @Override
+ public float[] getDeviceTemperatures(String callingPackage, int type) throws SecurityException {
+ enforceHardwarePropertiesRetrievalAllowed(callingPackage);
+ synchronized (mLock) {
+ return nativeGetDeviceTemperatures(type);
+ }
+ }
+
+ @Override
+ public CpuUsageInfo[] getCpuUsages(String callingPackage) throws SecurityException {
+ enforceHardwarePropertiesRetrievalAllowed(callingPackage);
+ synchronized (mLock) {
+ return nativeGetCpuUsages();
+ }
+ }
+
+ @Override
+ public float[] getFanSpeeds(String callingPackage) throws SecurityException {
+ enforceHardwarePropertiesRetrievalAllowed(callingPackage);
+ synchronized (mLock) {
+ return nativeGetFanSpeeds();
+ }
+ }
+
+ /**
+ * Throws SecurityException if the calling package is not allowed to retrieve information
+ * provided by the service.
+ *
+ * @param callingPackage The calling package name.
+ *
+ * @throws SecurityException if a non profile or device owner tries to retrieve information
+ * provided by the service.
+ */
+ private void enforceHardwarePropertiesRetrievalAllowed(String callingPackage)
+ throws SecurityException {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ final int uid = pm.getPackageUid(callingPackage, 0);
+ if (Binder.getCallingUid() != uid) {
+ throw new SecurityException("The caller has faked the package name.");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new SecurityException("The caller has faked the package name.");
+ }
+
+ final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)) {
+ throw new SecurityException("The caller is not a device or profile owner.");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index d77def67ab52..63c9822d82c8 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -61,7 +61,6 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
@@ -96,6 +95,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
+import android.util.LocaleList;
import android.util.LruCache;
import android.util.Pair;
import android.util.PrintWriterPrinter;
@@ -136,7 +136,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
-import java.util.Locale;
/**
* This class provides a system service that manages input methods.
@@ -190,6 +189,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private InputMethodFileManager mFileManager;
private final HardKeyboardListener mHardKeyboardListener;
private final AppOpsManager mAppOpsManager;
+ private final UserManager mUserManager;
final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1);
@@ -446,7 +446,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private View mSwitchingDialogTitleView;
private InputMethodInfo[] mIms;
private int[] mSubtypeIds;
- private Locale mLastSystemLocale;
+ private LocaleList mLastSystemLocales;
private boolean mShowImeWithHardKeyboard;
private boolean mAccessibilityRequestingNoSoftKeyboard;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
@@ -666,8 +666,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- buildInputMethodListLocked(
- mMethodList, mMethodMap, false /* resetDefaultEnabledIme */);
+ buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
boolean changed = false;
@@ -782,6 +781,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mService.systemRunning(statusBarService);
}
}
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mService.onUnlockUser(userHandle);
+ }
+ }
+
+ public void onUnlockUser(int userId) {
+ synchronized(mMethodMap) {
+ final int currentUserId = mSettings.getCurrentUserId();
+ if (DEBUG) {
+ Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
+ }
+ if (userId != currentUserId) {
+ return;
+ }
+ mSettings.switchCurrentUser(currentUserId, !mSystemReady);
+ // We need to rebuild IMEs.
+ buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
+ updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+ }
}
public InputMethodManagerService(Context context) {
@@ -800,7 +820,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
handleMessage(msg);
}
}, true /*asyncHandler*/);
- mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ mUserManager = mContext.getSystemService(UserManager.class);
mHardKeyboardListener = new HardKeyboardListener();
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
@@ -858,38 +879,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(
- mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
-
- // Let the package manager query which are the default imes
- // as they get certain permissions granted by default.
- PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- packageManagerInternal.setImePackagesProvider(
- new PackageManagerInternal.PackagesProvider() {
- @Override
- public String[] getPackages(int userId) {
- synchronized (mMethodMap) {
- final int currentUserId = mSettings.getCurrentUserId();
- // TODO: We are switching the current user id in the settings
- // object to query it and then revert the user id. Ideally, we
- // should call a API in settings with the user id as an argument.
- mSettings.setCurrentUserId(userId);
- List<InputMethodInfo> imes = mSettings
- .getEnabledInputMethodListLocked();
- String[] packageNames = null;
- if (imes != null) {
- final int imeCount = imes.size();
- packageNames = new String[imeCount];
- for (int i = 0; i < imeCount; i++) {
- InputMethodInfo ime = imes.get(i);
- packageNames[i] = ime.getPackageName();
- }
- }
- mSettings.setCurrentUserId(currentUserId);
- return packageNames;
- }
- }
- });
+ mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady);
updateCurrentProfileIds();
mFileManager = new InputMethodFileManager(mMethodMap, userId);
@@ -906,8 +896,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
synchronized (mMethodMap) {
- buildInputMethodListLocked(mMethodList, mMethodMap,
- !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
+ buildInputMethodListLocked(!mImeSelectedOnBoot /* resetDefaultEnabledIme */);
}
mSettings.enableAllIMEsIfThereIsNoEnabledIME();
@@ -940,35 +929,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private void resetDefaultImeLocked(Context context) {
// Do not reset the default (current) IME when it is a 3rd-party IME
- if (mCurMethodId != null
- && !InputMethodUtils.isSystemIme(mMethodMap.get(mCurMethodId))) {
+ if (mCurMethodId != null && !InputMethodUtils.isSystemIme(mMethodMap.get(mCurMethodId))) {
return;
}
-
- InputMethodInfo defIm = null;
- for (InputMethodInfo imi : mMethodList) {
- if (defIm == null && mSystemReady) {
- final Locale systemLocale = context.getResources().getConfiguration().locale;
- if (InputMethodUtils.isSystemImeThatHasSubtypeOf(imi, context,
- true /* checkDefaultAttribute */, systemLocale, false /* checkCountry */,
- InputMethodUtils.SUBTYPE_MODE_ANY)) {
- defIm = imi;
- Slog.i(TAG, "Selected default: " + imi.getId());
- }
- }
- }
- if (defIm == null && mMethodList.size() > 0) {
- defIm = InputMethodUtils.getMostApplicableDefaultIME(
- mSettings.getEnabledInputMethodListLocked());
- if (defIm != null) {
- Slog.i(TAG, "Default found, using " + defIm.getId());
- } else {
- Slog.i(TAG, "No default found");
- }
- }
- if (defIm != null) {
- setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
+ final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
+ context, mSystemReady, 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());
+ setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
}
private void resetAllInternalStateLocked(final boolean updateOnlyWhenLocaleChanged,
@@ -977,17 +949,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// not system ready
return;
}
- final Locale newLocale = mRes.getConfiguration().locale;
+ final LocaleList newLocales = mRes.getConfiguration().getLocales();
if (!updateOnlyWhenLocaleChanged
- || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
+ || (newLocales != null && !newLocales.equals(mLastSystemLocales))) {
if (!updateOnlyWhenLocaleChanged) {
hideCurrentInputLocked(0, null);
resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_RESET_IME);
}
if (DEBUG) {
- Slog.i(TAG, "Locale has been changed to " + newLocale);
+ Slog.i(TAG, "LocaleList has been changed to " + newLocales);
}
- buildInputMethodListLocked(mMethodList, mMethodMap, resetDefaultEnabledIme);
+ buildInputMethodListLocked(resetDefaultEnabledIme);
if (!updateOnlyWhenLocaleChanged) {
final String selectedImiId = mSettings.getSelectedInputMethod();
if (TextUtils.isEmpty(selectedImiId)) {
@@ -1000,7 +972,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
resetDefaultImeLocked(mContext);
}
updateFromSettingsLocked(true);
- mLastSystemLocale = newLocale;
+ mLastSystemLocales = newLocales;
if (!updateOnlyWhenLocaleChanged) {
try {
startInputInnerLocked();
@@ -1022,7 +994,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// ContentObserver should be registered again when the user is changed
mSettingsObserver.registerContentObserverLocked(newUserId);
- mSettings.setCurrentUserId(newUserId);
+
+ // If the system is not ready or the device is not yed unlocked by the user, then we use
+ // copy-on-write settings.
+ final boolean useCopyOnWriteSettings =
+ !mSystemReady || !mUserManager.isUserUnlocked(newUserId);
+ mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
updateCurrentProfileIds();
// InputMethodFileManager should be reset when the user is changed
mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
@@ -1050,8 +1027,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
void updateCurrentProfileIds() {
- List<UserInfo> profiles =
- UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+ List<UserInfo> profiles = mUserManager.getProfiles(mSettings.getCurrentUserId());
int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
for (int i = 0; i < currentProfileIds.length; i++) {
currentProfileIds[i] = profiles.get(i).id;
@@ -1081,10 +1057,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (!mSystemReady) {
mSystemReady = true;
- mKeyguardManager =
- (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ final int currentUserId = mSettings.getCurrentUserId();
+ mSettings.switchCurrentUser(currentUserId,
+ !mUserManager.isUserUnlocked(currentUserId));
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
mStatusBar = statusBar;
statusBar.setIconVisibility(mSlotIme, false);
updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
@@ -1094,8 +1071,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
mHardKeyboardListener);
}
- buildInputMethodListLocked(mMethodList, mMethodMap,
- !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
+ buildInputMethodListLocked(!mImeSelectedOnBoot /* resetDefaultEnabledIme */);
if (!mImeSelectedOnBoot) {
Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
resetStateIfCurrentLocaleChangedLocked();
@@ -1103,7 +1079,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mSettings.getEnabledInputMethodListLocked(),
mSettings.getCurrentUserId(), mContext.getBasePackageName());
}
- mLastSystemLocale = mRes.getConfiguration().locale;
+ mLastSystemLocales = mRes.getConfiguration().getLocales();
try {
startInputInnerLocked();
} catch (RuntimeException e) {
@@ -1482,8 +1458,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return null;
}
- @Override
- public InputBindResult startInput(
+ private InputBindResult startInput(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
int controlFlags) {
@@ -2221,7 +2196,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public InputBindResult windowGainedFocus(
+ public InputBindResult startInputOrWindowGainedFocus(
+ /* @InputMethodClient.StartInputReason */ final int startInputReason,
+ IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
+ int windowFlags, EditorInfo attribute, IInputContext inputContext) {
+ if (windowToken != null) {
+ return windowGainedFocus(startInputReason, client, windowToken, controlFlags,
+ softInputMode, windowFlags, attribute, inputContext);
+ } else {
+ return startInput(startInputReason, client, inputContext, attribute, controlFlags);
+ }
+ }
+
+ private InputBindResult windowGainedFocus(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext) {
@@ -2601,8 +2588,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mFileManager.addInputMethodSubtypes(imi, subtypes);
final long ident = Binder.clearCallingIdentity();
try {
- buildInputMethodListLocked(mMethodList, mMethodMap,
- false /* resetDefaultEnabledIme */);
+ buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2957,18 +2943,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return false;
}
- void buildInputMethodListLocked(ArrayList<InputMethodInfo> list,
- HashMap<String, InputMethodInfo> map, boolean resetDefaultEnabledIme) {
+ void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
if (DEBUG) {
Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
+ " \n ------ caller=" + Debug.getCallers(10));
}
- list.clear();
- map.clear();
+ mMethodList.clear();
+ mMethodMap.clear();
// Use for queryIntentServicesAsUser
final PackageManager pm = mContext.getPackageManager();
+ // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
+ // behavior of PackageManager is exactly what we want. It by default picks up appropriate
+ // services depending on the unlock state for the specified user.
final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
new Intent(InputMethod.SERVICE_INTERFACE),
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
@@ -2992,9 +2980,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
InputMethodInfo p = new InputMethodInfo(mContext, ri, additionalSubtypes);
- list.add(p);
+ mMethodList.add(p);
final String id = p.getId();
- map.put(id, p);
+ mMethodMap.put(id, p);
if (DEBUG) {
Slog.d(TAG, "Found an input method " + p);
@@ -3004,10 +2992,30 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ // TODO: The following code should find better place to live.
+ if (!resetDefaultEnabledIme) {
+ boolean enabledImeFound = false;
+ final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
+ final int N = enabledImes.size();
+ for (int i = 0; i < N; ++i) {
+ final InputMethodInfo imi = enabledImes.get(i);
+ if (mMethodList.contains(imi)) {
+ enabledImeFound = true;
+ break;
+ }
+ }
+ if (!enabledImeFound) {
+ Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
+ resetDefaultEnabledIme = true;
+ resetSelectedInputMethodAndSubtypeLocked("");
+ }
+ }
+
if (resetDefaultEnabledIme) {
final ArrayList<InputMethodInfo> defaultEnabledIme =
- InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, list);
- for (int i = 0; i < defaultEnabledIme.size(); ++i) {
+ InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, mMethodList);
+ final int N = defaultEnabledIme.size();
+ for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = defaultEnabledIme.get(i);
if (DEBUG) {
Slog.d(TAG, "--- enable ime = " + imi);
@@ -3018,7 +3026,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final String defaultImiId = mSettings.getSelectedInputMethod();
if (!TextUtils.isEmpty(defaultImiId)) {
- if (!map.containsKey(defaultImiId)) {
+ if (!mMethodMap.containsKey(defaultImiId)) {
Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
if (chooseNewDefaultIMELocked()) {
updateInputMethodsFromSettingsLocked(true);
@@ -3137,8 +3145,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mDialogBuilder.setIcon(dialogIcon);
- final LayoutInflater inflater = (LayoutInflater) dialogContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
+ final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
final View tv = inflater.inflate(
com.android.internal.R.layout.input_method_switch_dialog_title, null);
mDialogBuilder.setCustomTitle(tv);
@@ -3222,7 +3229,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mTextViewResourceId = textViewResourceId;
mItemsList = itemsList;
mCheckedItem = checkedItem;
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mInflater = context.getSystemService(LayoutInflater.class);
}
@Override
@@ -3370,16 +3377,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- // Workaround.
- // ASEC is not ready in the IMMS constructor. Accordingly, forward-locked
- // IMEs are not recognized and considered uninstalled.
- // Actually, we can't move everything after SystemReady because
- // IMMS needs to run in the encryption lock screen. So, we just skip changing
- // the default IME here and try cheking the default IME again in systemReady().
- // TODO: Do nothing before system ready and implement a separated logic for
- // the encryption lock screen.
- // TODO: ASEC should be ready before IMMS is instantiated.
- if (mSystemReady && !setSubtypeOnly) {
+ if (!setSubtypeOnly) {
// Set InputMethod here
mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
}
@@ -3860,6 +3858,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
p.println(" mSettingsObserver=" + mSettingsObserver);
p.println(" mSwitchingController:");
mSwitchingController.dump(p);
+ p.println(" mSettings:");
+ mSettings.dumpLocked(p, " ");
}
p.println(" ");
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 14ddc363f392..9884a70a2ca9 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -214,7 +214,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
- private GnssLocationProvider.GpsSystemInfoProvider mGpsSystemInfoProvider;
+ private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
public LocationManagerService(Context context) {
super();
@@ -462,7 +462,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// Create a gps location provider
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
- mGpsSystemInfoProvider = gnssProvider.getGpsSystemInfoProvider();
+ mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
addProviderLocked(gnssProvider);
@@ -990,12 +990,12 @@ public class LocationManagerService extends ILocationManager.Stub {
}
/**
- * Returns the system information of the GPS hardware.
+ * Returns the system information of the GNSS hardware.
*/
@Override
- public int getGpsYearOfHardware() {
+ public int getGnssYearOfHardware() {
if (mGnssNavigationMessageProvider != null) {
- return mGpsSystemInfoProvider.getGpsYearOfHardware();
+ return mGnssSystemInfoProvider.getGnssYearOfHardware();
} else {
return 0;
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 4dbb49005c28..c318140ae7e8 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -34,6 +35,7 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
+import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_CONTACTS;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -124,7 +126,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+ mLockSettingsService.maybeShowEncryptionNotifications();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
// TODO
}
@@ -176,22 +178,48 @@ public class LockSettingsService extends ILockSettings.Stub {
* If the account is credential-encrypted, show notification requesting the user to unlock
* the device.
*/
- private void maybeShowEncryptionNotification(UserHandle userHandle) {
- if (UserHandle.ALL.equals(userHandle)) {
- final List<UserInfo> users = mUserManager.getUsers();
- for (int i = 0; i < users.size(); i++) {
- UserHandle user = users.get(i).getUserHandle();
- if (!mUserManager.isUserUnlocked(user)) {
- showEncryptionNotification(user);
+ private void maybeShowEncryptionNotifications() {
+ final List<UserInfo> users = mUserManager.getUsers();
+ for (int i = 0; i < users.size(); i++) {
+ UserInfo user = users.get(i);
+ UserHandle userHandle = user.getUserHandle();
+ if (!mUserManager.isUserUnlocked(userHandle)) {
+ if (!user.isManagedProfile()) {
+ showEncryptionNotification(userHandle);
+ } else {
+ UserInfo parent = mUserManager.getProfileParent(user.id);
+ if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) {
+ // Only show notifications for managed profiles once their parent
+ // user is unlocked.
+ showEncryptionNotificationForProfile(userHandle);
+ }
}
}
- } else if (!mUserManager.isUserUnlocked(userHandle)){
- showEncryptionNotification(userHandle);
}
}
+ private void showEncryptionNotificationForProfile(UserHandle user) {
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.user_encrypted_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.profile_encrypted_message);
+ CharSequence detail = r.getText(
+ com.android.internal.R.string.profile_encrypted_detail);
+
+ final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
+ final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
+ if (unlockIntent == null) {
+ return;
+ }
+ unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ showEncryptionNotification(user, title, message, detail, intent);
+ }
+
private void showEncryptionNotification(UserHandle user) {
- if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Resources r = mContext.getResources();
CharSequence title = r.getText(
com.android.internal.R.string.user_encrypted_title);
@@ -203,6 +231,12 @@ public class LockSettingsService extends ILockSettings.Stub {
PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
PendingIntent.FLAG_UPDATE_CURRENT);
+ showEncryptionNotification(user, title, message, detail, intent);
+ }
+
+ private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
+ CharSequence detail, PendingIntent intent) {
+ if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Notification notification = new Notification.Builder(mContext)
.setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
.setWhen(0)
@@ -230,8 +264,21 @@ public class LockSettingsService extends ILockSettings.Stub {
hideEncryptionNotification(new UserHandle(userId));
}
- public void onUnlockUser(int userHandle) {
- hideEncryptionNotification(new UserHandle(userHandle));
+ public void onUnlockUser(int userId) {
+ hideEncryptionNotification(new UserHandle(userId));
+
+ // Now we have unlocked the parent user we should show notifications
+ // about any profiles that exist.
+ List<UserInfo> profiles = mUserManager.getProfiles(userId);
+ for (int i = 0; i < profiles.size(); i++) {
+ UserInfo profile = profiles.get(i);
+ if (profile.isManagedProfile()) {
+ UserHandle userHandle = profile.getUserHandle();
+ if (!mUserManager.isUserUnlocked(userHandle)) {
+ showEncryptionNotificationForProfile(userHandle);
+ }
+ }
+ }
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index cbd477a9500b..53923ba972c7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -844,6 +844,7 @@ class MountService extends IMountService.Stub
// user directories are locked or unlocked based on the current
// emulation status.
final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
+ Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
for (UserInfo user : users) {
try {
@@ -851,7 +852,7 @@ class MountService extends IMountService.Stub
mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
} else {
mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
- user.serialNumber, "!");
+ user.serialNumber, "!", "!");
}
} catch (NativeDaemonConnectorException e) {
Slog.w(TAG, "Failed to init vold", e);
@@ -1473,7 +1474,7 @@ class MountService extends IMountService.Stub
}
mSettingsFile = new AtomicFile(
- new File(Environment.getSystemSecureDirectory(), "storage.xml"));
+ new File(Environment.getDataSystemDirectory(), "storage.xml"));
synchronized (mLock) {
readSettingsLocked();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 95f57346dcfc..799d0bda895f 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2086,7 +2086,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
if (DBG) {
Slog.d(TAG, "oldRule = " + oldUidFirewallRule
- + ", newRule=" + rule + " for uid=" + uid);
+ + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
}
if (oldUidFirewallRule == rule) {
if (DBG) Slog.d(TAG, "!!!!! Skipping change");
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b984e1938758..879bb6f72895 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -234,12 +234,24 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
// safety as scores should never be compared across apps; in practice, Settings should
// only be allowing valid apps to be set as scorers, so failure here should be rare.
clearInternal();
+ // Get the scorer that is about to be replaced, if any, so we can notify it directly.
+ NetworkScorerAppData prevScorer = NetworkScorerAppManager.getActiveScorer(mContext);
boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
- if (result) {
+ if (result) { // new scorer successfully set
registerPackageReceiverIfNeeded();
Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
- intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ if (prevScorer != null) { // Directly notify the old scorer.
+ intent.setPackage(prevScorer.mPackageName);
+ // TODO: Need to update when we support per-user scorers. http://b/23422763
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ }
+
+ if (packageName != null) { // Then notify the new scorer
+ intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
+ intent.setPackage(packageName);
+ // TODO: Need to update when we support per-user scorers. http://b/23422763
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ }
}
return result;
} finally {
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index a291cc72ea60..2085f3277648 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -27,6 +27,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.persistentdata.IPersistentDataBlockService;
+import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Slog;
import com.android.internal.R;
@@ -72,6 +73,9 @@ public class PersistentDataBlockService extends SystemService {
private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
public static final int DIGEST_SIZE_BYTES = 32;
private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed";
+ private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked";
+ private static final String FLASH_LOCK_LOCKED = "1";
+ private static final String FLASH_LOCK_UNLOCKED = "0";
private final Context mContext;
private final String mDataBlockFile;
@@ -454,6 +458,20 @@ public class PersistentDataBlockService extends SystemService {
}
@Override
+ public int getFlashLockState() {
+ enforceOemUnlockPermission();
+ String locked = SystemProperties.get(FLASH_LOCK_PROP);
+ switch (locked) {
+ case FLASH_LOCK_LOCKED:
+ return PersistentDataBlockManager.FLASH_LOCK_LOCKED;
+ case FLASH_LOCK_UNLOCKED:
+ return PersistentDataBlockManager.FLASH_LOCK_UNLOCKED;
+ default:
+ return PersistentDataBlockManager.FLASH_LOCK_UNKNOWN;
+ }
+ }
+
+ @Override
public int getDataBlockSize() {
enforcePersistentDataBlockAccess();
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
new file mode 100644
index 000000000000..d237fe7b4c3e
--- /dev/null
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -0,0 +1,214 @@
+/*
+ * 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 android.content.Context;
+import android.os.IRecoverySystem;
+import android.os.IRecoverySystemProgressListener;
+import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Slog;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * The recovery system service is responsible for coordinating recovery related
+ * functions on the device. It sets up (or clears) the bootloader control block
+ * (BCB), which will be read by the bootloader and the recovery image. It also
+ * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
+ * /data partition so that it can be accessed under the recovery image.
+ */
+public final class RecoverySystemService extends SystemService {
+ private static final String TAG = "RecoverySystemService";
+ private static final boolean DEBUG = false;
+
+ // A pipe file to monitor the uncrypt progress.
+ private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
+ // Temporary command file to communicate between the system server and uncrypt.
+ private static final String COMMAND_FILE = "/cache/recovery/command";
+
+ private Context mContext;
+
+ public RecoverySystemService(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.RECOVERY_SERVICE, new BinderService());
+ }
+
+ private final class BinderService extends IRecoverySystem.Stub {
+ @Override // Binder call
+ public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
+ if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
+
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+ // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
+ // uncrypt.
+ RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+
+ try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
+ uncryptFile.write(filename + "\n");
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
+ "\": " + e.getMessage());
+ return false;
+ }
+
+ // Create the status pipe file to communicate with uncrypt.
+ new File(UNCRYPT_STATUS_FILE).delete();
+ try {
+ Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
+ } catch (ErrnoException e) {
+ Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
+ "\": " + e.getMessage());
+ return false;
+ }
+
+ // Trigger uncrypt via init.
+ SystemProperties.set("ctl.start", "uncrypt");
+
+ // Read the status from the pipe.
+ try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) {
+ int lastStatus = Integer.MIN_VALUE;
+ while (true) {
+ String str = reader.readLine();
+ try {
+ int status = Integer.parseInt(str);
+
+ // Avoid flooding the log with the same message.
+ if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+ continue;
+ }
+ lastStatus = status;
+
+ if (status >= 0 && status <= 100) {
+ // Update status
+ Slog.i(TAG, "uncrypt read status: " + status);
+ if (listener != null) {
+ try {
+ listener.onProgress(status);
+ } catch (RemoteException unused) {
+ Slog.w(TAG, "RemoteException when posting progress");
+ }
+ }
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt successfully finished.");
+ break;
+ }
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ return false;
+ }
+ } catch (NumberFormatException unused) {
+ Slog.e(TAG, "uncrypt invalid status received: " + str);
+ return false;
+ }
+ }
+ } catch (IOException unused) {
+ Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override // Binder call
+ public boolean clearBcb() {
+ if (DEBUG) Slog.d(TAG, "clearBcb");
+ return setupOrClearBcb(false, null);
+ }
+
+ @Override // Binder call
+ public boolean setupBcb(String command) {
+ if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
+ return setupOrClearBcb(true, command);
+ }
+
+ private boolean setupOrClearBcb(boolean isSetup, String command) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+ if (isSetup) {
+ // Set up the command file to be read by uncrypt.
+ try (FileWriter commandFile = new FileWriter(COMMAND_FILE)) {
+ commandFile.write(command + "\n");
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when writing \"" + COMMAND_FILE +
+ "\": " + e.getMessage());
+ return false;
+ }
+ }
+
+ // Create the status pipe file to communicate with uncrypt.
+ new File(UNCRYPT_STATUS_FILE).delete();
+ try {
+ Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
+ } catch (ErrnoException e) {
+ Slog.e(TAG, "ErrnoException when creating named pipe \"" +
+ UNCRYPT_STATUS_FILE + "\": " + e.getMessage());
+ return false;
+ }
+
+ if (isSetup) {
+ SystemProperties.set("ctl.start", "setup-bcb");
+ } else {
+ SystemProperties.set("ctl.start", "clear-bcb");
+ }
+
+ // Read the status from the pipe.
+ try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) {
+ while (true) {
+ String str = reader.readLine();
+ try {
+ int status = Integer.parseInt(str);
+
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
+ " bcb successfully finished.");
+ break;
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ return false;
+ }
+ } catch (NumberFormatException unused) {
+ Slog.e(TAG, "uncrypt invalid status received: " + str);
+ return false;
+ }
+ }
+ } catch (IOException unused) {
+ Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+ return false;
+ }
+
+ // Delete the command file as we don't need it anymore.
+ new File(COMMAND_FILE).delete();
+ return true;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 60621374baad..383e25a6d293 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -32,13 +33,16 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
/**
* Find the best Service, and bind to it.
@@ -64,17 +68,21 @@ public class ServiceWatcher implements ServiceConnection {
private final Runnable mNewServiceWork;
private final Handler mHandler;
- private Object mLock = new Object();
+ private final Object mLock = new Object();
- // all fields below synchronized on mLock
- private IBinder mBinder; // connected service
- private String mPackageName; // current best package
- private int mVersion = Integer.MIN_VALUE; // current best version
- /**
- * Whether the currently-connected service is multiuser-aware. This can change at run-time
- * when switching from one version of a service to another.
- */
- private boolean mIsMultiuser = false;
+ @GuardedBy("mLock")
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+
+ @GuardedBy("mLock")
+ private IBinder mBoundService;
+ @GuardedBy("mLock")
+ private ComponentName mBoundComponent;
+ @GuardedBy("mLock")
+ private String mBoundPackageName;
+ @GuardedBy("mLock")
+ private int mBoundVersion = Integer.MIN_VALUE;
+ @GuardedBy("mLock")
+ private int mBoundUserId = UserHandle.USER_NULL;
public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
List<String> initialPackageNames) {
@@ -84,7 +92,8 @@ public class ServiceWatcher implements ServiceConnection {
String pkg = initialPackageNames.get(i);
try {
HashSet<Signature> set = new HashSet<Signature>();
- Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
+ Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.GET_SIGNATURES).signatures;
set.addAll(Arrays.asList(sigs));
sigSets.add(set);
} catch (NameNotFoundException e) {
@@ -108,7 +117,7 @@ public class ServiceWatcher implements ServiceConnection {
// Whether to enable service overlay.
boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
- ArrayList<String> initialPackageNames = new ArrayList<String>();
+ ArrayList<String> initialPackageNames = new ArrayList<String>();
if (enableOverlay) {
// A list of package names used to create the signatures.
String[] pkgs = resources.getStringArray(initialPackageNamesResId);
@@ -126,20 +135,32 @@ public class ServiceWatcher implements ServiceConnection {
mSignatureSets = getSignatureSets(context, initialPackageNames);
}
+ /**
+ * Start this watcher, including binding to the current best match and
+ * re-binding to any better matches down the road.
+ * <p>
+ * Note that if there are no matching encryption-aware services, we may not
+ * bind to a real service until after the current user is unlocked.
+ */
public boolean start() {
synchronized (mLock) {
- if (!bindBestPackageLocked(mServicePackageName)) return false;
+ bindBestPackageLocked(mServicePackageName, false);
}
// listen for user change
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- switchUser();
+ switchUser(userId);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ unlockUser(userId);
}
}
}, UserHandle.ALL, intentFilter, null, mHandler);
@@ -153,30 +174,36 @@ public class ServiceWatcher implements ServiceConnection {
}
/**
- * Searches and binds to the best package, or do nothing
- * if the best package is already bound.
- * Only checks the named package, or checks all packages if it
- * is null.
- * Return true if a new package was found to bind to.
+ * Searches and binds to the best package, or do nothing if the best package
+ * is already bound, unless force rebinding is requested.
+ *
+ * @param justCheckThisPackage Only consider this package, or consider all
+ * packages if it is {@code null}.
+ * @param forceRebind Force a rebinding to the best package if it's already
+ * bound.
+ * @return {@code true} if a valid package was found to bind to.
*/
- private boolean bindBestPackageLocked(String justCheckThisPackage) {
+ private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
Intent intent = new Intent(mAction);
if (justCheckThisPackage != null) {
intent.setPackage(justCheckThisPackage);
}
- List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
- PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
+ final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ mCurrentUserId);
int bestVersion = Integer.MIN_VALUE;
- String bestPackage = null;
+ ComponentName bestComponent = null;
boolean bestIsMultiuser = false;
if (rInfos != null) {
for (ResolveInfo rInfo : rInfos) {
- String packageName = rInfo.serviceInfo.packageName;
+ final ComponentName component = rInfo.serviceInfo.getComponentName();
+ final String packageName = component.getPackageName();
// check signature
try {
PackageInfo pInfo;
- pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
if (!isSignatureMatch(pInfo.signatures)) {
Log.w(mTag, packageName + " resolves service " + mAction
+ ", but has wrong signature, ignoring");
@@ -196,9 +223,9 @@ public class ServiceWatcher implements ServiceConnection {
isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
}
- if (version > mVersion) {
+ if (version > bestVersion) {
bestVersion = version;
- bestPackage = packageName;
+ bestComponent = component;
bestIsMultiuser = isMultiuser;
}
}
@@ -207,42 +234,53 @@ public class ServiceWatcher implements ServiceConnection {
Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? ""
: "(" + justCheckThisPackage + ") "), rInfos.size(),
- (bestPackage == null ? "no new best package"
- : "new best package: " + bestPackage)));
+ (bestComponent == null ? "no new best component"
+ : "new best component: " + bestComponent)));
}
} else {
if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
}
- if (bestPackage != null) {
- bindToPackageLocked(bestPackage, bestVersion, bestIsMultiuser);
- return true;
+
+ if (bestComponent == null) {
+ Slog.w(mTag, "Odd, no component found for service " + mAction);
+ unbindLocked();
+ return false;
}
- return false;
+
+ final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
+ final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
+ && bestVersion == mBoundVersion && userId == mBoundUserId;
+ if (forceRebind || !alreadyBound) {
+ unbindLocked();
+ bindToPackageLocked(bestComponent, bestVersion, userId);
+ }
+ return true;
}
private void unbindLocked() {
- String pkg;
- pkg = mPackageName;
- mPackageName = null;
- mVersion = Integer.MIN_VALUE;
- mIsMultiuser = false;
- if (pkg != null) {
- if (D) Log.d(mTag, "unbinding " + pkg);
+ ComponentName component;
+ component = mBoundComponent;
+ mBoundComponent = null;
+ mBoundPackageName = null;
+ mBoundVersion = Integer.MIN_VALUE;
+ mBoundUserId = UserHandle.USER_NULL;
+ if (component != null) {
+ if (D) Log.d(mTag, "unbinding " + component);
mContext.unbindService(this);
}
}
- private void bindToPackageLocked(String packageName, int version, boolean isMultiuser) {
- unbindLocked();
+ private void bindToPackageLocked(ComponentName component, int version, int userId) {
Intent intent = new Intent(mAction);
- intent.setPackage(packageName);
- mPackageName = packageName;
- mVersion = version;
- mIsMultiuser = isMultiuser;
- if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ") ("
- + (isMultiuser ? "multi" : "single") + "-user)");
- mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_NOT_VISIBLE, mIsMultiuser ? UserHandle.SYSTEM : UserHandle.CURRENT);
+ intent.setComponent(component);
+ mBoundComponent = component;
+ mBoundPackageName = component.getPackageName();
+ mBoundVersion = version;
+ mBoundUserId = userId;
+ if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
+ mContext.bindServiceAsUser(intent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+ new UserHandle(userId));
}
public static boolean isSignatureMatch(Signature[] signatures,
@@ -275,106 +313,92 @@ public class ServiceWatcher implements ServiceConnection {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbindLocked();
- }
- // Need to check all packages because this method is also called when a
- // system app is uninstalled and the stock version in reinstalled.
- bindBestPackageLocked(null);
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
}
@Override
public void onPackageAdded(String packageName, int uid) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbindLocked();
- }
- // check the new package is case it is better
- bindBestPackageLocked(null);
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
}
@Override
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- unbindLocked();
- // the currently bound package was removed,
- // need to search for a new package
- bindBestPackageLocked(null);
- }
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
synchronized (mLock) {
- if (packageName.equals(mPackageName)) {
- // service enabled or disabled, make sure to rebind
- unbindLocked();
- }
- // the service might be disabled, need to search for a new
- // package
- bindBestPackageLocked(null);
+ final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
+ bindBestPackageLocked(null, forceRebind);
}
return super.onPackageChanged(packageName, uid, components);
}
};
@Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
+ public void onServiceConnected(ComponentName component, IBinder binder) {
synchronized (mLock) {
- String packageName = name.getPackageName();
- if (packageName.equals(mPackageName)) {
- if (D) Log.d(mTag, packageName + " connected");
- mBinder = binder;
+ if (component.equals(mBoundComponent)) {
+ if (D) Log.d(mTag, component + " connected");
+ mBoundService = binder;
if (mHandler !=null && mNewServiceWork != null) {
mHandler.post(mNewServiceWork);
}
} else {
- Log.w(mTag, "unexpected onServiceConnected: " + packageName);
+ Log.w(mTag, "unexpected onServiceConnected: " + component);
}
}
}
@Override
- public void onServiceDisconnected(ComponentName name) {
+ public void onServiceDisconnected(ComponentName component) {
synchronized (mLock) {
- String packageName = name.getPackageName();
- if (D) Log.d(mTag, packageName + " disconnected");
+ if (D) Log.d(mTag, component + " disconnected");
- if (packageName.equals(mPackageName)) {
- mBinder = null;
+ if (component.equals(mBoundComponent)) {
+ mBoundService = null;
}
}
}
- public String getBestPackageName() {
+ public @Nullable String getBestPackageName() {
synchronized (mLock) {
- return mPackageName;
+ return mBoundPackageName;
}
}
public int getBestVersion() {
synchronized (mLock) {
- return mVersion;
+ return mBoundVersion;
+ }
+ }
+
+ public @Nullable IBinder getBinder() {
+ synchronized (mLock) {
+ return mBoundService;
}
}
- public IBinder getBinder() {
+ public void switchUser(int userId) {
synchronized (mLock) {
- return mBinder;
+ mCurrentUserId = userId;
+ bindBestPackageLocked(mServicePackageName, false);
}
}
- public void switchUser() {
+ public void unlockUser(int userId) {
synchronized (mLock) {
- if (!mIsMultiuser) {
- unbindLocked();
- bindBestPackageLocked(mServicePackageName);
+ if (userId == mCurrentUserId) {
+ bindBestPackageLocked(mServicePackageName, false);
}
}
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 5aba22d5c4c7..1c1784ec3668 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -101,6 +101,10 @@ public class SystemConfig {
// background while in power save mode, as read from the configuration files.
final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
+ // These are the packages that are white-listed to be able to run in the
+ // background while in data-usage save mode, as read from the configuration files.
+ final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
+
// These are the app package names that should not allow IME switching.
final ArraySet<String> mFixedImeApps = new ArraySet<>();
@@ -151,6 +155,10 @@ public class SystemConfig {
return mAllowInPowerSave;
}
+ public ArraySet<String> getAllowInDataUsageSave() {
+ return mAllowInDataUsageSave;
+ }
+
public ArraySet<String> getFixedImeApps() {
return mFixedImeApps;
}
@@ -342,6 +350,7 @@ public class SystemConfig {
} else if ("feature".equals(name) && allowFeatures) {
String fname = parser.getAttributeValue(null, "name");
+ int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
boolean allowed;
if (!lowRam) {
allowed = true;
@@ -353,7 +362,7 @@ public class SystemConfig {
Slog.w(TAG, "<feature> without name in " + permFile + " at "
+ parser.getPositionDescription());
} else if (allowed) {
- addFeature(fname);
+ addFeature(fname, fversion);
}
XmlUtils.skipCurrentTag(parser);
continue;
@@ -391,6 +400,17 @@ public class SystemConfig {
XmlUtils.skipCurrentTag(parser);
continue;
+ } else if ("allow-in-data-usage-save".equals(name) && allowAll) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mAllowInDataUsageSave.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+
} else if ("fixed-ime-app".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
@@ -445,8 +465,8 @@ public class SystemConfig {
// Some devices can be field-converted to FBE, so offer to splice in
// those features if not already defined by the static config
if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
- addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION);
- addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS);
+ addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
+ addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
}
for (String featureName : mUnavailableFeatures) {
@@ -454,17 +474,21 @@ public class SystemConfig {
}
}
- private void addFeature(String featureName) {
- if (!mAvailableFeatures.containsKey(featureName)) {
- final FeatureInfo fi = new FeatureInfo();
- fi.name = featureName;
- mAvailableFeatures.put(featureName, fi);
+ private void addFeature(String name, int version) {
+ FeatureInfo fi = mAvailableFeatures.get(name);
+ if (fi == null) {
+ fi = new FeatureInfo();
+ fi.name = name;
+ fi.version = version;
+ mAvailableFeatures.put(name, fi);
+ } else {
+ fi.version = Math.max(fi.version, version);
}
}
- private void removeFeature(String featureName) {
- if (mAvailableFeatures.remove(featureName) != null) {
- Slog.d(TAG, "Removed unavailable feature " + featureName);
+ private void removeFeature(String name) {
+ if (mAvailableFeatures.remove(name) != null) {
+ Slog.d(TAG, "Removed unavailable feature " + name);
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2683be66b347..a63faf1b3011 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -101,9 +101,12 @@ import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -122,7 +125,7 @@ public class AccountManagerService
private static final String TAG = "AccountManagerService";
private static final String DATABASE_NAME = "accounts.db";
- private static final int DATABASE_VERSION = 8;
+ private static final int DATABASE_VERSION = 9;
private static final int MAX_DEBUG_DB_SIZE = 64;
@@ -200,6 +203,11 @@ public class AccountManagerService
EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
+ private static final String META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX =
+ "auth_uid_for_type:";
+ private static final String META_KEY_DELIMITER = ":";
+ private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
+
private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
private final AtomicInteger mNotificationIds = new AtomicInteger(1);
@@ -315,15 +323,15 @@ public class AccountManagerService
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
- userFilter.addAction(Intent.ACTION_USER_STARTED);
+ userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(intent);
- } else if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStarted(intent);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ onUserUnlocked(intent);
}
}
}, UserHandle.ALL, userFilter, null, null);
@@ -376,15 +384,69 @@ public class AccountManagerService
mAuthenticatorCache.invalidateCache(accounts.userId);
}
- final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
+ final HashMap<String, Integer> knownAuth = new HashMap<>();
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
mAuthenticatorCache.getAllServices(accounts.userId)) {
- knownAuth.add(service.type);
+ knownAuth.put(service.type.type, service.uid);
}
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
boolean accountDeleted = false;
+
+ // Get a list of stored authenticator type and UID
+ Cursor metaCursor = db.query(
+ TABLE_META,
+ new String[] {META_KEY, META_VALUE},
+ SELECTION_META_BY_AUTHENTICATOR_TYPE,
+ new String[] {META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
+ null /* groupBy */,
+ null /* having */,
+ META_KEY);
+ // Create a list of authenticator type whose previous uid no longer exists
+ HashSet<String> obsoleteAuthType = Sets.newHashSet();
+ try {
+ while (metaCursor.moveToNext()) {
+ String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
+ String uid = metaCursor.getString(1);
+ if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uid)) {
+ // Should never happen.
+ Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
+ + ", uid empty: " + TextUtils.isEmpty(uid));
+ continue;
+ }
+ Integer knownUid = knownAuth.get(type);
+ if (knownUid != null && uid.equals(knownUid.toString())) {
+ // Remove it from the knownAuth list if it's unchanged.
+ knownAuth.remove(type);
+ } else {
+ // Only add it to the list if it no longer exists or uid different
+ obsoleteAuthType.add(type);
+ // And delete it from the TABLE_META
+ db.delete(
+ TABLE_META,
+ META_KEY + "=? AND " + META_VALUE + "=?",
+ new String[] {
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
+ uid}
+ );
+ }
+ }
+ } finally {
+ metaCursor.close();
+ }
+
+ // Add the newly registered authenticator to TABLE_META
+ Iterator<Entry<String, Integer>> iterator = knownAuth.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry<String, Integer> entry = iterator.next();
+ ContentValues values = new ContentValues();
+ values.put(META_KEY,
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
+ values.put(META_VALUE, entry.getValue());
+ db.insert(TABLE_META, null, values);
+ }
+
Cursor cursor = db.query(TABLE_ACCOUNTS,
new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
null, null, null, null, ACCOUNTS_ID);
@@ -397,9 +459,9 @@ public class AccountManagerService
final String accountType = cursor.getString(1);
final String accountName = cursor.getString(2);
- if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
+ if (obsoleteAuthType.contains(accountType)) {
Slog.w(TAG, "deleting account " + accountName + " because type "
- + accountType + " no longer has a registered authenticator");
+ + accountType + "'s registered authenticator no longer exist.");
db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
accountDeleted = true;
@@ -440,6 +502,18 @@ public class AccountManagerService
}
}
+ private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
+ Context context,
+ int userId) {
+ AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
+ HashMap<String, Integer> knownAuth = new HashMap<>();
+ for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
+ .getAllServices(userId)) {
+ knownAuth.put(service.type.type, service.uid);
+ }
+ return knownAuth;
+ }
+
private UserAccounts getUserAccountsForCaller() {
return getUserAccounts(UserHandle.getCallingUserId());
}
@@ -513,7 +587,7 @@ public class AccountManagerService
}
}
- private void onUserStarted(Intent intent) {
+ private void onUserUnlocked(Intent intent) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId < 1) return;
@@ -986,13 +1060,9 @@ public class AccountManagerService
for (UserInfo user : users) {
if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
addSharedAccountAsUser(account, user.id);
- try {
- if (ActivityManagerNative.getDefault().isUserRunning(user.id, 0)) {
- mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
- MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
- }
- } catch (RemoteException re) {
- // Shouldn't happen
+ if (mUserManager.isUserUnlocked(user.id)) {
+ mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
+ MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
}
}
}
@@ -3809,7 +3879,7 @@ public class AccountManagerService
}
private static String getDatabaseName(int userId) {
- File systemDir = Environment.getSystemSecureDirectory();
+ File systemDir = Environment.getDataSystemDirectory();
File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
@@ -3967,8 +4037,13 @@ public class AccountManagerService
static class DatabaseHelper extends SQLiteOpenHelper {
+ private final Context mContext;
+ private final int mUserId;
+
public DatabaseHelper(Context context, int userId) {
super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
+ mContext = context;
+ mUserId = userId;
}
/**
@@ -4057,6 +4132,20 @@ public class AccountManagerService
+ "," + GRANTS_GRANTEE_UID + "))");
}
+ private void populateMetaTableWithAuthTypeAndUID(
+ SQLiteDatabase db,
+ Map<String, Integer> authTypeAndUIDMap) {
+ Iterator<Entry<String, Integer>> iterator = authTypeAndUIDMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry<String, Integer> entry = iterator.next();
+ ContentValues values = new ContentValues();
+ values.put(META_KEY,
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
+ values.put(META_VALUE, entry.getValue());
+ db.insert(TABLE_META, null, values);
+ }
+ }
+
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
@@ -4100,6 +4189,13 @@ public class AccountManagerService
oldVersion++;
}
+ if (oldVersion == 8) {
+ populateMetaTableWithAuthTypeAndUID(
+ db,
+ AccountManagerService.getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
+ oldVersion++;
+ }
+
if (oldVersion != newVersion) {
Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index bef6f0aabf5d..4f0d4d951e1c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -62,7 +62,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
- static final boolean DEBUG_PAUSE = DEBUG_ALL || true;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
@@ -77,7 +77,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || true;
+ static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
static final boolean DEBUG_TASKS = DEBUG_ALL || false;
static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
@@ -85,7 +85,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
- static final boolean DEBUG_VISIBILITY = DEBUG_ALL || true;
+ static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9dae74050812..71a0f495eea1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -273,6 +273,7 @@ import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
+import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.provider.Settings.System.FONT_SCALE;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -499,6 +500,9 @@ public final class ActivityManagerService extends ActivityManagerNative
private static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
+ // Intent sent when remote bugreport collection has been completed
+ private static final String INTENT_REMOTE_BUGREPORT_FINISHED =
+ "android.intent.action.REMOTE_BUGREPORT_FINISHED";
// Delay to disable app launch boost
static final int APP_BOOST_MESSAGE_DELAY = 3000;
@@ -1287,6 +1291,7 @@ public final class ActivityManagerService extends ActivityManagerNative
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
+ boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
boolean mSupportsFreeformWindowManagement;
boolean mSupportsPictureInPicture;
@@ -1366,7 +1371,6 @@ public final class ActivityManagerService extends ActivityManagerNative
int mProcessLimitOverride = -1;
WindowManagerService mWindowManager;
-
final ActivityThread mSystemThread;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1451,6 +1455,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int VR_MODE_CHANGE_MSG = 63;
static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 65;
+ static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1888,7 +1893,7 @@ public final class ActivityManagerService extends ActivityManagerNative
case SYSTEM_USER_UNLOCK_MSG: {
final int userId = msg.arg1;
mSystemServiceManager.unlockUser(userId);
- mRecentTasks.cleanupLocked(userId);
+ mRecentTasks.loadUserRecentsLocked(userId);
installEncryptionUnawareProviders(userId);
break;
}
@@ -1979,6 +1984,20 @@ public final class ActivityManagerService extends ActivityManagerNative
}
break;
}
+ case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG: {
+ synchronized (ActivityManagerService.this) {
+ for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
+ try {
+ // Make a one-way callback to the listener
+ mTaskStackListeners.getBroadcastItem(i).onPinnedStackAnimationEnded();
+ } catch (RemoteException e){
+ // Handled by the RemoteCallbackList
+ }
+ }
+ mTaskStackListeners.finishBroadcast();
+ }
+ break;
+ }
case NOTIFY_CLEARTEXT_NETWORK_MSG: {
final int uid = msg.arg1;
final byte[] firstPacket = (byte[]) msg.obj;
@@ -2467,7 +2486,6 @@ public final class ActivityManagerService extends ActivityManagerNative
mActivityStarter = new ActivityStarter(this, mStackSupervisor);
mRecentTasks = new RecentTasks(this, mStackSupervisor);
-
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
@@ -2521,7 +2539,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
void onUserStoppedLocked(int userId) {
- mRecentTasks.unloadUserRecentsLocked(userId);
+ mRecentTasks.unloadUserDataFromMemoryLocked(userId);
}
public void initPowerManagement() {
@@ -2836,31 +2854,39 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void setFocusedStack(int stackId) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
- synchronized (ActivityManagerService.this) {
- ActivityStack stack = mStackSupervisor.getStack(stackId);
- if (stack != null) {
- ActivityRecord r = stack.topRunningActivityLocked();
- if (r != null) {
- setFocusedActivityLocked(r, "setFocusedStack");
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ return;
+ }
+ final ActivityRecord r = stack.topRunningActivityLocked();
+ if (setFocusedActivityLocked(r, "setFocusedStack")) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@Override
public void setFocusedTask(int taskId) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
- synchronized (ActivityManagerService.this) {
- TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
- if (task != null) {
- final ActivityRecord r = task.topRunningActivityLocked();
- if (setFocusedActivityLocked(r, "setFocusedTask")) {
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- }
+ synchronized (this) {
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ return;
+ }
+ final ActivityRecord r = task.topRunningActivityLocked();
+ if (setFocusedActivityLocked(r, "setFocusedTask")) {
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
} finally {
@@ -6404,6 +6430,9 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
mLockScreenShown = LOCK_SCREEN_HIDDEN;
updateSleepIfNeededLocked();
+
+ // Some stack visibility might change (e.g. docked stack)
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
} finally {
@@ -7161,8 +7190,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final Rect bounds = (mStackSupervisor.getStack(PINNED_STACK_ID) == null)
? mDefaultPinnedStackBounds : null;
- mStackSupervisor.moveActivityToStackLocked(
- r, PINNED_STACK_ID, "enterPictureInPicture", bounds);
+ mStackSupervisor.moveActivityToPinnedStackLocked(
+ r, "enterPictureInPicture", bounds);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -7461,7 +7490,16 @@ public final class ActivityManagerService extends ActivityManagerNative
int checkAllowBackgroundLocked(int uid, String packageName, int callingPid) {
UidRecord uidRec = mActiveUids.get(uid);
- if (uidRec == null || uidRec.idle) {
+ if (!mLenientBackgroundCheck) {
+ if (uidRec == null
+ || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
+ packageName) != AppOpsManager.MODE_ALLOWED) {
+ return ActivityManager.APP_START_MODE_DELAYED;
+ }
+ }
+
+ } else if (uidRec == null || uidRec.idle) {
if (callingPid >= 0) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
@@ -8699,6 +8737,10 @@ public final class ActivityManagerService extends ActivityManagerNative
android.Manifest.permission.GET_DETAILED_TASKS)
== PackageManager.PERMISSION_GRANTED;
+ if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
+ Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
+ return Collections.emptyList();
+ }
mRecentTasks.loadUserRecentsLocked(userId);
final int recentsCount = mRecentTasks.size();
@@ -9186,11 +9228,35 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public void removeStack(int stackId) {
+ enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
+ if (stackId == HOME_STACK_ID) {
+ throw new IllegalArgumentException("Removing home stack is not allowed.");
+ }
+
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ return;
+ }
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ removeTaskByIdLocked(
+ tasks.get(i).taskId, true /* killProcess */, REMOVE_FROM_RECENTS);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public boolean removeTask(int taskId) {
+ enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()");
synchronized (this) {
- enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
- "removeTask()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);
} finally {
@@ -10722,6 +10788,12 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
+ // We're only interested in providers that are encryption unaware, and
+ // we don't care about uninstalled apps, since there's no way they're
+ // running at this point.
+ final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE
+ | MATCH_DEBUG_TRIAGED_MISSING;
+
synchronized (this) {
final int NP = mProcessNames.getMap().size();
for (int ip = 0; ip < NP; ip++) {
@@ -10736,8 +10808,7 @@ public final class ActivityManagerService extends ActivityManagerNative
try {
final String pkgName = app.pkgList.keyAt(ig);
final PackageInfo pkgInfo = AppGlobals.getPackageManager()
- .getPackageInfo(pkgName,
- GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE, userId);
+ .getPackageInfo(pkgName, matchFlags, userId);
if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
for (ProviderInfo provInfo : pkgInfo.providers) {
Log.v(TAG, "Installing " + provInfo);
@@ -11052,6 +11123,16 @@ public final class ActivityManagerService extends ActivityManagerNative
mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG).sendToTarget();
}
+ /** Notifies all listeners when the pinned stack animation ends. */
+ @Override
+ public void notifyPinnedStackAnimationEnded() {
+ synchronized (this) {
+ mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
+ mHandler.obtainMessage(
+ NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG).sendToTarget();
+ }
+ }
+
@Override
public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
@@ -11308,12 +11389,36 @@ public final class ActivityManagerService extends ActivityManagerNative
enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
"setAlwaysFinish()");
- Settings.Global.putInt(
- mContext.getContentResolver(),
- Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putInt(
+ mContext.getContentResolver(),
+ Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
- synchronized (this) {
- mAlwaysFinishActivities = enabled;
+ synchronized (this) {
+ mAlwaysFinishActivities = enabled;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void setLenientBackgroundCheck(boolean enabled) {
+ enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
+ "setLenientBackgroundCheck()");
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putInt(
+ mContext.getContentResolver(),
+ Settings.Global.LENIENT_BACKGROUND_CHECK, enabled ? 1 : 0);
+
+ synchronized (this) {
+ mLenientBackgroundCheck = enabled;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -12184,10 +12289,11 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " from " + proc.initialIdlePss + ")", true);
}
}
- } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
+ } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME
+ && proc.setProcState > ActivityManager.PROCESS_STATE_NONEXISTENT) {
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
- proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
+ proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
mTestPssMode, isSleeping(), now);
}
}
@@ -12210,6 +12316,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+ final boolean lenientBackgroundCheck =
+ Settings.Global.getInt(resolver, LENIENT_BACKGROUND_CHECK, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
@@ -12227,6 +12335,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
+ mLenientBackgroundCheck = lenientBackgroundCheck;
mForceResizableActivities = forceResizable;
mWindowManager.setForceResizableTasks(mForceResizableActivities);
mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
@@ -12454,7 +12563,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Make sure we have the current profile info, since it is needed for security checks.
mUserController.onSystemReady();
- mRecentTasks.onSystemReady();
+ mRecentTasks.onSystemReadyLocked();
// Check to see if there are any update receivers to run.
if (!mDidUpdate) {
if (mWaitingUpdate) {
@@ -12599,7 +12708,7 @@ public final class ActivityManagerService extends ActivityManagerNative
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
- e.rethrowAsRuntimeException();
+ throw e.rethrowAsRuntimeException();
}
}
startHomeActivityLocked(currentUserId, "systemReady");
@@ -13284,6 +13393,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public int getMemoryTrimLevel() {
+ enforceNotIsolatedCaller("getMyMemoryState");
+ synchronized (this) {
+ return mLastMemoryLevel;
+ }
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
(new ActivityManagerShellCommand(this, false)).exec(
@@ -14006,8 +14123,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (dumpPackage == null) {
- if (mAlwaysFinishActivities || mController != null) {
+ if (mAlwaysFinishActivities || mLenientBackgroundCheck || mController != null) {
pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
+ + " mLenientBackgroundCheck=" + mLenientBackgroundCheck
+ " mController=" + mController);
}
if (dumpAll) {
@@ -14612,6 +14730,9 @@ public final class ActivityManagerService extends ActivityManagerNative
case Process.THREAD_GROUP_DEFAULT:
schedGroup = 'F';
break;
+ case Process.THREAD_GROUP_TOP_APP:
+ schedGroup = 'T';
+ break;
default:
schedGroup = '?';
break;
@@ -14894,7 +15015,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(mi.hasActivities ? ",a" : ",e");
} else {
pw.print(tag); pw.print(","); pw.print(mi.shortLabel); pw.print(",");
- pw.println(mi.pss); pw.print(dumpSwapPss ? mi.swapPss : "N/A");
+ pw.print(mi.pss); pw.print(","); pw.println(dumpSwapPss ? mi.swapPss : "N/A");
}
if (mi.subitems != null) {
dumpMemItems(pw, prefix + " ", mi.shortLabel, mi.subitems,
@@ -14959,6 +15080,9 @@ public final class ActivityManagerService extends ActivityManagerNative
private final void dumpApplicationMemoryUsageHeader(PrintWriter pw, long uptime,
long realtime, boolean isCheckinRequest, boolean isCompact) {
+ if (isCompact) {
+ pw.print("version,"); pw.println(MEMINFO_COMPACT_VERSION);
+ }
if (isCheckinRequest || isCompact) {
// short checkin version
pw.print("time,"); pw.print(uptime); pw.print(","); pw.println(realtime);
@@ -15017,12 +15141,16 @@ public final class ActivityManagerService extends ActivityManagerNative
return stringifySize(size * 1024, 1024);
}
+ // Update this version number in case you change the 'compact' format
+ private static final int MEMINFO_COMPACT_VERSION = 1;
+
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
boolean dumpDetails = false;
boolean dumpFullDetails = false;
boolean dumpDalvik = false;
boolean dumpSummaryOnly = false;
+ boolean dumpUnreachable = false;
boolean oomOnly = false;
boolean isCompact = false;
boolean localOnly = false;
@@ -15051,6 +15179,8 @@ public final class ActivityManagerService extends ActivityManagerNative
dumpSummaryOnly = true;
} else if ("-S".equals(opt)) {
dumpSwapPss = true;
+ } else if ("--unreachable".equals(opt)) {
+ dumpUnreachable = true;
} else if ("--oom".equals(opt)) {
oomOnly = true;
} else if ("--local".equals(opt)) {
@@ -15212,7 +15342,7 @@ public final class ActivityManagerService extends ActivityManagerNative
try {
pw.flush();
thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, innerArgs);
+ dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs);
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
@@ -16729,10 +16859,12 @@ public final class ActivityManagerService extends ActivityManagerNative
HashSet<ComponentName> singleUserReceivers = null;
boolean scannedFirstReceivers = false;
for (int user : users) {
- // Skip users that have Shell restrictions
+ // Skip users that have Shell restrictions, with exception of always permitted
+ // Shell broadcasts
if (callingUid == Process.SHELL_UID
&& mUserController.hasUserRestriction(
- UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
+ UserManager.DISALLOW_DEBUGGING_FEATURES, user)
+ && !isPermittedShellBroadcast(intent)) {
continue;
}
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
@@ -16799,6 +16931,11 @@ public final class ActivityManagerService extends ActivityManagerNative
return receivers;
}
+ private boolean isPermittedShellBroadcast(Intent intent) {
+ // remote bugreport should always be allowed to be taken
+ return INTENT_REMOTE_BUGREPORT_FINISHED.equals(intent.getAction());
+ }
+
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
@@ -16876,7 +17013,6 @@ public final class ActivityManagerService extends ActivityManagerNative
case Process.ROOT_UID:
case Process.SYSTEM_UID:
case Process.PHONE_UID:
- case Process.SHELL_UID:
case Process.BLUETOOTH_UID:
case Process.NFC_UID:
isCallerSystem = true;
@@ -16890,6 +17026,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (isProtectedBroadcast
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
+ || Intent.ACTION_GET_PERMISSIONS_COUNT.equals(action)
+ || Intent.ACTION_GET_PERMISSIONS_PACKAGES.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
|| LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
@@ -17088,6 +17226,15 @@ public final class ActivityManagerService extends ActivityManagerNative
ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
break;
+ case android.hardware.Camera.ACTION_NEW_PICTURE:
+ case android.hardware.Camera.ACTION_NEW_VIDEO:
+ // These broadcasts are no longer allowed by the system, since they can
+ // cause significant thrashing at a crictical point (using the camera).
+ // Apps should use JobScehduler to monitor for media provider changes.
+ Slog.w(TAG, action + " no longer allowed; dropping from "
+ + UserHandle.formatUid(callingUid));
+ // Lie; we don't want to crash the app.
+ return ActivityManager.BROADCAST_SUCCESS;
}
}
@@ -17683,36 +17830,42 @@ public final class ActivityManagerService extends ActivityManagerNative
final long origId = Binder.clearCallingIdentity();
final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
if (stack != null) {
- if (fromStackId == DOCKED_STACK_ID) {
-
- // We are moving all tasks from the docked stack to the fullscreen stack, which
- // is dismissing the docked stack, so resize all other stacks to fullscreen here
- // already so we don't end up with resize trashing.
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i)) {
- ActivityStack otherStack = mStackSupervisor.getStack(i);
- if (otherStack != null) {
- mStackSupervisor.resizeStackLocked(i,
- null, null, null, PRESERVE_WINDOWS,
- true /* allowResizeInDockedMode */);
+ mWindowManager.deferSurfaceLayout();
+ try {
+ if (fromStackId == DOCKED_STACK_ID) {
+
+ // We are moving all tasks from the docked stack to the fullscreen stack,
+ // which is dismissing the docked stack, so resize all other stacks to
+ // fullscreen here already so we don't end up with resize trashing.
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i)) {
+ ActivityStack otherStack = mStackSupervisor.getStack(i);
+ if (otherStack != null) {
+ mStackSupervisor.resizeStackLocked(i,
+ null, null, null, PRESERVE_WINDOWS,
+ true /* allowResizeInDockedMode */);
+ }
}
}
}
- }
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
- final int size = tasks.size();
- if (onTop) {
- for (int i = 0; i < size; i++) {
- mStackSupervisor.moveTaskToStackLocked(tasks.get(i).taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, !FORCE_FOCUS,
- "moveTasksToFullscreenStack", ANIMATE);
- }
- } else {
- for (int i = size - 1; i >= 0; i--) {
- mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, 0);
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final int size = tasks.size();
+ if (onTop) {
+ for (int i = 0; i < size; i++) {
+ mStackSupervisor.moveTaskToStackLocked(tasks.get(i).taskId,
+ FULLSCREEN_WORKSPACE_STACK_ID, onTop, !FORCE_FOCUS,
+ "moveTasksToFullscreenStack", ANIMATE);
+ }
+ } else {
+ for (int i = size - 1; i >= 0; i--) {
+ mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
+ FULLSCREEN_WORKSPACE_STACK_ID, 0);
+ }
}
+ } finally {
+ mWindowManager.continueSurfaceLayout();
}
+
}
Binder.restoreCallingIdentity(origId);
}
@@ -18505,8 +18658,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ // This will treat important bound services identically to
+ // the top app, which may behave differently than generic
+ // foreground work.
+ if (client.curSchedGroup > schedGroup) {
+ if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
+ schedGroup = client.curSchedGroup;
+ } else {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
@@ -18570,11 +18730,15 @@ public final class ActivityManagerService extends ActivityManagerNative
final ActivityRecord a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
+ (a.visible || a.state == ActivityState.RESUMED ||
+ a.state == ActivityState.PAUSING)) {
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
+ schedGroup = Process.THREAD_GROUP_TOP_APP;
+ } else {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
}
app.cached = false;
app.adjType = "service";
@@ -18654,7 +18818,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (procState > clientProcState) {
procState = clientProcState;
}
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ if (client.curSchedGroup > schedGroup) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
@@ -20357,6 +20521,10 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "No user info for user #" + targetUserId);
return false;
}
+ if (!targetUserInfo.supportsSwitchTo()) {
+ Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
+ return false;
+ }
if (targetUserInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
return false;
@@ -20598,6 +20766,20 @@ public final class ActivityManagerService extends ActivityManagerNative
voiceSession, voiceInteractor);
}
}
+
+ @Override
+ public void notifyStartingWindowDrawn() {
+ synchronized (ActivityManagerService.this) {
+ mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn();
+ }
+ }
+
+ @Override
+ public void notifyAppTransitionStarting(int reason) {
+ synchronized (ActivityManagerService.this) {
+ mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(reason);
+ }
+ }
}
private final class SleepTokenImpl extends SleepToken {
@@ -20758,7 +20940,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
} catch (RemoteException e) {
}
- if (pkgUid == -1) {
+ if (userId != UserHandle.USER_ALL && pkgUid == -1) {
throw new IllegalArgumentException(
"Cannot kill dependents of non-existing package " + packageName);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8c997395da46..02539766ed59 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -62,6 +62,8 @@ class ActivityManagerShellCommand extends ShellCommand {
return runUntrackAssociations(pw);
case "is-user-stopped":
return runIsUserStopped(pw);
+ case "lenient-background-check":
+ return runLenientBackgroundCheck(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -152,6 +154,22 @@ class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
+ int runLenientBackgroundCheck(PrintWriter pw) throws RemoteException {
+ String arg = getNextArg();
+ if (arg != null) {
+ boolean state = Boolean.valueOf(arg) || "1".equals(arg);
+ mInterface.setLenientBackgroundCheck(state);
+ }
+ synchronized (mInternal) {
+ if (mInternal.mLenientBackgroundCheck) {
+ pw.println("Lenient background check enabled");
+ } else {
+ pw.println("Lenient background check disabled");
+ }
+ }
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -203,6 +221,8 @@ class ActivityManagerShellCommand extends ShellCommand {
pw.println(" Disable and clear association tracking.");
pw.println(" is-user-stopped <USER_ID>");
pw.println(" returns whether <USER_ID> has been stopped or not");
+ pw.println(" lenient-background-check [<true|false>]");
+ pw.println(" optionally controls lenient background check mode, returns current mode.");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index ffb2fc4a6d02..0e6dd28379b3 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -7,11 +7,13 @@ import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
+import android.annotation.Nullable;
import android.app.ActivityManager.StackId;
import android.content.Context;
import android.os.SystemClock;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
/**
* Handles logging into Tron.
@@ -24,6 +26,8 @@ class ActivityMetricsLogger {
private static final int WINDOW_STATE_FREEFORM = 2;
private static final int WINDOW_STATE_INVALID = -1;
+ private static final long INVALID_START_TIME = -1;
+
// Preallocated strings we are sending to tron, so we don't have to allocate a new one every
// time we log.
private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
@@ -34,6 +38,11 @@ class ActivityMetricsLogger {
private final ActivityStackSupervisor mSupervisor;
private final Context mContext;
+ private long mCurrentTransitionStartTime = INVALID_START_TIME;
+ private boolean mLoggedWindowsDrawn;
+ private boolean mLoggedStartingWindowDrawn;
+ private boolean mLoggedTransitionStarting;
+
ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
mSupervisor = supervisor;
@@ -73,4 +82,101 @@ class ActivityMetricsLogger {
throw new IllegalStateException("Unknown stack=" + stack);
}
}
+
+ /**
+ * Notifies the tracker at the earliest possible point when we are starting to launch an
+ * activity.
+ */
+ void notifyActivityLaunching() {
+ mCurrentTransitionStartTime = System.currentTimeMillis();
+ }
+
+ /**
+ * Notifies the tracker the the activity is actually launching.
+ *
+ * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
+ * launch
+ * @param componentName the component name of the activity being launched
+ * @param processRunning whether the process that will contains the activity is already running
+ */
+ void notifyActivityLaunched(int resultCode, @Nullable String componentName,
+ boolean processRunning) {
+
+ if (resultCode < 0 || componentName == null) {
+
+ // Failed to launch, don't track anything.
+ reset();
+ return;
+ }
+
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_COMPONENT_NAME,
+ componentName);
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_PROCESS_RUNNING,
+ processRunning);
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
+ (int) (SystemClock.uptimeMillis() / 1000));
+ }
+
+ /**
+ * Notifies the tracker that all windows of the app have been drawn.
+ */
+ void notifyWindowsDrawn() {
+ if (!isTransitionActive() || mLoggedWindowsDrawn) {
+ return;
+ }
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS,
+ calculateCurrentDelay());
+ mLoggedWindowsDrawn = true;
+ if (mLoggedTransitionStarting) {
+ reset();
+ }
+ }
+
+ /**
+ * Notifies the tracker that the starting window was drawn.
+ */
+ void notifyStartingWindowDrawn() {
+ if (!isTransitionActive() || mLoggedStartingWindowDrawn) {
+ return;
+ }
+ mLoggedStartingWindowDrawn = true;
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
+ calculateCurrentDelay());
+ }
+
+ /**
+ * Notifies the tracker that the app transition is starting.
+ *
+ * @param reason The reason why we started it. Must be on of
+ * ActivityManagerInternal.APP_TRANSITION_* reasons.
+ */
+ void notifyTransitionStarting(int reason) {
+ if (!isTransitionActive() || mLoggedTransitionStarting) {
+ return;
+ }
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_REASON, reason);
+ MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DELAY_MS,
+ calculateCurrentDelay());
+ mLoggedTransitionStarting = true;
+ if (mLoggedWindowsDrawn) {
+ reset();
+ }
+ }
+
+ private boolean isTransitionActive() {
+ return mCurrentTransitionStartTime != INVALID_START_TIME;
+ }
+
+ private void reset() {
+ mCurrentTransitionStartTime = INVALID_START_TIME;
+ mLoggedWindowsDrawn = false;
+ mLoggedTransitionStarting = false;
+ mLoggedStartingWindowDrawn = false;
+ }
+
+ private int calculateCurrentDelay() {
+
+ // Shouldn't take more than 25 days to launch an app, so int is fine here.
+ return (int) (System.currentTimeMillis() - mCurrentTransitionStartTime);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 90a7da977355..d5e40cf4de7a 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -196,7 +196,12 @@ final class ActivityRecord {
private boolean inHistory; // are we in the history stack?
final ActivityStackSupervisor mStackSupervisor;
- boolean mStartingWindowShown = false;
+
+ static final int STARTING_WINDOW_NOT_SHOWN = 0;
+ static final int STARTING_WINDOW_SHOWN = 1;
+ static final int STARTING_WINDOW_REMOVED = 2;
+ int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
+
boolean mUpdateTaskThumbnailWhenHidden;
ActivityContainer mInitialActivityContainer;
@@ -214,6 +219,19 @@ final class ActivityRecord {
boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session
IVoiceInteractionSession voiceSession; // Voice interaction session for this activity
+ private static String startingWindowStateToString(int state) {
+ switch (state) {
+ case STARTING_WINDOW_NOT_SHOWN:
+ return "STARTING_WINDOW_NOT_SHOWN";
+ case STARTING_WINDOW_SHOWN:
+ return "STARTING_WINDOW_SHOWN";
+ case STARTING_WINDOW_REMOVED:
+ return "STARTING_WINDOW_REMOVED";
+ default:
+ return "unknown state=" + state;
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -320,7 +338,9 @@ final class ActivityRecord {
pw.print(" inHistory="); pw.print(inHistory);
pw.print(" visible="); pw.print(visible);
pw.print(" sleeping="); pw.print(sleeping);
- pw.print(" idle="); pw.println(idle);
+ pw.print(" idle="); pw.print(idle);
+ pw.print(" mStartingWindowState=");
+ pw.println(startingWindowStateToString(mStartingWindowState));
pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
pw.print(" noDisplay="); pw.print(noDisplay);
pw.print(" immersive="); pw.print(immersive);
@@ -1166,6 +1186,7 @@ final class ActivityRecord {
}
void windowsDrawnLocked() {
+ mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
if (displayStartTime != 0) {
reportLaunchTimeLocked(SystemClock.uptimeMillis());
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0bccffa5b505..5491b4f9021b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -25,6 +25,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.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED;
@@ -33,6 +34,8 @@ import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
+import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.MOVING;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -62,7 +65,6 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -766,9 +768,8 @@ final class ActivityStack {
void minimalResumeActivityLocked(ActivityRecord r) {
r.state = ActivityState.RESUMED;
- if (DEBUG_STATES) Slog.v(TAG_STATES,
- "Moving to RESUMED: " + r + " (starting new instance)");
- r.stopped = false;
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
+ + " callers=" + Debug.getCallers(5));
mResumedActivity = r;
r.task.touchActiveTime();
mRecentTasks.addLocked(r.task);
@@ -1055,6 +1056,7 @@ final class ActivityStack {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
completePauseLocked(true);
+ return;
} else {
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
r.userId, System.identityHashCode(r), r.shortComponentName,
@@ -1070,6 +1072,7 @@ final class ActivityStack {
}
}
}
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
@@ -1127,7 +1130,8 @@ final class ActivityStack {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending stop: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ + " wasStopping=" + wasStopping + " visible=" + prev.visible);
if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Complete pause, no longer waiting: " + prev);
@@ -1142,10 +1146,11 @@ final class ActivityStack {
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.state = ActivityState.STOPPING;
- } else if (!hasVisibleBehindActivity() || mService.isSleepingOrShuttingDown()) {
+ } else if ((!prev.visible && !hasVisibleBehindActivity())
+ || mService.isSleepingOrShuttingDown()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
- addToStopping(prev);
+ addToStopping(prev, true /* immediate */);
}
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
@@ -1197,23 +1202,30 @@ final class ActivityStack {
prev.cpuTimeAtResume = 0; // reset it
}
- // Notify when the task stack has changed, but only if visibilities changed (not just
- // focus).
+ // Notify when the task stack has changed, but only if visibilities changed (not just focus)
if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
mService.notifyTaskStackChangedLocked();
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
+
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
- private void addToStopping(ActivityRecord r) {
- mStackSupervisor.mStoppingActivities.add(r);
- if (mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE ||
- r.frontOfTask && mTaskHistory.size() <= 1) {
- // If we already have a few activities waiting to stop,
- // then give up on things going idle and start clearing
- // them out. Or if r is the last of activity of the last task the stack
- // will be empty and must be cleared immediately.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "To many pending stops, forcing idle");
+ private void addToStopping(ActivityRecord r, boolean immediate) {
+ if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+ mStackSupervisor.mStoppingActivities.add(r);
+ }
+
+ // If we already have a few activities waiting to stop, then give up
+ // on things going idle and start clearing them out. Or if r is the
+ // last of activity of the last task the stack will be empty and must
+ // be cleared immediately.
+ boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
+ || (r.frontOfTask && mTaskHistory.size() <= 1);
+
+ if (immediate || forceIdle) {
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
+ + forceIdle + "immediate=" + immediate);
mStackSupervisor.scheduleIdleLocked();
} else {
mStackSupervisor.checkReadyForSleepLocked();
@@ -1226,9 +1238,11 @@ final class ActivityStack {
* this function updates the rest of our state to match that fact.
*/
private void completeResumeLocked(ActivityRecord next) {
+ next.visible = true;
next.idle = false;
next.results = null;
next.newIntents = null;
+ next.stopped = false;
if (next.isHomeActivity()) {
ProcessRecord app = next.task.mActivities.get(0).app;
@@ -1421,10 +1435,12 @@ final class ActivityStack {
if (mStackId == DOCKED_STACK_ID) {
// Docked stack is always visible, except in the case where the top running activity
- // task in the focus stack doesn't support any form of resizing.
+ // task in the focus stack doesn't support any form of resizing but we show it for the
+ // 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() ? STACK_VISIBLE : STACK_INVISIBLE;
+ return task == null || task.canGoInDockedStack() || task.isHomeTask() ? STACK_VISIBLE
+ : STACK_INVISIBLE;
}
// Find the first stack below focused stack that actually got something visible.
@@ -1587,6 +1603,33 @@ final class ActivityStack {
// determined individually unlike other stacks where the visibility or fullscreen
// status of an activity in a previous task affects other.
behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
+ } else if (mStackId == HOME_STACK_ID) {
+ if (task.isHomeTask()) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ // No other task in the home stack should be visible behind the home activity.
+ // Home activities is usually a translucent activity with the wallpaper behind
+ // them. However, when they don't have the wallpaper behind them, we want to
+ // show activities in the next application stack behind them vs. another
+ // task in the home stack like recents.
+ behindFullscreenActivity = true;
+ } else if (task.isRecentsTask()
+ && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Recents task returning to app: at " + task
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ // We don't want any other tasks in the home stack visible if the recents
+ // activity is going to be returning to an application activity type.
+ // We do this to preserve the visible order the user used to get into the
+ // recents activity. The recents activity is normally translucent and if it
+ // doesn't have the wallpaper behind it the next activity in the home stack
+ // shouldn't be visible when the home stack is brought to the front to display
+ // the recents activity from an app.
+ behindFullscreenActivity = true;
+ }
+
}
}
@@ -1663,10 +1706,7 @@ final class ActivityStack {
if (visibleBehind == r) {
releaseBackgroundResources(r);
} else {
- if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- mStackSupervisor.mStoppingActivities.add(r);
- }
- mStackSupervisor.scheduleIdleLocked();
+ addToStopping(r, true /* immediate */);
}
break;
@@ -1687,33 +1727,7 @@ final class ActivityStack {
+ " behindFullscreenActivity=" + behindFullscreenActivity);
// At this point, nothing else needs to be shown in this task.
behindFullscreenActivity = true;
- } else if (isHomeStack()) {
- if (r.isHomeActivity()) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home activity: at " + r
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // No other activity in the home stack should be visible behind the home activity.
- // Home activities is usually a translucent activity with the wallpaper behind them.
- // However, when they don't have the wallpaper behind them, we want to show
- // activities in the next application stack behind them vs. another activity in the
- // home stack like recents.
- behindFullscreenActivity = true;
- } else if (r.isRecentsActivity()
- && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Recents activity returning to app: at " + r
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // We don't want any other activities in the home stack visible if the recents
- // activity is going to be returning to an application activity type.
- // We do this to preserve the visible order the user used to get into the recents
- // activity. The recents activity is normally translucent and if it doesn't have
- // the wallpaper behind it the next activity in the home stack shouldn't be visible
- // when the home stack is brought to the front to display the recents activity from
- // an app.
- behindFullscreenActivity = true;
- }
- } else if (r.frontOfTask && task.isOverHomeStack()) {
+ } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
+ " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
@@ -1726,6 +1740,8 @@ final class ActivityStack {
// This activity is not currently visible, but is running. Tell it to become visible.
if (r.state == ActivityState.RESUMED || r == starting) {
+ if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
+ "Not making visible, r=" + r + " state=" + r.state + " starting=" + starting);
return;
}
@@ -1830,10 +1846,11 @@ final class ActivityStack {
continue;
}
- if (r.state == ActivityState.INITIALIZING && r.mStartingWindowShown) {
+ if (r.state == ActivityState.INITIALIZING
+ && r.mStartingWindowState == STARTING_WINDOW_SHOWN) {
if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
"Found orphaned starting window " + r);
- r.mStartingWindowShown = false;
+ r.mStartingWindowState = STARTING_WINDOW_REMOVED;
mWindowManager.removeAppStartingWindow(r.appToken);
}
}
@@ -1892,7 +1909,7 @@ final class ActivityStack {
return false;
}
- cancelInitializingActivities();
+ mStackSupervisor.cancelInitializingActivities();
// Find the first activity that is not finishing.
final ActivityRecord next = topRunningActivityLocked();
@@ -1999,8 +2016,7 @@ final class ActivityStack {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
- // If we are currently pausing an activity, then don't do anything
- // until that is done.
+ // If we are currently pausing an activity, then don't do anything until that is done.
if (!mStackSupervisor.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
@@ -2008,40 +2024,10 @@ final class ActivityStack {
return false;
}
- // Okay we are now going to start a switch, to 'next'. We may first
- // have to pause the current activity, but this is an important point
- // where we have decided to go to 'next' so keep track of that.
- // XXX "App Redirected" dialog is getting too many false positives
- // at this point, so turn off for now.
- if (false) {
- if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
- long now = SystemClock.uptimeMillis();
- final boolean inTime = mLastStartedActivity.startTime != 0
- && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
- final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
- final int nextUid = next.info.applicationInfo.uid;
- if (inTime && lastUid != nextUid
- && lastUid != next.launchedFromUid
- && mService.checkPermission(
- android.Manifest.permission.STOP_APP_SWITCHES,
- -1, next.launchedFromUid)
- != PackageManager.PERMISSION_GRANTED) {
- mService.showLaunchWarningLocked(mLastStartedActivity, next);
- } else {
- next.startTime = now;
- mLastStartedActivity = next;
- }
- } else {
- next.startTime = SystemClock.uptimeMillis();
- mLastStartedActivity = next;
- }
- }
-
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
- // We need to start pausing the current activity so the top one
- // can be resumed...
- boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
+ // We need to start pausing the current activity so the top one can be resumed...
+ final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
@@ -2279,6 +2265,7 @@ final class ActivityStack {
mService.compatibilityInfoForPackageLocked(next.info.applicationInfo),
next.nonLocalizedLabel, next.labelRes, next.icon, next.logo,
next.windowFlags, null, true);
+ next.mStartingWindowState = STARTING_WINDOW_SHOWN;
}
mStackSupervisor.startSpecificActivityLocked(next, true, false);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2288,7 +2275,6 @@ final class ActivityStack {
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
- next.visible = true;
completeResumeLocked(next);
} catch (Exception e) {
// If any exception gets thrown, toss away this
@@ -2299,8 +2285,6 @@ final class ActivityStack {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
- next.stopped = false;
-
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
@@ -2314,6 +2298,7 @@ final class ActivityStack {
next.nonLocalizedLabel,
next.labelRes, next.icon, next.logo, next.windowFlags,
null, true);
+ next.mStartingWindowState = STARTING_WINDOW_SHOWN;
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
@@ -2546,7 +2531,7 @@ final class ActivityStack {
r.info.applicationInfo), r.nonLocalizedLabel,
r.labelRes, r.icon, r.logo, r.windowFlags,
prev != null ? prev.appToken : null, showStartingIcon);
- r.mStartingWindowShown = true;
+ r.mStartingWindowState = STARTING_WINDOW_SHOWN;
}
} else {
// If this is the first activity, don't do any fancy animations,
@@ -3285,7 +3270,7 @@ final class ActivityStack {
// finishing until the resumed one becomes visible.
if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- addToStopping(r);
+ addToStopping(r, false /* immediate */);
}
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: "+ r + " (finish requested)");
@@ -4280,6 +4265,12 @@ final class ActivityStack {
// "restart!".
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching resumed " + r);
+
+ if (DEBUG_STATES && !r.visible) {
+ Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + r
+ + " called by " + Debug.getCallers(4));
+ }
+
relaunchActivityLocked(r, r.configChangeFlags, true, preserveWindow);
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -4416,7 +4407,8 @@ final class ActivityStack {
try {
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
- "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
+ "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r
+ + " callers=" + Debug.getCallers(6));
r.forceNewConfig = false;
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
!andResume, new Configuration(mService.mConfiguration),
@@ -4430,9 +4422,21 @@ final class ActivityStack {
}
if (andResume) {
- r.results = null;
- r.newIntents = null;
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "Resumed after relaunch " + r);
+ }
r.state = ActivityState.RESUMED;
+ // Relaunch-resume could happen either when the app is already in the front,
+ // or while it's being brought to front. In the latter case, it's marked RESUMED
+ // but not yet visible (or stopped). We need to complete the resume here as the
+ // code in resumeTopActivityInnerLocked to complete the resume might be skipped.
+ if (!r.visible || r.stopped) {
+ mWindowManager.setAppVisibility(r.appToken, true);
+ completeResumeLocked(r);
+ } else {
+ r.results = null;
+ r.newIntents = null;
+ }
} else {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
r.state = ActivityState.PAUSED;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0beef53cbb70..20f8285cfee7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -119,6 +119,7 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
@@ -148,6 +149,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.ANIMATE;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
@@ -399,12 +401,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
// The default minimal size that will be used if the activity doesn't specify its minimal size.
// It will be calculated when the default display gets added.
- private int mDefaultMinimalSizeOfResizeableTask = -1;
+ int mDefaultMinimalSizeOfResizeableTask = -1;
// Whether tasks have moved and we need to rank the tasks before next OOM scoring
private boolean mTaskLayersChanged = true;
- private final ActivityMetricsLogger mActivityMetricsLogger;
+ final ActivityMetricsLogger mActivityMetricsLogger;
private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
@@ -718,14 +720,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
int getNextTaskIdForUserLocked(int userId) {
- mRecentTasks.loadUserRecentsLocked(userId);
final int currentTaskId = mCurTaskIdForUser.get(userId, userId * MAX_TASK_IDS_PER_USER);
// for a userId u, a taskId can only be in the range
// [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER
// was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on.
int candidateTaskId = currentTaskId;
- while (anyTaskForIdLocked(candidateTaskId, !RESTORE_FROM_RECENTS,
- INVALID_STACK_ID) != null) {
+ while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId)
+ || anyTaskForIdLocked(candidateTaskId, !RESTORE_FROM_RECENTS,
+ INVALID_STACK_ID) != null) {
candidateTaskId++;
if (candidateTaskId == (userId + 1) * MAX_TASK_IDS_PER_USER) {
// Wrap around as there will be smaller task ids that are available now.
@@ -907,6 +909,15 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
+ void cancelInitializingActivities() {
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ stacks.get(stackNdx).cancelInitializingActivities();
+ }
+ }
+ }
+
void reportActivityVisibleLocked(ActivityRecord r) {
sendWaitingVisibleReportLocked(r);
}
@@ -1045,10 +1056,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
+ return resolveIntent(intent, resolvedType, userId, 0);
+ }
+
+ ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
try {
return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
+ PackageManager.MATCH_DEFAULT_ONLY | flags
+ | ActivityManagerService.STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
}
return null;
@@ -1060,9 +1075,18 @@ public final class ActivityStackSupervisor implements DisplayListener {
return resolveActivity(intent, rInfo, startFlags, profilerInfo);
}
- final boolean realStartActivityLocked(ActivityRecord r,
- ProcessRecord app, boolean andResume, boolean checkConfig)
- throws RemoteException {
+ final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
+ boolean andResume, boolean checkConfig) throws RemoteException {
+
+ if (!allPausedActivitiesComplete()) {
+ // While there are activities pausing we skipping starting any new activities until
+ // pauses are complete. NOTE: that we also do this for activities that are starting in
+ // the paused state because they will first be resumed then paused on the client side.
+ if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
+ "realStartActivityLocked: Skipping start of r=" + r
+ + " some activities pausing...");
+ return false;
+ }
if (andResume) {
r.startFreezingScreenLocked(app, 0);
@@ -1937,9 +1961,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
final boolean updated = stack.ensureActivityConfigurationLocked(r, 0,
preserveWindows);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
- ensureActivitiesVisibleLocked(r, 0, preserveWindows);
if (!updated) {
resumeFocusedStackTopActivityLocked();
}
@@ -2019,8 +2040,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
return true;
}
- adjustForMinimalTaskDimensions(task, bounds);
-
// If this is a forced resize, let it go through even if the bounds is not changing,
// as we might need a relayout due to surface size change (to/from fullscreen).
final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
@@ -2054,7 +2073,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// to be relaunched due to configuration change.
boolean kept = true;
if (overrideConfig != null) {
- ActivityRecord r = task.topRunningActivityLocked();
+ final ActivityRecord r = task.topRunningActivityLocked();
if (r != null) {
final ActivityStack stack = task.stack;
kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
@@ -2065,44 +2084,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
}
- mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
+ mWindowManager.resizeTask(task.taskId, task.mBounds, task.mOverrideConfig, kept, forced);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
return kept;
}
- private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) {
- if (bounds == null) {
- return;
- }
- int minimalSize = task.mMinimalSize == -1 ? mDefaultMinimalSizeOfResizeableTask
- : task.mMinimalSize;
- final boolean adjustWidth = minimalSize > bounds.width();
- final boolean adjustHeight = minimalSize > bounds.height();
- if (!(adjustWidth || adjustHeight)) {
- return;
- }
- Rect taskBounds = task.mBounds;
- if (adjustWidth) {
- if (taskBounds != null && bounds.right == taskBounds.right) {
- bounds.left = bounds.right - minimalSize;
- } else {
- // Either left bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping left.
- bounds.right = bounds.left + minimalSize;
- }
- }
- if (adjustHeight) {
- if (taskBounds != null && bounds.bottom == taskBounds.bottom) {
- bounds.top = bounds.bottom - minimalSize;
- } else {
- // Either top bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping top.
- bounds.bottom = bounds.top + minimalSize;
- }
- }
- }
-
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
@@ -2240,6 +2227,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
return;
}
+ if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+ throw new IllegalArgumentException("moveTaskToStack:"
+ + "Attempt to move task " + taskId + " to unsupported freeform stack");
+ }
+
final ActivityRecord topActivity = task.getTopActivity();
final int sourceStackId = task.stack != null ? task.stack.mStackId : INVALID_STACK_ID;
final boolean mightReplaceWindow =
@@ -2261,7 +2253,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
boolean kept = true;
try {
final ActivityStack stack = moveTaskToStackUncheckedLocked(
- task, stackId, toTop, forceFocus, "moveTaskToStack:" + reason);
+ task, stackId, toTop, forceFocus, reason + " moveTaskToStack");
stackId = stack.mStackId;
if (!animate) {
@@ -2274,10 +2266,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
// Make sure the task has the appropriate bounds/size for the stack it is in.
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow);
- } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
- && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
- kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds,
- RESIZE_MODE_SYSTEM, !mightReplaceWindow);
+ } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+ Rect bounds = task.getLaunchBounds();
+ if (bounds == null) {
+ stack.layoutTaskInStack(task, null);
+ bounds = task.mBounds;
+ }
+ kept = resizeTaskLocked(task, bounds, RESIZE_MODE_FORCED, !mightReplaceWindow);
} else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow);
}
@@ -2321,36 +2316,44 @@ public final class ActivityStackSupervisor implements DisplayListener {
return false;
}
- moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null);
- mWindowManager.animateResizePinnedStack(bounds);
+ moveActivityToPinnedStackLocked(r, "moveTopActivityToPinnedStack", bounds);
return true;
}
- void moveActivityToStackLocked(ActivityRecord r, int stackId, String reason, Rect bounds) {
- final TaskRecord task = r.task;
- if (task.mActivities.size() == 1) {
- // There is only one activity in the task. So, we can just move the task over to the
- // stack without re-parenting the activity in a different task.
- moveTaskToStackLocked(
- task.taskId, stackId, ON_TOP, FORCE_FOCUS, reason, true /* animate */);
- } else {
- final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
- stack.moveActivityToStack(r);
- }
-
- if (bounds != null) {
- resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
- null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true);
+ void moveActivityToPinnedStackLocked(ActivityRecord r, String reason, Rect bounds) {
+ mWindowManager.deferSurfaceLayout();
+ try {
+ final TaskRecord task = r.task;
+
+ // 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.
+ resizeStackLocked(PINNED_STACK_ID, task.mBounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS,
+ true /* allowResizeInDockedMode */);
+
+ if (task.mActivities.size() == 1) {
+ // There is only one activity in the task. So, we can just move the task over to
+ // the stack without re-parenting the activity in a different task.
+ moveTaskToStackLocked(
+ task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS, reason, !ANIMATE);
+ } else {
+ stack.moveActivityToStack(r);
+ }
+ } finally {
+ mWindowManager.continueSurfaceLayout();
}
- // The task might have already been running and its visibility needs to be synchronized with
- // the visibility of the stack / windows.
+ // The task might have already been running and its visibility needs to be synchronized
+ // with the visibility of the stack / windows.
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- if (stackId == PINNED_STACK_ID) {
- mService.notifyActivityPinnedLocked();
- }
+ mWindowManager.animateResizePinnedStack(bounds);
+ mService.notifyActivityPinnedLocked();
}
void positionTaskInStackLocked(int taskId, int stackId, int position) {
@@ -2368,6 +2371,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
stack.positionTask(task, position);
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
+ stack.ensureActivityConfigurationLocked(task.topRunningActivityLocked(), 0,
+ !PRESERVE_WINDOWS);
stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
}
@@ -3248,9 +3253,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
return;
}
- if (!task.canGoInDockedStack() || task.inCropWindowsResizeMode()) {
+ if (!task.canGoInDockedStack() || task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
// Display warning toast if we tried to put a non-dockable task in the docked stack or
- // the task is running in cropped window mode.
+ // the task was forced to be resizable by the system.
mWindowManager.scheduleShowNonResizeableDockToast(task.taskId);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 1ed749fdd9da..e4b4c2dcfad7 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -1,3 +1,19 @@
+/*
+ * 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.am;
import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
@@ -82,15 +98,23 @@ class ActivityStartInterceptor {
mAInfo = aInfo;
mResolvedType = resolvedType;
mInTask = inTask;
- interceptQuietProfileIfNeeded();
- interceptSuspendPackageIfNeed();
+ if (interceptSuspendPackageIfNeed()) {
+ // Skip the rest of interceptions as the package is suspended by device admin so
+ // no user action can undo this.
+ return;
+ }
+ if (interceptQuietProfileIfNeeded()) {
+ // If work profile is turned off, skip the work challenge since the profile can only
+ // be unlocked when profile's user is running.
+ return;
+ }
interceptWorkProfileChallengeIfNeeded();
}
- private void interceptQuietProfileIfNeeded() {
+ private boolean interceptQuietProfileIfNeeded() {
// Do not intercept if the user has not turned off the profile
if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
- return;
+ return false;
}
mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
mCallingPid = mRealCallingPid;
@@ -99,15 +123,15 @@ class ActivityStartInterceptor {
final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
- null /*profilerInfo*/);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
}
- private void interceptSuspendPackageIfNeed() {
+ private boolean interceptSuspendPackageIfNeed() {
// Do not intercept if the admin did not suspend the package
if (mAInfo == null || mAInfo.applicationInfo == null ||
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
- return;
+ return false;
}
mIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(mAInfo.packageName,
mUserId);
@@ -121,15 +145,15 @@ class ActivityStartInterceptor {
} else {
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
}
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
- null /*profilerInfo*/);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
}
- private void interceptWorkProfileChallengeIfNeeded() {
+ private boolean interceptWorkProfileChallengeIfNeeded() {
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
mResolvedType, mAInfo, mCallingPackage, mUserId);
if (interceptingIntent == null) {
- return;
+ return false;
}
mIntent = interceptingIntent;
mCallingPid = mRealCallingPid;
@@ -145,8 +169,8 @@ class ActivityStartInterceptor {
final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
- mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
- null /*profilerInfo*/);
+ mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b360b897d1ee..bcdc800c5857 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1,3 +1,19 @@
+/*
+ * 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.am;
import static android.app.Activity.RESULT_CANCELED;
@@ -74,7 +90,9 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -84,6 +102,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
@@ -574,6 +593,7 @@ class ActivityStarter {
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ mSupervisor.mActivityMetricsLogger.notifyActivityLaunching();
boolean componentSpecified = intent.getComponent() != null;
// Save a copy in case ephemeral needs it
@@ -582,6 +602,28 @@ class ActivityStarter {
intent = new Intent(intent);
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ if (rInfo == null) {
+ UserInfo userInfo = mSupervisor.getUserInfo(userId);
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ // Special case for managed profiles, if attempting to launch non-cryto aware
+ // app in a locked managed profile from an unlocked parent allow it to resolve
+ // as user will be sent via confirm credentials to unlock the profile.
+ UserManager userManager = UserManager.get(mService.mContext);
+ UserInfo parent = null;
+ long token = Binder.clearCallingIdentity();
+ try {
+ parent = userManager.getProfileParent(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ if (parent != null
+ && userManager.isUserUnlocked(parent.getUserHandle())
+ && !userManager.isUserUnlocked(userInfo.getUserHandle())) {
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ }
+ }
+ }
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
@@ -681,11 +723,13 @@ class ActivityStarter {
}
}
+ final ActivityRecord[] outRecord = new ActivityRecord[1];
int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor,
resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
- options, ignoreTargetSecurity, componentSpecified, null, container, inTask);
+ options, ignoreTargetSecurity, componentSpecified, outRecord, container,
+ inTask);
Binder.restoreCallingIdentity(origId);
@@ -732,6 +776,13 @@ class ActivityStarter {
}
}
+ final String componentName = outRecord[0] != null ? outRecord[0].shortComponentName
+ : null;
+ final boolean processRunning = outRecord[0] != null &&
+ mService.mProcessNames.get(outRecord[0].processName,
+ outRecord[0].appInfo.uid) != null;
+ mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, componentName,
+ processRunning);
return res;
}
}
@@ -1001,7 +1052,10 @@ class ActivityStarter {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
- mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
+ mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ // Go ahead and tell window manager to execute app transition for this activity
+ // since the app transition will not be triggered through the resume channel.
+ mWindowManager.executeAppTransition();
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
@@ -1362,7 +1416,7 @@ class ActivityStarter {
}
intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
- } else if (!mStartActivity.intent.filterEquals(intentActivity.task.intent)) {
+ } else if (!intentActivity.task.isSameIntentResolution(mStartActivity)) {
// In this case we are launching the root activity of the task, but with a
// different intent. We should start a new instance on top.
mAddingToTask = true;
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index b746a4b6b11c..86cdbcc43edf 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -37,6 +37,7 @@ import java.util.List;
import static com.android.server.am.ActivityManagerService.IS_USER_BUILD;
final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListener {
+
private final ActivityManagerService mService;
private final AppErrorResult mResult;
private final ProcessRecord mProc;
@@ -44,12 +45,17 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
private CharSequence mName;
+ static int CANT_SHOW = -1;
+ static int BACKGROUND_USER = -2;
+ static int ALREADY_SHOWING = -3;
+
// Event 'what' codes
static final int FORCE_QUIT = 1;
static final int FORCE_QUIT_AND_REPORT = 2;
static final int RESTART = 3;
static final int RESET = 4;
static final int MUTE = 5;
+ static final int TIMEOUT = 6;
// 5-minute timeout, then we automatically dismiss the crash dialog
static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
@@ -89,7 +95,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
// After the timeout, pretend the user clicked the quit button
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(FORCE_QUIT),
+ mHandler.obtainMessage(TIMEOUT),
DISMISS_TIMEOUT);
}
@@ -132,7 +138,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
mResult.set(result);
// Make sure we don't have time timeout still hanging around.
- removeMessages(FORCE_QUIT);
+ removeMessages(TIMEOUT);
dismiss();
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 190e9e1141b0..055935dd995e 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -17,6 +17,8 @@
package com.android.server.am;
import com.android.internal.app.ProcessMap;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
import com.android.internal.os.ProcessCpuTracker;
import com.android.server.Watchdog;
@@ -403,6 +405,10 @@ class AppErrors {
Intent appErrorIntent = null;
final long ident = Binder.clearCallingIdentity();
try {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
+ if (res == AppErrorDialog.TIMEOUT) {
+ res = AppErrorDialog.FORCE_QUIT;
+ }
if (res == AppErrorDialog.RESET) {
String[] packageList = r.getPackageList();
if (packageList != null) {
@@ -697,7 +703,7 @@ class AppErrors {
if (proc != null && proc.crashDialog != null) {
Slog.e(TAG, "App already has crash dialog: " + proc);
if (res != null) {
- res.set(0);
+ res.set(AppErrorDialog.ALREADY_SHOWING);
}
return;
}
@@ -710,7 +716,7 @@ class AppErrors {
if (isBackground && !showBackground) {
Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
if (res != null) {
- res.set(0);
+ res.set(AppErrorDialog.BACKGROUND_USER);
}
return;
}
@@ -724,7 +730,7 @@ class AppErrors {
// The device is asleep, so just pretend that the user
// saw a crash dialog and hit "force quit".
if (res != null) {
- res.set(0);
+ res.set(AppErrorDialog.CANT_SHOW);
}
}
}
@@ -920,6 +926,8 @@ class AppErrors {
ProcessRecord proc = (ProcessRecord)data.get("app");
if (proc != null && proc.anrDialog != null) {
Slog.e(TAG, "App already has anr dialog: " + proc);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
+ AppNotRespondingDialog.ALREADY_SHOWING);
return;
}
@@ -939,6 +947,8 @@ class AppErrors {
d.show();
proc.anrDialog = d;
} else {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
+ AppNotRespondingDialog.CANT_SHOW);
// Just kill the app if there is no dialog to be shown.
mService.killAppAtUsersRequest(proc, null);
}
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 987588759ae8..6d1d9f38c055 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
+
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
@@ -41,6 +44,9 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
static final int WAIT = 2;
static final int WAIT_AND_REPORT = 3;
+ public static final int CANT_SHOW = -1;
+ public static final int ALREADY_SHOWING = -2;
+
private final ActivityManagerService mService;
private final ProcessRecord mProc;
@@ -132,6 +138,10 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
Intent appErrorIntent = null;
+
+ MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_APP_ANR,
+ msg.what);
+
switch (msg.what) {
case FORCE_CLOSE:
// Kill the application.
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 9c139d524bc1..7209814312af 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -37,8 +37,12 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Environment;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings.System;
+import android.util.ArraySet;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import java.io.File;
@@ -59,12 +63,22 @@ class RecentTasks extends ArrayList<TaskRecord> {
// Maximum number recent bitmaps to keep in memory.
private static final int MAX_RECENT_BITMAPS = 3;
+ private static final int DEFAULT_INITIAL_CAPACITY = 5;
/**
* Save recent tasks information across reboots.
*/
private final TaskPersister mTaskPersister;
- private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(5);
+ private final ActivityManagerService mService;
+ private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
+ DEFAULT_INITIAL_CAPACITY);
+
+ /**
+ * Stores for each user task ids that are taken by tasks residing in persistent storage. These
+ * tasks may or may not currently be in memory.
+ */
+ final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>(
+ DEFAULT_INITIAL_CAPACITY);
// Mainly to avoid object recreation on multiple calls.
private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
@@ -75,6 +89,7 @@ class RecentTasks extends ArrayList<TaskRecord> {
RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) {
File systemDir = Environment.getDataSystemDirectory();
+ mService = service;
mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this);
mStackSupervisor.setRecentTasks(this);
}
@@ -87,6 +102,8 @@ class RecentTasks extends ArrayList<TaskRecord> {
*/
void loadUserRecentsLocked(int userId) {
if (!mUsersWithRecentsLoaded.get(userId)) {
+ // Load the task ids if not loaded.
+ loadPersistedTaskIdsForUserLocked(userId);
Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
addAll(mTaskPersister.restoreTasksForUserLocked(userId));
cleanupLocked(userId);
@@ -94,21 +111,49 @@ class RecentTasks extends ArrayList<TaskRecord> {
}
}
+ private void loadPersistedTaskIdsForUserLocked(int userId) {
+ // An empty instead of a null set here means that no persistent taskIds were present
+ // on file when we loaded them.
+ if (mPersistedTaskIds.get(userId) == null) {
+ mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId));
+ }
+ }
+
+ boolean taskIdTakenForUserLocked(int taskId, int userId) {
+ loadPersistedTaskIdsForUserLocked(userId);
+ return mPersistedTaskIds.get(userId).get(taskId);
+ }
+
void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
if (task != null && task.stack != null && task.stack.isHomeStack()) {
// Never persist the home stack.
return;
}
+ syncPersistentTaskIdsLocked();
mTaskPersister.wakeup(task, flush);
}
- void onSystemReady() {
- clear();
- loadUserRecentsLocked(UserHandle.USER_SYSTEM);
- startPersisting();
+ private void syncPersistentTaskIdsLocked() {
+ for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
+ int userId = mPersistedTaskIds.keyAt(i);
+ if (mUsersWithRecentsLoaded.get(userId)) {
+ // Recents are loaded only after task ids are loaded. Therefore, the set of taskids
+ // referenced here should not be null.
+ mPersistedTaskIds.valueAt(i).clear();
+ }
+ }
+ for (int i = size() - 1; i >= 0; i--) {
+ TaskRecord task = get(i);
+ if (task.isPersistable && (task.stack == null || !task.stack.isHomeStack())) {
+ // Set of persisted taskIds for task.userId should not be null here
+ mPersistedTaskIds.get(task.userId).put(task.taskId, true);
+ }
+ }
}
- void startPersisting() {
+
+ void onSystemReadyLocked() {
+ clear();
mTaskPersister.startPersisting();
}
@@ -125,11 +170,14 @@ class RecentTasks extends ArrayList<TaskRecord> {
}
void flush() {
+ synchronized (mService) {
+ syncPersistentTaskIdsLocked();
+ }
mTaskPersister.flush();
}
/**
- * Returns all userIds for which recents from storage are loaded
+ * Returns all userIds for which recents from persistent storage are loaded into this list.
*
* @return an array of userIds.
*/
@@ -149,12 +197,7 @@ class RecentTasks extends ArrayList<TaskRecord> {
return usersWithRecentsLoaded;
}
- /**
- * Removes recent tasks for this user if they are loaded, does not do anything otherwise.
- *
- * @param userId the user id.
- */
- void unloadUserRecentsLocked(int userId) {
+ private void unloadUserRecentsLocked(int userId) {
if (mUsersWithRecentsLoaded.get(userId)) {
Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
mUsersWithRecentsLoaded.delete(userId);
@@ -162,6 +205,18 @@ class RecentTasks extends ArrayList<TaskRecord> {
}
}
+ /**
+ * Removes recent tasks and any other state kept in memory for the passed in user. Does not
+ * touch the information present on persistent storage.
+ *
+ * @param userId the id of the user
+ */
+ void unloadUserDataFromMemoryLocked(int userId) {
+ unloadUserRecentsLocked(userId);
+ mPersistedTaskIds.delete(userId);
+ mTaskPersister.unloadUserDataFromMemory(userId);
+ }
+
TaskRecord taskForIdLocked(int id) {
final int recentsCount = size();
for (int i = 0; i < recentsCount; i++) {
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 283939e29229..11fd3bc61ca6 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Debug;
@@ -26,11 +29,13 @@ import android.os.SystemClock;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
-
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -38,9 +43,12 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
@@ -71,6 +79,7 @@ public class TaskPersister {
private static final String TASKS_DIRNAME = "recent_tasks";
private static final String TASK_EXTENSION = ".xml";
private static final String IMAGES_DIRNAME = "recent_images";
+ private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt";
static final String IMAGE_EXTENSION = ".png";
private static final String TAG_TASK = "task";
@@ -78,6 +87,7 @@ public class TaskPersister {
private final ActivityManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private final RecentTasks mRecentTasks;
+ private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
/**
* Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
@@ -170,6 +180,64 @@ public class TaskPersister {
}
}
+ @NonNull
+ SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
+ if (mTaskIdsInFile.get(userId) != null) {
+ return mTaskIdsInFile.get(userId).clone();
+ }
+ final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
+ BufferedReader reader = null;
+ String line;
+ try {
+ reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
+ while ((line = reader.readLine()) != null) {
+ for (String taskIdString : line.split("\\s+")) {
+ int id = Integer.parseInt(taskIdString);
+ persistedTaskIds.put(id, true);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // File doesn't exist. Ignore.
+ } catch (Exception e) {
+ Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+ mTaskIdsInFile.put(userId, persistedTaskIds);
+ return persistedTaskIds.clone();
+ }
+
+ private void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds,
+ int userId) {
+ if (userId < 0) {
+ return;
+ }
+ SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
+ if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
+ return;
+ }
+ final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
+ for (int i = 0; i < taskIds.size(); i++) {
+ if (taskIds.valueAt(i)) {
+ writer.write(String.valueOf(taskIds.keyAt(i)));
+ writer.newLine();
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
+ } finally {
+ IoUtils.closeQuietly(writer);
+ }
+ mTaskIdsInFile.put(userId, taskIds.clone());
+ }
+
+ void unloadUserDataFromMemory(int userId) {
+ mTaskIdsInFile.delete(userId);
+ }
+
void wakeup(TaskRecord task, boolean flush) {
synchronized (this) {
if (task != null) {
@@ -336,14 +404,16 @@ public class TaskPersister {
File[] recentFiles = userTasksDir.listFiles();
if (recentFiles == null) {
- Slog.e(TAG, "restoreTasksForUser: Unable to list files from " + userTasksDir);
+ Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
return tasks;
}
for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
File taskFile = recentFiles[taskNdx];
- if (DEBUG) Slog.d(TAG, "restoreTasksForUser: userId=" + userId
- + ", taskFile=" + taskFile.getName());
+ if (DEBUG) {
+ Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
+ + ", taskFile=" + taskFile.getName());
+ }
BufferedReader reader = null;
boolean deleteFile = false;
try {
@@ -366,20 +436,29 @@ public class TaskPersister {
// out the stuff we just read, if we don't write it we will
// read the same thing again.
// mWriteQueue.add(new TaskWriteQueueItem(task));
+
final int taskId = task.taskId;
- mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
- // Check if it's a valid user id. Don't add tasks for removed users.
- if (userId == task.userId) {
+ if (mStackSupervisor.anyTaskForIdLocked(taskId,
+ /* restoreFromRecents= */ false, 0) != null) {
+ // Should not happen.
+ Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
+ } else if (userId != task.userId) {
+ // Should not happen.
+ Slog.wtf(TAG, "Task with userId " + task.userId + " found in "
+ + userTasksDir.getAbsolutePath());
+ } else {
+ // Looks fine.
+ mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
task.isPersistable = true;
tasks.add(task);
recoveredTaskIds.add(taskId);
}
} else {
- Slog.e(TAG, "restoreTasksForUser: Unable to restore taskFile="
+ Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile="
+ taskFile + ": " + fileToString(taskFile));
}
} else {
- Slog.wtf(TAG, "restoreTasksForUser: Unknown xml event=" + event
+ Slog.wtf(TAG, "restoreTasksForUserLocked: Unknown xml event=" + event
+ " name=" + name);
}
}
@@ -454,6 +533,20 @@ public class TaskPersister {
}
}
+ private void writeTaskIdsFiles() {
+ int candidateUserIds[];
+ synchronized (mService) {
+ candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
+ }
+ SparseBooleanArray taskIdsToSave;
+ for (int userId : candidateUserIds) {
+ synchronized (mService) {
+ taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
+ }
+ maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
+ }
+ }
+
private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
int[] candidateUserIds;
synchronized (mService) {
@@ -472,8 +565,12 @@ public class TaskPersister {
return BitmapFactory.decodeFile(filename);
}
+ static File getUserPersistedTaskIdsFile(int userId) {
+ return new File(Environment.getDataSystemDeDirectory(userId), PERSISTED_TASK_IDS_FILENAME);
+ }
+
static File getUserTasksDir(int userId) {
- File userTasksDir = new File(Environment.getUserSystemDirectory(userId), TASKS_DIRNAME);
+ File userTasksDir = new File(Environment.getDataSystemCeDirectory(userId), TASKS_DIRNAME);
if (!userTasksDir.exists()) {
if (!userTasksDir.mkdir()) {
@@ -485,7 +582,7 @@ public class TaskPersister {
}
static File getUserImagesDir(int userId) {
- File userImagesDir = new File(Environment.getUserSystemDirectory(userId), IMAGES_DIRNAME);
+ File userImagesDir = new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
if (!userImagesDir.exists()) {
if (!userImagesDir.mkdir()) {
@@ -535,6 +632,7 @@ public class TaskPersister {
}
removeObsoleteFiles(persistentTaskIds);
}
+ writeTaskIdsFiles();
// If mNextWriteTime, then don't delay between each call to saveToXml().
final WriteQueueItem item;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 10f09775608b..62275a98aba1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -70,6 +70,7 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+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_UNRESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
@@ -122,9 +123,6 @@ final class TaskRecord {
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";
- // TODO(b/26847884): Currently needed while migrating to resize_mode.
- // Can be removed at some later point.
- private static final String ATTR_RESIZEABLE = "resizeable";
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";
@@ -245,6 +243,8 @@ final class TaskRecord {
// Bounds of the Task. null for fullscreen tasks.
Rect mBounds = null;
+ private final Rect mTmpStableBounds = new Rect();
+ private final Rect mTmpNonDecorBounds = new Rect();
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
@@ -469,6 +469,19 @@ final class TaskRecord {
setLockTaskAuth();
}
+ /**
+ * Return true if the input activity has the same intent resolution as the intent this task
+ * record is based on (normally the root activity intent).
+ */
+ boolean isSameIntentResolution(ActivityRecord r) {
+ final Intent intent = new Intent(r.intent);
+ // Correct the activity intent for aliasing. The task record intent will always be based on
+ // the real activity that will be launched not the alias, so we need to use an intent with
+ // the component name pointing to the real activity not the alias in the activity record.
+ intent.setComponent(r.realActivity);
+ return this.intent.filterEquals(intent);
+ }
+
void setTaskToReturnTo(int taskToReturnTo) {
mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
? HOME_ACTIVITY_TYPE : taskToReturnTo;
@@ -933,10 +946,15 @@ final class TaskRecord {
}
return false;
}
+
boolean isHomeTask() {
return taskType == HOME_ACTIVITY_TYPE;
}
+ boolean isRecentsTask() {
+ return taskType == RECENTS_ACTIVITY_TYPE;
+ }
+
boolean isApplicationTask() {
return taskType == APPLICATION_ACTIVITY_TYPE;
}
@@ -1006,6 +1024,7 @@ final class TaskRecord {
String label = null;
String iconFilename = null;
int colorPrimary = 0;
+ int colorBackground = 0;
for (--activityNdx; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = mActivities.get(activityNdx);
if (r.taskDescription != null) {
@@ -1018,9 +1037,13 @@ final class TaskRecord {
if (colorPrimary == 0) {
colorPrimary = r.taskDescription.getPrimaryColor();
}
+ if (colorBackground == 0) {
+ colorBackground = r.taskDescription.getBackgroundColor();
+ }
}
}
- lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename);
+ lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
+ colorBackground);
// Update the task affiliation color if we are the parent of the group
if (taskId == mAffiliatedTaskId) {
mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
@@ -1164,7 +1187,7 @@ final class TaskRecord {
int nextTaskId = INVALID_TASK_ID;
int callingUid = -1;
String callingPackage = "";
- int resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
boolean privileged = false;
Rect bounds = null;
@@ -1226,11 +1249,10 @@ final class TaskRecord {
callingUid = Integer.valueOf(attrValue);
} else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
callingPackage = attrValue;
- } else if (ATTR_RESIZEABLE.equals(attrName)) {
- resizeMode = Boolean.valueOf(attrValue)
- ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_CROP_WINDOWS;
} else if (ATTR_RESIZE_MODE.equals(attrName)) {
resizeMode = Integer.valueOf(attrValue);
+ resizeMode = (resizeMode == RESIZE_MODE_CROP_WINDOWS)
+ ? RESIZE_MODE_FORCE_RESIZEABLE : resizeMode;
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.valueOf(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
@@ -1306,6 +1328,38 @@ final class TaskRecord {
return task;
}
+ private void adjustForMinimalTaskDimensions(Rect bounds) {
+ if (bounds == null) {
+ return;
+ }
+ final int minimalSize = mMinimalSize == -1
+ ? mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask : mMinimalSize;
+ final boolean adjustWidth = minimalSize > bounds.width();
+ final boolean adjustHeight = minimalSize > bounds.height();
+ if (!(adjustWidth || adjustHeight)) {
+ return;
+ }
+
+ if (adjustWidth) {
+ if (mBounds != null && bounds.right == mBounds.right) {
+ bounds.left = bounds.right - minimalSize;
+ } else {
+ // Either left bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping left.
+ bounds.right = bounds.left + minimalSize;
+ }
+ }
+ if (adjustHeight) {
+ if (mBounds != null && bounds.bottom == mBounds.bottom) {
+ bounds.top = bounds.bottom - minimalSize;
+ } else {
+ // Either top bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping top.
+ bounds.bottom = bounds.top + minimalSize;
+ }
+ }
+ }
+
/**
* Update task's override configuration based on the bounds.
* @param bounds The bounds of the task.
@@ -1338,20 +1392,17 @@ final class TaskRecord {
mBounds = null;
mOverrideConfig = Configuration.EMPTY;
} else {
+ mTmpRect.set(bounds);
+ adjustForMinimalTaskDimensions(mTmpRect);
if (mBounds == null) {
- mBounds = new Rect(bounds);
+ mBounds = new Rect(mTmpRect);
} else {
- mBounds.set(bounds);
+ mBounds.set(mTmpRect);
}
if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
mLastNonFullscreenBounds = mBounds;
}
-
- // Stable insets need to be subtracted because we also subtract it in the fullscreen
- // configuration.
- mTmpRect.set(bounds);
- subtractStableInsets(mTmpRect, insetBounds != null ? insetBounds : mTmpRect);
- mOverrideConfig = calculateOverrideConfig(mTmpRect);
+ mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds);
}
if (mFullscreen != oldFullscreen) {
@@ -1361,6 +1412,16 @@ final class TaskRecord {
return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
+ private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds) {
+ mTmpRect2.set(inInsetBounds);
+ mService.mWindowManager.subtractNonDecorInsets(mTmpRect2);
+ int leftInset = mTmpRect2.left - inInsetBounds.left;
+ int topInset = mTmpRect2.top - inInsetBounds.top;
+ int rightInset = inInsetBounds.right - mTmpRect2.right;
+ int bottomInset = inInsetBounds.bottom - mTmpRect2.bottom;
+ inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
+ }
+
private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds) {
mTmpRect2.set(inInsetBounds);
mService.mWindowManager.subtractStableInsets(mTmpRect2);
@@ -1371,23 +1432,39 @@ final class TaskRecord {
inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
}
- Configuration calculateOverrideConfig(Rect bounds) {
+ private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds) {
+ mTmpNonDecorBounds.set(bounds);
+ mTmpStableBounds.set(bounds);
+ subtractNonDecorInsets(
+ mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds);
+ subtractStableInsets(
+ mTmpStableBounds, insetBounds != null ? insetBounds : bounds);
+
+ // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
+ // i.e. the screen area without the system bars.
final Configuration serviceConfig = mService.mConfiguration;
final Configuration config = new Configuration(Configuration.EMPTY);
// TODO(multidisplay): Update Dp to that of display stack is on.
final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
config.screenWidthDp =
- Math.min((int)(bounds.width() / density), serviceConfig.screenWidthDp);
+ Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);
config.screenHeightDp =
- Math.min((int)(bounds.height() / density), serviceConfig.screenHeightDp);
- config.smallestScreenWidthDp =
- Math.min(config.screenWidthDp, config.screenHeightDp);
+ Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);
+ config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp);
+
+ // TODO: Orientation?
config.orientation = (config.screenWidthDp <= config.screenHeightDp)
? Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
+
+ // For calculating screen layout, we need to use the non-decor inset screen area for the
+ // calculation for compatibility reasons, i.e. screen area without system bars that could
+ // never go away in Honeycomb.
+ final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
+ final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
- int longSize = Math.max(config.screenWidthDp, config.screenHeightDp);
- int shortSize = Math.min(config.screenWidthDp, config.screenHeightDp);
+ final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
+ final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
return config;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a355fa4750eb..addffd33d746 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -68,6 +68,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.provider.Settings;
@@ -82,6 +83,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
import com.android.server.pm.UserManagerService;
import java.io.PrintWriter;
@@ -165,15 +167,15 @@ final class UserController {
void register(ContentResolver resolver) {
resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
synchronized (mService) {
- updateCurrentUserSetupCompleteLocked();
+ updateUserSetupCompleteLocked(UserHandle.USER_ALL);
}
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, Uri uri, int userId) {
if (mUserSetupComplete.equals(uri)) {
synchronized (mService) {
- updateCurrentUserSetupCompleteLocked();
+ updateUserSetupCompleteLocked(userId);
}
}
}
@@ -297,6 +299,22 @@ final class UserController {
null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
userId);
+ if (getUserInfo(userId).isManagedProfile()) {
+ UserInfo parent = getUserManager().getProfileParent(userId);
+ if (parent != null) {
+ final Intent profileUnlockedIntent = new Intent(
+ Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+ profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
+ profileUnlockedIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ mService.broadcastIntentLocked(null, null, profileUnlockedIntent,
+ null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID,
+ parent.id);
+ }
+ }
+
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -545,6 +563,10 @@ final class UserController {
continue;
}
UserInfo userInfo = getUserInfo(oldUserId);
+ if (userInfo.isEphemeral()) {
+ LocalServices.getService(UserManagerInternal.class)
+ .onEphemeralUserStop(oldUserId);
+ }
if (userInfo.isGuest() || userInfo.isEphemeral()) {
// This is a user to be stopped.
stopUsersLocked(oldUserId, true, null);
@@ -655,7 +677,7 @@ final class UserController {
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
- updateCurrentUserSetupCompleteLocked();
+ updateUserSetupCompleteLocked(userId);
if (foreground) {
mCurrentUserId = userId;
@@ -870,11 +892,16 @@ final class UserController {
mUserSwitchObservers.finishBroadcast();
}
- void updateCurrentUserSetupCompleteLocked() {
+ void updateUserSetupCompleteLocked(int userId) {
final ContentResolver cr = mService.mContext.getContentResolver();
- final boolean setupComplete =
- Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, mCurrentUserId) != 0;
- mSetupCompletedUsers.put(mCurrentUserId, setupComplete);
+ for (int i = mStartedUsers.size() - 1; i >= 0; i--) {
+ int startedUser = mStartedUsers.keyAt(i);
+ if (startedUser == userId || userId == UserHandle.USER_ALL) {
+ final boolean setupComplete =
+ Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, startedUser) != 0;
+ mSetupCompletedUsers.put(startedUser, setupComplete);
+ }
+ }
}
boolean isUserSetupCompleteLocked(int userId) {
@@ -1354,6 +1381,11 @@ final class UserController {
* intercept activity launches for work apps when the Work Challenge is present.
*/
boolean shouldConfirmCredentials(int userId) {
+ synchronized (mService) {
+ if (mStartedUsers.get(userId) == null) {
+ return false;
+ }
+ }
if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
return false;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 548f563bd6af..a3100c820d99 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -222,7 +222,6 @@ public class AudioService extends IAudioService.Stub {
private static final int MSG_UNMUTE_STREAM = 24;
private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
private static final int MSG_INDICATE_SYSTEM_READY = 26;
- private static final int MSG_PERSIST_MASTER_MONO = 27;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -827,10 +826,7 @@ public class AudioService extends IAudioService.Stub {
}
// Restore mono mode
- final boolean masterMono = System.getIntForUser(
- mContentResolver, System.MASTER_MONO,
- 0 /* default */, UserHandle.USER_CURRENT) == 1;
- AudioSystem.setMasterMono(masterMono);
+ updateMasterMono(mContentResolver);
// Restore ringer mode
setRingerModeInt(getRingerModeInternal(), false);
@@ -1015,6 +1011,16 @@ public class AudioService extends IAudioService.Stub {
0);
}
+ private void updateMasterMono(ContentResolver cr)
+ {
+ final boolean masterMono = System.getIntForUser(
+ cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
+ if (DEBUG_VOL) {
+ Log.d(TAG, String.format("Master mono %b", masterMono));
+ }
+ AudioSystem.setMasterMono(masterMono);
+ }
+
private void readPersistedSettings() {
final ContentResolver cr = mContentResolver;
@@ -1091,13 +1097,7 @@ public class AudioService extends IAudioService.Stub {
}
AudioSystem.muteMicrophone(microphoneMute);
- final boolean masterMono = System.getIntForUser(
- cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
- if (DEBUG_VOL) {
- Log.d(TAG, String.format("Master mono %b, user=%d", masterMono, currentUser));
- }
- AudioSystem.setMasterMono(masterMono);
- broadcastMasterMonoStatus(masterMono);
+ updateMasterMono(cr);
// Each stream will read its own persisted settings
@@ -1855,52 +1855,6 @@ public class AudioService extends IAudioService.Stub {
userId);
}
- /** @hide */
- public boolean isMasterMono() {
- return AudioSystem.getMasterMono();
- }
-
- /** @hide */
- public void setMasterMono(boolean mono, String callingPackage, int userId) {
- int callingUid = Binder.getCallingUid();
- // If we are being called by the system check for user we are going to change
- // so we handle user restrictions correctly.
- if (callingUid == android.os.Process.SYSTEM_UID) {
- callingUid = UserHandle.getUid(userId, UserHandle.getAppId(callingUid));
- }
-
- if (userId != UserHandle.getCallingUserId() &&
- mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- if (DEBUG_VOL) {
- Log.d(TAG, String.format("Master mono %b, user=%d", mono, userId));
- }
-
- if (getCurrentUserId() == userId) {
- if (mono != AudioSystem.getMasterMono()) {
- AudioSystem.setMasterMono(mono);
- // Post a persist master mono msg
- sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
- : 0 /* value */, userId, null /* obj */, 0 /* delay */);
- // notify apps and settings
- broadcastMasterMonoStatus(mono);
- }
- } else {
- // Post a persist master mono msg
- sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
- : 0 /* value */, userId, null /* obj */, 0 /* delay */);
- }
- }
-
- private void broadcastMasterMonoStatus(boolean mono) {
- Intent intent = new Intent(AudioManager.MASTER_MONO_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_MASTER_MONO, mono);
- sendBroadcastToAll(intent);
- }
-
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -4641,13 +4595,6 @@ public class AudioService extends IAudioService.Stub {
case MSG_DYN_POLICY_MIX_STATE_UPDATE:
onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
break;
-
- case MSG_PERSIST_MASTER_MONO:
- Settings.System.putIntForUser(mContentResolver,
- Settings.System.MASTER_MONO,
- msg.arg1 /* value */,
- msg.arg2 /* userHandle */);
- break;
}
}
}
@@ -4660,6 +4607,8 @@ public class AudioService extends IAudioService.Stub {
Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
mContentResolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
+ mContentResolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.MASTER_MONO), false, this);
}
@Override
@@ -4678,6 +4627,7 @@ public class AudioService extends IAudioService.Stub {
setRingerModeInt(getRingerModeInternal(), false);
}
readDockAudioSettings(mContentResolver);
+ updateMasterMono(mContentResolver);
}
}
}
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 5806f3fb5b70..7e76ac46a545 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -16,10 +16,12 @@
package com.android.server.audio;
+import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecordConfiguration;
import android.media.AudioSystem;
import android.media.IRecordingConfigDispatcher;
+import android.media.MediaRecorder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -47,8 +49,12 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
/**
* Implementation of android.media.AudioSystem.AudioRecordingCallback
*/
- public void onRecordingConfigurationChanged(int event, int session, int source) {
- if (updateSnapshot(event, session, source)) {
+ public void onRecordingConfigurationChanged(int event, int session, int source,
+ int[] recordingInfo) {
+ if (MediaRecorder.isSystemOnlyAudioSource(source)) {
+ return;
+ }
+ if (updateSnapshot(event, session, source, recordingInfo)) {
final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
synchronized(mClients) {
while (clientIterator.hasNext()) {
@@ -106,23 +112,48 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
* @param event
* @param session
* @param source
+ * @param recordingFormat see
+ * {@link AudioSystem.AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])}
+ * for the definition of the contents of the array
* @return true if the list of active recording sessions has been modified, false otherwise.
*/
- private boolean updateSnapshot(int event, int session, int source) {
+ private boolean updateSnapshot(int event, int session, int source, int[] recordingInfo) {
synchronized(mRecordConfigs) {
switch (event) {
case AudioManager.RECORD_CONFIG_EVENT_STOP:
// return failure if an unknown recording session stopped
return (mRecordConfigs.remove(new Integer(session)) != null);
case AudioManager.RECORD_CONFIG_EVENT_START:
- if (mRecordConfigs.containsKey(new Integer(session))) {
- // start of session that's already tracked, not worth an update
- // TO DO in the future when tracking record format: there might be a record
- // format change during a recording that requires reporting
- return false;
+ final AudioFormat clientFormat = new AudioFormat.Builder()
+ .setEncoding(recordingInfo[0])
+ // FIXME this doesn't support index-based masks
+ .setChannelMask(recordingInfo[1])
+ .setSampleRate(recordingInfo[2])
+ .build();
+ final AudioFormat deviceFormat = new AudioFormat.Builder()
+ .setEncoding(recordingInfo[3])
+ // FIXME this doesn't support index-based masks
+ .setChannelMask(recordingInfo[4])
+ .setSampleRate(recordingInfo[5])
+ .build();
+ final int patchHandle = recordingInfo[6];
+ final Integer sessionKey = new Integer(session);
+ if (mRecordConfigs.containsKey(sessionKey)) {
+ final AudioRecordConfiguration updatedConfig =
+ new AudioRecordConfiguration(session, source,
+ clientFormat, deviceFormat, patchHandle);
+ if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) {
+ return false;
+ } else {
+ // config exists but has been modified
+ mRecordConfigs.remove(sessionKey);
+ mRecordConfigs.put(sessionKey, updatedConfig);
+ return true;
+ }
} else {
- mRecordConfigs.put(new Integer(session),
- new AudioRecordConfiguration(session, source));
+ mRecordConfigs.put(sessionKey,
+ new AudioRecordConfiguration(session, source,
+ clientFormat, deviceFormat, patchHandle));
return true;
}
default:
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
new file mode 100644
index 000000000000..f6dc9b98c136
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -0,0 +1,177 @@
+/*
+ * 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.connectivity;
+
+import com.android.server.SystemService;
+
+import android.content.Context;
+import android.net.ConnectivityMetricsEvent;
+import android.net.ConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLoggerSubscriber;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** {@hide} */
+public class MetricsLoggerService extends SystemService {
+ private static String TAG = "ConnectivityMetricsLoggerService";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ public MetricsLoggerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+ publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
+ mBinder);
+ }
+ }
+
+ private final int MAX_NUMBER_OF_EVENTS = 100;
+ private final int MAX_TIME_OFFSET = 15*60*1000; // 15 minutes
+ private final List<ConnectivityMetricsEvent> mEvents = new ArrayList<>();
+ private long mLastSentEventTimeMillis = System.currentTimeMillis();
+
+ private final void enforceConnectivityInternalPermission() {
+ getContext().enforceCallingPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "MetricsLoggerService");
+ }
+
+ /**
+ * Implementation of the IConnectivityMetricsLogger interface.
+ */
+ private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
+
+ private final ArrayMap<IConnectivityMetricsLoggerSubscriber,
+ IBinder.DeathRecipient> mSubscribers = new ArrayMap<>();
+
+
+ private ConnectivityMetricsEvent[] prepareEventsToSendIfReady() {
+ ConnectivityMetricsEvent[] eventsToSend = null;
+ final long currentTimeMillis = System.currentTimeMillis();
+ final long timeOffset = currentTimeMillis - mLastSentEventTimeMillis;
+ if (timeOffset >= MAX_TIME_OFFSET
+ || timeOffset < 0 // system time has changed
+ || mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+ // batch events
+ mLastSentEventTimeMillis = currentTimeMillis;
+ eventsToSend = new ConnectivityMetricsEvent[mEvents.size()];
+ mEvents.toArray(eventsToSend);
+ mEvents.clear();
+ }
+ return eventsToSend;
+ }
+
+ private void maybeSendEventsToSubscribers(ConnectivityMetricsEvent[] eventsToSend) {
+ if (eventsToSend == null || eventsToSend.length == 0) return;
+ synchronized (mSubscribers) {
+ for (IConnectivityMetricsLoggerSubscriber s : mSubscribers.keySet()) {
+ try {
+ s.onEvents(eventsToSend);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "RemoteException " + ex);
+ }
+ }
+ }
+ }
+
+ public void logEvent(ConnectivityMetricsEvent event) {
+ ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
+ logEvents(events);
+ }
+
+ public void logEvents(ConnectivityMetricsEvent[] events) {
+ enforceConnectivityInternalPermission();
+ ConnectivityMetricsEvent[] eventsToSend;
+
+ if (VDBG) {
+ for (ConnectivityMetricsEvent e : events) {
+ Log.v(TAG, "writeEvent(" + e.toString() + ")");
+ }
+ }
+
+ synchronized (mEvents) {
+ for (ConnectivityMetricsEvent e : events) {
+ mEvents.add(e);
+ }
+
+ eventsToSend = prepareEventsToSendIfReady();
+ }
+
+ maybeSendEventsToSubscribers(eventsToSend);
+ }
+
+ public boolean subscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
+ enforceConnectivityInternalPermission();
+ if (VDBG) Log.v(TAG, "subscribe");
+
+ synchronized (mSubscribers) {
+ if (mSubscribers.containsKey(subscriber)) {
+ Log.e(TAG, "subscriber is already subscribed");
+ return false;
+ }
+ final IConnectivityMetricsLoggerSubscriber s = subscriber;
+ IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (VDBG) Log.v(TAG, "subscriber died");
+ synchronized (mSubscribers) {
+ mSubscribers.remove(s);
+ }
+ }
+ };
+
+ try {
+ subscriber.asBinder().linkToDeath(dr, 0);
+ mSubscribers.put(subscriber, dr);
+ } catch (RemoteException e) {
+ Log.e(TAG, "subscribe failed: " + e);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void unsubscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
+ enforceConnectivityInternalPermission();
+ if (VDBG) Log.v(TAG, "unsubscribe");
+ synchronized (mSubscribers) {
+ IBinder.DeathRecipient dr = mSubscribers.remove(subscriber);
+ if (dr == null) {
+ Log.e(TAG, "subscriber is not subscribed");
+ return;
+ }
+ subscriber.asBinder().unlinkToDeath(dr, 0);
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5fd39c02a10a..dc6260921a67 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -49,7 +49,9 @@ import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -107,27 +109,33 @@ public class NetworkDiagnostics {
// so callers can wait for completion.
private final CountDownLatch mCountDownLatch;
- private class Measurement {
+ public class Measurement {
private static final String SUCCEEDED = "SUCCEEDED";
private static final String FAILED = "FAILED";
- // TODO: Refactor to make these private for better encapsulation.
- public String description = "";
- public long startTime;
- public long finishTime;
- public String result = "";
- public Thread thread;
+ private boolean succeeded;
- public void recordSuccess(String msg) {
+ // Package private. TODO: investigate better encapsulation.
+ String description = "";
+ long startTime;
+ long finishTime;
+ String result = "";
+ Thread thread;
+
+ public boolean checkSucceeded() { return succeeded; }
+
+ void recordSuccess(String msg) {
maybeFixupTimes();
+ succeeded = true;
result = SUCCEEDED + ": " + msg;
if (mCountDownLatch != null) {
mCountDownLatch.countDown();
}
}
- public void recordFailure(String msg) {
+ void recordFailure(String msg) {
maybeFixupTimes();
+ succeeded = false;
result = FAILED + ": " + msg;
if (mCountDownLatch != null) {
mCountDownLatch.countDown();
@@ -265,41 +273,69 @@ public class NetworkDiagnostics {
} catch (InterruptedException ignored) {}
}
- public void dump(IndentingPrintWriter pw) {
- pw.println(TAG + ":" + mDescription);
- final long unfinished = mCountDownLatch.getCount();
- if (unfinished > 0) {
- // This can't happen unless a caller forgets to call waitForMeasurements()
- // or a measurement isn't implemented to correctly honor the timeout.
- pw.println("WARNING: countdown wait incomplete: "
- + unfinished + " unfinished measurements");
- }
+ public List<Measurement> getMeasurements() {
+ // TODO: Consider moving waitForMeasurements() in here to minimize the
+ // chance of caller errors.
- pw.increaseIndent();
+ ArrayList<Measurement> measurements = new ArrayList(totalMeasurementCount());
+
+ // Sort measurements IPv4 first.
for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
if (entry.getKey() instanceof Inet4Address) {
- pw.println(entry.getValue().toString());
+ measurements.add(entry.getValue());
+ }
+ }
+ for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+ mExplicitSourceIcmpChecks.entrySet()) {
+ if (entry.getKey().first instanceof Inet4Address) {
+ measurements.add(entry.getValue());
+ }
+ }
+ for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
+ if (entry.getKey() instanceof Inet4Address) {
+ measurements.add(entry.getValue());
}
}
+
+ // IPv6 measurements second.
for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
if (entry.getKey() instanceof Inet6Address) {
- pw.println(entry.getValue().toString());
+ measurements.add(entry.getValue());
}
}
for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
mExplicitSourceIcmpChecks.entrySet()) {
- pw.println(entry.getValue().toString());
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet4Address) {
- pw.println(entry.getValue().toString());
+ if (entry.getKey().first instanceof Inet6Address) {
+ measurements.add(entry.getValue());
}
}
for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
if (entry.getKey() instanceof Inet6Address) {
- pw.println(entry.getValue().toString());
+ measurements.add(entry.getValue());
}
}
+
+ return measurements;
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.println(TAG + ":" + mDescription);
+ final long unfinished = mCountDownLatch.getCount();
+ if (unfinished > 0) {
+ // This can't happen unless a caller forgets to call waitForMeasurements()
+ // or a measurement isn't implemented to correctly honor the timeout.
+ pw.println("WARNING: countdown wait incomplete: "
+ + unfinished + " unfinished measurements");
+ }
+
+ pw.increaseIndent();
+
+ String prefix;
+ for (Measurement m : getMeasurements()) {
+ prefix = m.checkSucceeded() ? "." : "F";
+ pw.println(prefix + " " + m.toString());
+ }
+
pw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index fd9abffc88ef..f231f922a0e6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -190,6 +190,7 @@ public class Vpn {
if (!setPackageAuthorization(packageName, true)) {
return false;
}
+ prepareInternal(packageName);
}
// Save the new package name in Settings.Secure.
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index daf839a59e1b..95a98751c7d0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -62,6 +62,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Messenger;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -70,40 +71,42 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.os.Messenger;
import android.provider.Settings;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.EventLog;
import android.util.Log;
-import android.util.Slog;
import android.util.Pair;
-
+import android.util.Slog;
import android.util.SparseArray;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
import com.android.internal.R;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.accounts.AccountManagerService;
+import com.android.server.backup.AccountSyncSettingsBackupHelper;
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import com.android.server.content.SyncStorageEngine.EndPoint;
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Random;
-import java.util.List;
-import java.util.HashSet;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Map;
-import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Random;
+import java.util.Set;
/**
* Implementation details:
@@ -178,18 +181,6 @@ public class SyncManager {
private static final int SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES = 10; // 10 bytes
/**
- * How long to delay each queued {@link SyncHandler} message that may have occurred before boot
- * or befor the device became provisioned.
- */
- private static final long PER_SYNC_BOOT_DELAY_MILLIS = 1000L; // 1 second
-
- /**
- * The maximum amount of time we're willing to delay syncs out of boot, after device has been
- * provisioned, etc.
- */
- private static final long MAX_SYNC_BOOT_DELAY_MILLIS = 60000L; // 1 minute
-
- /**
* If a previously scheduled sync becomes ready and we are low on storage, it gets
* pushed back for this amount of time.
*/
@@ -242,12 +233,24 @@ public class SyncManager {
private SparseArray<SyncOperation> mScheduledSyncs = new SparseArray<SyncOperation>(32);
private final Random mRand;
- private int getUnusedJobId() {
+ private boolean isJobIdInUseLockedH(int jobId) {
+ if (mScheduledSyncs.indexOfKey(jobId) >= 0) {
+ return true;
+ }
+ for (ActiveSyncContext asc: mActiveSyncContexts) {
+ if (asc.mSyncOperation.jobId == jobId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int getUnusedJobIdH() {
synchronized (mScheduledSyncs) {
- int newJobId = mRand.nextInt(Integer.MAX_VALUE);
- while (mScheduledSyncs.indexOfKey(newJobId) >= 0) {
+ int newJobId;
+ do {
newJobId = mRand.nextInt(Integer.MAX_VALUE);
- }
+ } while (isJobIdInUseLockedH(newJobId));
return newJobId;
}
}
@@ -425,6 +428,35 @@ public class SyncManager {
}
}
+ /**
+ * Cancel all unnecessary jobs. This function will be run once after every boot.
+ */
+ private void cleanupJobs() {
+ // O(n^2) in number of jobs, so we run this on the background thread.
+ mSyncHandler.postAtFrontOfQueue(new Runnable() {
+ @Override
+ public void run() {
+ List<SyncOperation> ops = getAllPendingSyncsFromCache();
+ Set<String> cleanedKeys = new HashSet<String>();
+ for (SyncOperation opx: ops) {
+ if (cleanedKeys.contains(opx.key)) {
+ continue;
+ }
+ cleanedKeys.add(opx.key);
+ for (SyncOperation opy: ops) {
+ if (opx == opy) {
+ continue;
+ }
+ if (opx.key.equals(opy.key)) {
+ removeSyncOperationFromCache(opy.jobId);
+ mJobScheduler.cancel(opy.jobId);
+ }
+ }
+ }
+ }
+ });
+ }
+
private synchronized void verifyJobScheduler() {
if (mJobScheduler != null) {
return;
@@ -449,6 +481,7 @@ public class SyncManager {
}
}
}
+ cleanupJobs();
}
private JobScheduler getJobScheduler() {
@@ -479,12 +512,12 @@ public class SyncManager {
mSyncStorageEngine.setPeriodicSyncAddedListener(
new SyncStorageEngine.PeriodicSyncAddedListener() {
- @Override
- public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
- long flex) {
- updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
- }
- });
+ @Override
+ public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
+ long flex) {
+ updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
+ }
+ });
mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
@Override
@@ -719,10 +752,9 @@ public class SyncManager {
* @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
*/
public void scheduleSync(Account requestedAccount, int userId, int reason,
- String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
- long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+ String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
+ long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- EndPoint ep = new EndPoint(requestedAccount,requestedAuthority, userId);
if (extras == null) {
extras = new Bundle();
}
@@ -911,7 +943,7 @@ public class SyncManager {
* flexMillis will be updated.
*/
public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
- Bundle extras) {
+ Bundle extras) {
UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
pollFrequency, flex, extras);
mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
@@ -965,7 +997,7 @@ public class SyncManager {
}
private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
- SyncResult syncResult) {
+ SyncResult syncResult) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
@@ -1023,7 +1055,7 @@ public class SyncManager {
public final SyncResult syncResult;
SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
- SyncResult syncResult) {
+ SyncResult syncResult) {
this.activeSyncContext = syncContext;
this.syncResult = syncResult;
}
@@ -1036,7 +1068,7 @@ public class SyncManager {
public final Bundle extras;
UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
- Bundle extras) {
+ Bundle extras) {
this.target = target;
this.pollFrequency = pollFrequency;
this.flex = flex;
@@ -1197,7 +1229,18 @@ public class SyncManager {
}
// Check if duplicate syncs are pending. If found, keep one with least expected run time.
- if (!syncOperation.isReasonPeriodic()) {
+ if (!syncOperation.isPeriodic) {
+ // Check currently running syncs
+ for (ActiveSyncContext asc: mActiveSyncContexts) {
+ if (asc.mSyncOperation.key.equals(syncOperation.key)) {
+ if (isLoggable) {
+ Log.v(TAG, "Duplicate sync is already running. Not scheduling "
+ + syncOperation);
+ }
+ return;
+ }
+ }
+
int duplicatesCount = 0;
long now = SystemClock.elapsedRealtime();
syncOperation.expectedRuntime = now + minDelay;
@@ -1240,21 +1283,23 @@ public class SyncManager {
}
}
- syncOperation.jobId = getUnusedJobId();
+ // Syncs that are re-scheduled shouldn't get a new job id.
+ if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
+ syncOperation.jobId = getUnusedJobIdH();
+ }
addSyncOperationToCache(syncOperation);
if (isLoggable) {
- Slog.v(TAG, "scheduling sync operation " + syncOperation.target.toString());
+ Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
}
- // This is done to give preference to syncs that are not pushed back.
int priority = syncOperation.findPriority();
final int networkType = syncOperation.isNotAllowedOnMetered() ?
JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
- new ComponentName(mContext, SyncJobService.class))
+ new ComponentName(mContext, SyncJobService.class))
.setExtras(syncOperation.toJobInfoExtras())
.setRequiredNetworkType(networkType)
.setPersisted(true)
@@ -1274,7 +1319,7 @@ public class SyncManager {
}
getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
- syncOperation.target.userId);
+ syncOperation.target.userId, "sync");
}
/**
@@ -1343,7 +1388,7 @@ public class SyncManager {
Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
+ "encountered an error: " + operation);
}
- scheduleSyncOperationH(operation, 0 /* immediately */);
+ scheduleSyncOperationH(operation);
} else if (syncResult.tooManyRetries) {
// If this sync aborted because the internal sync loop retried too many times then
// don't reschedule. Otherwise we risk getting into a retry loop.
@@ -1357,7 +1402,7 @@ public class SyncManager {
Log.d(TAG, "retrying sync operation because even though it had an error "
+ "it achieved some success");
}
- scheduleSyncOperationH(operation, 0 /* immediately */);
+ scheduleSyncOperationH(operation);
} else if (syncResult.syncAlreadyInProgress) {
if (isLoggable) {
Log.d(TAG, "retrying sync operation that failed because there was already a "
@@ -1459,7 +1504,7 @@ public class SyncManager {
* for this sync. This is used to attribute the wakelock hold to that application.
*/
public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
- int syncAdapterUid) {
+ int syncAdapterUid) {
super();
mSyncAdapterUid = syncAdapterUid;
mSyncOperation = syncOperation;
@@ -1688,7 +1733,7 @@ public class SyncManager {
new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
@Override
public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
- RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
+ RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
return lhs.type.authority.compareTo(rhs.type.authority);
}
});
@@ -2188,6 +2233,7 @@ public class SyncManager {
void checkIfDeviceReady() {
if (mProvisioned && mBootCompleted) {
synchronized(this) {
+ mSyncStorageEngine.restoreAllPeriodicSyncs();
// Dispatch any stashed messages.
obtainMessage(MESSAGE_RELEASE_MESSAGES_FROM_QUEUE).sendToTarget();
}
@@ -2207,7 +2253,8 @@ public class SyncManager {
synchronized (this) {
if (!mBootCompleted || !mProvisioned) {
if (msg.what == MESSAGE_START_SYNC) {
- deferSyncH((SyncOperation) msg.obj, 60*1000 /* 1 minute */);
+ SyncOperation op = (SyncOperation) msg.obj;
+ addSyncOperationToCache(op);
}
// Need to copy the message bc looper will recycle it.
Message m = Message.obtain(msg);
@@ -2272,21 +2319,24 @@ public class SyncManager {
case MESSAGE_STOP_SYNC:
op = (SyncOperation) msg.obj;
- boolean reschedule = msg.arg1 != 0;
- boolean applyBackoff = msg.arg2 != 0;
if (isLoggable) {
- Slog.v(TAG, "Stop sync received. Reschedule: " + reschedule
- + "Backoff: " + applyBackoff);
- }
- if (applyBackoff) {
- increaseBackoffSetting(op.target);
- }
- if (reschedule) {
- scheduleSyncOperationH(op);
+ Slog.v(TAG, "Stop sync received.");
}
ActiveSyncContext asc = findActiveSyncContextH(op.jobId);
if (asc != null) {
runSyncFinishedOrCanceledH(null /* no result */, asc);
+ boolean reschedule = msg.arg1 != 0;
+ boolean applyBackoff = msg.arg2 != 0;
+ if (isLoggable) {
+ Slog.v(TAG, "Stopping sync. Reschedule: " + reschedule
+ + "Backoff: " + applyBackoff);
+ }
+ if (applyBackoff) {
+ increaseBackoffSetting(op.target);
+ }
+ if (reschedule) {
+ deferStoppedSyncH(op, 0);
+ }
}
break;
@@ -2414,7 +2464,8 @@ public class SyncManager {
/**
* Defer the specified SyncOperation by rescheduling it on the JobScheduler with some
- * delay.
+ * delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
+ * sync will be scheduled.
*/
private void deferSyncH(SyncOperation op, long delay) {
mSyncJobService.callJobFinished(op.jobId, false);
@@ -2426,14 +2477,22 @@ public class SyncManager {
}
}
+ /* Same as deferSyncH, but assumes that job is no longer running on JobScheduler. */
+ private void deferStoppedSyncH(SyncOperation op, long delay) {
+ if (op.isPeriodic) {
+ scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
+ } else {
+ removeSyncOperationFromCache(op.jobId);
+ scheduleSyncOperationH(op, delay);
+ }
+ }
+
/**
* Cancel an active sync and reschedule it on the JobScheduler with some delay.
*/
private void deferActiveSyncH(ActiveSyncContext asc) {
SyncOperation op = asc.mSyncOperation;
-
- mSyncHandler.obtainMessage(MESSAGE_STOP_SYNC, 0 /* no reschedule */,
- 0 /* no backoff */, op).sendToTarget();
+ runSyncFinishedOrCanceledH(null, asc);
deferSyncH(op, SYNC_DELAY_ON_CONFLICT);
}
@@ -2467,6 +2526,7 @@ public class SyncManager {
// Check for adapter delays.
if (isAdapterDelayed(op.target)) {
deferSyncH(op, 0 /* No minimum delay */);
+ return;
}
} else {
// Remove SyncOperation entry from mScheduledSyncs cache for non periodic jobs.
@@ -2489,6 +2549,7 @@ public class SyncManager {
Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
}
deferActiveSyncH(asc);
+ break;
}
}
}
@@ -2514,6 +2575,7 @@ public class SyncManager {
}
private void updateRunningAccountsH(EndPoint syncTargets) {
+ AccountAndUser[] oldAccounts = mRunningAccounts;
mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "Accounts list: ");
@@ -2523,7 +2585,6 @@ public class SyncManager {
}
if (mBootCompleted) {
doDatabaseCleanup();
- mSyncStorageEngine.restoreAllPeriodicSyncs();
}
AccountAndUser[] accounts = mRunningAccounts;
@@ -2537,6 +2598,17 @@ public class SyncManager {
}
}
+ // On account add, check if there are any settings to be restored.
+ for (AccountAndUser aau : mRunningAccounts) {
+ if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
+ }
+ AccountSyncSettingsBackupHelper.accountAdded(mContext);
+ break;
+ }
+ }
+
List<SyncOperation> ops = getAllPendingSyncsFromCache();
for (SyncOperation op: ops) {
if (!containsAccountAndUser(accounts, op.target.account, op.target.userId)) {
@@ -2560,22 +2632,22 @@ public class SyncManager {
* @param flexMillis new flex time in milliseconds.
*/
private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
- long flexMillis) {
+ long flexMillis) {
if (!(pollFrequencyMillis == syncOperation.periodMillis
&& flexMillis == syncOperation.flexMillis)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "updating period " + syncOperation + " to " + pollFrequencyMillis
+ " and flex to " + flexMillis);
}
- removePeriodicSyncInternalH(syncOperation);
- syncOperation.periodMillis = pollFrequencyMillis;
- syncOperation.flexMillis = flexMillis;
- scheduleSyncOperationH(syncOperation);
+ SyncOperation newOp = new SyncOperation(syncOperation, pollFrequencyMillis,
+ flexMillis);
+ newOp.jobId = syncOperation.jobId;
+ scheduleSyncOperationH(newOp);
}
}
private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
- Bundle extras) {
+ Bundle extras) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
final long pollFrequencyMillis = pollFrequency * 1000L;
@@ -2614,9 +2686,8 @@ public class SyncManager {
SyncOperation op = new SyncOperation(target, syncAdapterInfo.uid,
syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
SyncStorageEngine.SOURCE_PERIODIC, extras,
- syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID);
- op.periodMillis = pollFrequencyMillis;
- op.flexMillis = flexMillis;
+ syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
+ pollFrequencyMillis, flexMillis);
scheduleSyncOperationH(op);
mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
@@ -2764,7 +2835,7 @@ public class SyncManager {
}
private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
- IBinder syncAdapter) {
+ IBinder syncAdapter) {
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
try {
activeSyncContext.mIsLinkedToDeath = true;
@@ -2816,14 +2887,23 @@ public class SyncManager {
* Should be called when a one-off instance of a periodic sync completes successfully.
*/
private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
- removeSyncOperationFromCache(syncOperation.sourcePeriodicId);
- getJobScheduler().cancel(syncOperation.sourcePeriodicId);
- SyncOperation periodic = syncOperation.createPeriodicSyncOperation();
- scheduleSyncOperationH(periodic);
+ // Ensure that the periodic sync wasn't removed.
+ SyncOperation periodicSync = null;
+ List<SyncOperation> ops = getAllPendingSyncsFromCache();
+ for (SyncOperation op: ops) {
+ if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
+ periodicSync = op;
+ break;
+ }
+ }
+ if (periodicSync == null) {
+ return;
+ }
+ scheduleSyncOperationH(periodicSync);
}
private void runSyncFinishedOrCanceledH(SyncResult syncResult,
- ActiveSyncContext activeSyncContext) {
+ ActiveSyncContext activeSyncContext) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
@@ -2957,7 +3037,7 @@ public class SyncManager {
}
private void installHandleTooManyDeletesNotification(Account account, String authority,
- long numDeletes, int userId) {
+ long numDeletes, int userId) {
if (mNotificationMgr == null) return;
final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
@@ -3033,7 +3113,7 @@ public class SyncManager {
}
public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
- int upstreamActivity, int downstreamActivity, long elapsedTime) {
+ int upstreamActivity, int downstreamActivity, long elapsedTime) {
EventLog.writeEvent(2720,
syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
@@ -3197,4 +3277,4 @@ public class SyncManager {
return mContext;
}
}
-}
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 4fb31c0cda9f..804be4ea1ae7 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -17,6 +17,7 @@
package com.android.server.content;
import android.accounts.Account;
+import android.app.job.JobInfo;
import android.content.pm.PackageManager;
import android.content.ContentResolver;
import android.os.Bundle;
@@ -79,9 +80,9 @@ public class SyncOperation {
public final String key;
/** Poll frequency of periodic sync in milliseconds */
- public long periodMillis;
+ public final long periodMillis;
/** Flex time of periodic sync in milliseconds */
- public long flexMillis;
+ public final long flexMillis;
/** Descriptive string key for this operation */
public String wakeLockName;
/**
@@ -90,6 +91,9 @@ public class SyncOperation {
*/
public long expectedRuntime;
+ /** Stores the number of times this sync operation failed and had to be retried. */
+ int retries;
+
/** jobId of the JobScheduler job corresponding to this sync */
public int jobId;
@@ -103,23 +107,32 @@ public class SyncOperation {
private SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
int reason, int source, Bundle extras, boolean allowParallelSyncs) {
this(info, owningUid, owningPackage, reason, source, extras, allowParallelSyncs, false,
- NO_JOB_ID);
+ NO_JOB_ID, 0, 0);
+ }
+
+ public SyncOperation(SyncOperation op, long periodMillis, long flexMillis) {
+ this(op.target, op.owningUid, op.owningPackage, op.reason, op.syncSource,
+ new Bundle(op.extras), op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId,
+ periodMillis, flexMillis);
}
public SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
int reason, int source, Bundle extras, boolean allowParallelSyncs,
- boolean isPeriodic, int sourcePeriodicId) {
+ boolean isPeriodic, int sourcePeriodicId, long periodMillis,
+ long flexMillis) {
this.target = info;
this.owningUid = owningUid;
this.owningPackage = owningPackage;
this.reason = reason;
this.syncSource = source;
this.extras = new Bundle(extras);
- cleanBundle(this.extras);
this.allowParallelSyncs = allowParallelSyncs;
this.isPeriodic = isPeriodic;
this.sourcePeriodicId = sourcePeriodicId;
- this.key = toKey(target, extras);
+ this.periodMillis = periodMillis;
+ this.flexMillis = flexMillis;
+ this.jobId = NO_JOB_ID;
+ this.key = toKey();
}
/* Get a one off sync operation instance from a periodic sync. */
@@ -128,18 +141,8 @@ public class SyncOperation {
return null;
}
SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
- new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */);
- // Copied to help us recreate the periodic sync from this one off sync.
- op.periodMillis = periodMillis;
- op.flexMillis = flexMillis;
- return op;
- }
-
- public SyncOperation createPeriodicSyncOperation() {
- SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
- new Bundle(extras), allowParallelSyncs, true, NO_JOB_ID);
- op.periodMillis = periodMillis;
- op.flexMillis = flexMillis;
+ new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */,
+ periodMillis, flexMillis);
return op;
}
@@ -224,6 +227,7 @@ public class SyncOperation {
jobInfoExtras.putLong("periodMillis", periodMillis);
jobInfoExtras.putLong("flexMillis", flexMillis);
jobInfoExtras.putLong("expectedRuntime", expectedRuntime);
+ jobInfoExtras.putInt("retries", retries);
return jobInfoExtras;
}
@@ -240,6 +244,7 @@ public class SyncOperation {
int initiatedBy;
Bundle extras;
boolean allowParallelSyncs, isPeriodic;
+ long periodMillis, flexMillis;
if (!jobExtras.getBoolean("SyncManagerJob", false)) {
return null;
@@ -256,6 +261,8 @@ public class SyncOperation {
allowParallelSyncs = jobExtras.getBoolean("allowParallelSyncs", false);
isPeriodic = jobExtras.getBoolean("isPeriodic", false);
initiatedBy = jobExtras.getInt("sourcePeriodicId", NO_JOB_ID);
+ periodMillis = jobExtras.getLong("periodMillis");
+ flexMillis = jobExtras.getLong("flexMillis");
extras = new Bundle();
PersistableBundle syncExtras = jobExtras.getPersistableBundle("syncExtras");
@@ -277,38 +284,14 @@ public class SyncOperation {
SyncStorageEngine.EndPoint target =
new SyncStorageEngine.EndPoint(account, provider, userId);
SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, source,
- extras, allowParallelSyncs, isPeriodic, initiatedBy);
+ extras, allowParallelSyncs, isPeriodic, initiatedBy, periodMillis, flexMillis);
op.jobId = jobExtras.getInt("jobId");
- op.periodMillis = jobExtras.getLong("periodMillis");
- op.flexMillis = jobExtras.getLong("flexMillis");
op.expectedRuntime = jobExtras.getLong("expectedRuntime");
+ op.retries = jobExtras.getInt("retries");
return op;
}
/**
- * Make sure the bundle attached to this SyncOperation doesn't have unnecessary
- * flags set.
- * @param bundle to clean.
- */
- private void cleanBundle(Bundle bundle) {
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_UPLOAD);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_MANUAL);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_EXPEDITED);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
- removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISALLOW_METERED);
- }
-
- private void removeFalseExtra(Bundle bundle, String extraName) {
- if (!bundle.getBoolean(extraName, false)) {
- bundle.remove(extraName);
- }
- }
-
- /**
* Determine whether if this sync operation is running, the provided operation would conflict
* with it.
* Parallel syncs allow multiple accounts to be synced at the same time.
@@ -326,28 +309,37 @@ public class SyncOperation {
return reason == REASON_PERIODIC;
}
+ boolean matchesPeriodicOperation(SyncOperation other) {
+ return target.matchesSpec(other.target)
+ && SyncManager.syncExtrasEquals(extras, other.extras, true)
+ && periodMillis == other.periodMillis && flexMillis == other.flexMillis;
+ }
+
boolean isDerivedFromFailedPeriodicSync() {
return sourcePeriodicId != NO_JOB_ID;
}
int findPriority() {
if (isInitialization()) {
- return 2;
+ return JobInfo.PRIORITY_SYNC_INITIALIZATION;
} else if (isExpedited()) {
- return 1;
+ return JobInfo.PRIORITY_SYNC_EXPEDITED;
}
- return 0;
+ return JobInfo.PRIORITY_DEFAULT;
}
- static String toKey(SyncStorageEngine.EndPoint info, Bundle extras) {
+ private String toKey() {
StringBuilder sb = new StringBuilder();
- sb.append("provider: ").append(info.provider);
- sb.append(" account {name=" + info.account.name
+ sb.append("provider: ").append(target.provider);
+ sb.append(" account {name=" + target.account.name
+ ", user="
- + info.userId
+ + target.userId
+ ", type="
- + info.account.type
+ + target.account.type
+ "}");
+ sb.append(" isPeriodic: ").append(isPeriodic);
+ sb.append(" period: ").append(periodMillis);
+ sb.append(" flex: ").append(flexMillis);
sb.append(" extras: ");
extrasToStringBuilder(extras, sb);
return sb.toString();
@@ -360,7 +352,9 @@ public class SyncOperation {
String dump(PackageManager pm, boolean useOneLine) {
StringBuilder sb = new StringBuilder();
- sb.append(target.account.name)
+ sb.append("JobId: ").append(jobId)
+ .append(", ")
+ .append(target.account.name)
.append(" u")
.append(target.userId).append(" (")
.append(target.account.type)
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index f8e3e48f8026..bc3fc6a47aef 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -438,9 +438,7 @@ public class SyncStorageEngine extends Handler {
if (sSyncStorageEngine != null) {
return;
}
- // This call will return the correct directory whether Encrypted File Systems is
- // enabled or not.
- File dataDir = Environment.getSecureDataDirectory();
+ File dataDir = Environment.getDataDirectory();
sSyncStorageEngine = new SyncStorageEngine(context, dataDir);
}
@@ -1492,6 +1490,9 @@ public class SyncStorageEngine extends Handler {
if (authority.ident > highestAuthorityId) {
highestAuthorityId = authority.ident;
}
+ } else {
+ EventLog.writeEvent(0x534e4554, "26513719", -1,
+ "Malformed authority");
}
} else if (XML_TAG_LISTEN_FOR_TICKLES.equals(tagName)) {
parseListenForTickles(parser);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1908f72dfd51..5c80d04da10e 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -60,22 +60,8 @@ 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;
- // If true, enables the use of the current time as an auto-brightness adjustment.
- // The basic idea here is to expand the dynamic range of auto-brightness
- // when it is especially dark outside. The light sensor tends to perform
- // poorly at low light levels so we compensate for it by making an
- // assumption about the environment.
- private static final boolean USE_TWILIGHT_ADJUSTMENT =
- PowerManager.useTwilightAdjustmentFeature();
-
// Specifies the maximum magnitude of the time of day adjustment.
- private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
-
- // The amount of time after or before sunrise over which to start adjusting
- // the gamma. We want the change to happen gradually so that it is below the
- // threshold of perceptibility and so that the adjustment has maximum effect
- // well after dusk.
- private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+ 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.
@@ -193,6 +179,8 @@ 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,
@@ -221,10 +209,6 @@ class AutomaticBrightnessController {
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
-
- if (USE_TWILIGHT_ADJUSTMENT) {
- mTwilight.registerListener(mTwilightListener, mHandler);
- }
}
public int getAutomaticScreenBrightness() {
@@ -235,7 +219,7 @@ class AutomaticBrightnessController {
}
public void configure(boolean enable, float adjustment, boolean dozing,
- boolean userInitiatedChange) {
+ boolean userInitiatedChange, boolean useTwilight) {
// 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
@@ -244,6 +228,7 @@ class AutomaticBrightnessController {
mDozing = dozing;
boolean changed = setLightSensorEnabled(enable && !dozing);
changed |= setScreenAutoBrightnessAdjustment(adjustment);
+ changed |= setUseTwilight(useTwilight);
if (changed) {
updateAutoBrightness(false /*sendUpdate*/);
}
@@ -252,6 +237,17 @@ 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:");
@@ -484,18 +480,13 @@ class AutomaticBrightnessController {
}
}
- if (USE_TWILIGHT_ADJUSTMENT) {
+ if (mUseTwilight) {
TwilightState state = mTwilight.getCurrentState();
if (state != null && state.isNight()) {
final long now = System.currentTimeMillis();
- final float earlyGamma =
- getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
- final float lateGamma =
- getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
- gamma *= earlyGamma * lateGamma;
+ gamma *= 1 + state.getAmount() * TWILIGHT_ADJUSTMENT_MAX_GAMMA;
if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
- + ", lateGamma=" + lateGamma);
+ Slog.d(TAG, "updateAutoBrightness: twilight amount=" + state.getAmount());
}
}
}
@@ -579,25 +570,6 @@ class AutomaticBrightnessController {
}
}
- private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
- if (lastSunset < 0 || nextSunrise < 0
- || now < lastSunset || now > nextSunrise) {
- return 1.0f;
- }
-
- if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
- return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
- (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
- return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
- (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
- }
-
private final class AutomaticBrightnessHandler extends Handler {
public AutomaticBrightnessHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b74b0f2e3caa..1ed7070d2586 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -615,7 +615,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
&& mPowerRequest.brightnessSetByUser;
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
- userInitiatedChange);
+ userInitiatedChange, mPowerRequest.useTwilight);
}
// Apply brightness boost.
@@ -840,7 +840,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// If there is already an animation in progress, don't interfere with it.
if (mColorFadeOnAnimator.isStarted()
|| mColorFadeOffAnimator.isStarted()) {
- return;
+ if (target != Display.STATE_ON) {
+ return;
+ }
+ // If display state changed to on, proceed and stop the color fade and turn screen on.
+ mPendingScreenOff = false;
}
// If we were in the process of turning off the screen but didn't quite
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 13e764828c34..5d81daeccc6b 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -62,6 +62,7 @@ import android.hardware.fingerprint.IFingerprintDaemon;
import android.hardware.fingerprint.IFingerprintDaemonCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
@@ -504,6 +505,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
public boolean hasEnrolledFingerprints(int userId) {
+ if (userId != UserHandle.getCallingUserId()) {
+ checkPermission(INTERACT_ACROSS_USERS);
+ }
return mFingerprintUtils.getFingerprintsForUser(mContext, userId).size() > 0;
}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index 62114cd0c5c8..7e19c66b1ad6 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -52,7 +52,7 @@ public class IntentFirewall {
static final String TAG = "IntentFirewall";
// e.g. /data/system/ifw or /data/secure/system/ifw
- private static final File RULES_DIR = new File(Environment.getSystemSecureDirectory(), "ifw");
+ private static final File RULES_DIR = new File(Environment.getDataSystemDirectory(), "ifw");
private static final int LOG_PACKAGES_MAX_LENGTH = 150;
private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 4c2699891893..bd888d809d78 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -19,6 +19,7 @@ package com.android.server.job;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -49,14 +50,17 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.os.Process;
-import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.app.ProcessStats;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
+import com.android.server.job.JobStore.JobStatusFunctor;
import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BatteryController;
import com.android.server.job.controllers.ConnectivityController;
@@ -66,6 +70,8 @@ import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
import com.android.server.job.controllers.TimeController;
+import libcore.util.EmptyArray;
+
/**
* Responsible for taking jobs representing work to be performed by a client app, and determining
* based on the criteria specified when that job should be run against the client application's
@@ -78,13 +84,20 @@ import com.android.server.job.controllers.TimeController;
* Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
* @hide
*/
-public class JobSchedulerService extends com.android.server.SystemService
+public final class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
- public static final boolean DEBUG = false;
- /** The number of concurrent jobs we run at one time. */
- private static final int MAX_JOB_CONTEXTS_COUNT
- = ActivityManager.isLowRamDeviceStatic() ? 3 : 6;
static final String TAG = "JobSchedulerService";
+ public static final boolean DEBUG = false;
+
+ /** The maximum number of concurrent jobs we run at one time. */
+ private static final int MAX_JOB_CONTEXTS_COUNT = 8;
+ /** Enforce a per-app limit on scheduled jobs? */
+ private static final boolean ENFORCE_MAX_JOBS = false;
+ /** The maximum number of jobs that we allow an unprivileged app to schedule */
+ private static final int MAX_JOBS_PER_APP = 100;
+
+ /** Global local for all job scheduler state. */
+ final Object mLock = new Object();
/** Master list of jobs. */
final JobStore mJobs;
@@ -134,7 +147,7 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
final ArrayList<JobStatus> mPendingJobs = new ArrayList<>();
- final ArrayList<Integer> mStartedUsers = new ArrayList<>();
+ int[] mStartedUsers = EmptyArray.INT;
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
@@ -154,11 +167,40 @@ public class JobSchedulerService extends com.android.server.SystemService
boolean mDeviceIdleMode;
/**
- * What we last reported to DeviceIdleController about wheter we are active.
+ * What we last reported to DeviceIdleController about whether we are active.
*/
boolean mReportedActive;
/**
+ * Current limit on the number of concurrent JobServiceContext entries we want to
+ * keep actively running a job.
+ */
+ int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+
+ /**
+ * Which uids are currently in the foreground.
+ */
+ final SparseIntArray mUidPriorityOverride = new SparseIntArray();
+
+ // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
+
+ /**
+ * This array essentially stores the state of mActiveServices array.
+ * The ith index stores the job present on the ith JobServiceContext.
+ * We manipulate this array until we arrive at what jobs should be running on
+ * what JobServiceContext.
+ */
+ JobStatus[] mTmpAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
+ /**
+ * Indicates whether we need to act on this jobContext id
+ */
+ boolean[] mTmpAssignAct = new boolean[MAX_JOB_CONTEXTS_COUNT];
+ /**
+ * The uid whose jobs we would like to assign to a context.
+ */
+ int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
+
+ /**
* Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
* still clean up. On reinstall the package will have a new uid.
*/
@@ -194,9 +236,11 @@ public class JobSchedulerService extends com.android.server.SystemService
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
+ updateUidState(uid, procState);
}
@Override public void onUidGone(int uid) throws RemoteException {
+ updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
}
@Override public void onUidActive(int uid) throws RemoteException {
@@ -207,16 +251,26 @@ public class JobSchedulerService extends com.android.server.SystemService
}
};
+ public Object getLock() {
+ return mLock;
+ }
+
@Override
public void onStartUser(int userHandle) {
- mStartedUsers.add(userHandle);
+ mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
+ // Let's kick any outstanding jobs for this user.
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
// Let's kick any outstanding jobs for this user.
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@Override
public void onStopUser(int userHandle) {
- mStartedUsers.remove(Integer.valueOf(userHandle));
+ mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
}
/**
@@ -227,14 +281,12 @@ public class JobSchedulerService extends com.android.server.SystemService
* @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
*/
public int schedule(JobInfo job, int uId) {
- return scheduleAsPackage(job, uId, null, -1);
+ return scheduleAsPackage(job, uId, null, -1, null);
}
- public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
- JobStatus jobStatus = new JobStatus(job, uId);
- if (packageName != null) {
- jobStatus.setSource(packageName, userId);
- }
+ public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId,
+ String tag) {
+ JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
try {
if (ActivityManagerNative.getDefault().getAppStartMode(uId,
job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
@@ -246,7 +298,16 @@ public class JobSchedulerService extends com.android.server.SystemService
}
if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
JobStatus toCancel;
- synchronized (mJobs) {
+ synchronized (mLock) {
+ // Jobs on behalf of others don't apply to the per-app job cap
+ if (ENFORCE_MAX_JOBS && packageName == null) {
+ if (mJobs.countJobsForUid(uId) > MAX_JOBS_PER_APP) {
+ Slog.w(TAG, "Too many jobs for uid " + uId);
+ throw new IllegalStateException("Apps may not schedule more than "
+ + MAX_JOBS_PER_APP + " distinct jobs");
+ }
+ }
+
toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
}
startTrackingJob(jobStatus, toCancel);
@@ -258,22 +319,20 @@ public class JobSchedulerService extends com.android.server.SystemService
}
public List<JobInfo> getPendingJobs(int uid) {
- ArrayList<JobInfo> outList = new ArrayList<JobInfo>();
- synchronized (mJobs) {
- ArraySet<JobStatus> jobs = mJobs.getJobs();
- for (int i=0; i<jobs.size(); i++) {
- JobStatus job = jobs.valueAt(i);
- if (job.getUid() == uid) {
- outList.add(job.getJob());
- }
+ synchronized (mLock) {
+ List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+ ArrayList<JobInfo> outList = new ArrayList<JobInfo>(jobs.size());
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.get(i);
+ outList.add(job.getJob());
}
+ return outList;
}
- return outList;
}
void cancelJobsForUser(int userHandle) {
List<JobStatus> jobsForUser;
- synchronized (mJobs) {
+ synchronized (mLock) {
jobsForUser = mJobs.getJobsByUser(userHandle);
}
for (int i=0; i<jobsForUser.size(); i++) {
@@ -292,7 +351,7 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
public void cancelJobsForUid(int uid, boolean forceAll) {
List<JobStatus> jobsForUid;
- synchronized (mJobs) {
+ synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(uid);
}
for (int i=0; i<jobsForUid.size(); i++) {
@@ -320,7 +379,7 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
public void cancelJob(int uid, int jobId) {
JobStatus toCancel;
- synchronized (mJobs) {
+ synchronized (mLock) {
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
}
if (toCancel != null) {
@@ -330,8 +389,8 @@ public class JobSchedulerService extends com.android.server.SystemService
private void cancelJobImpl(JobStatus cancelled) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
- stopTrackingJob(cancelled);
- synchronized (mJobs) {
+ stopTrackingJob(cancelled, true /* writeBack */);
+ synchronized (mLock) {
// Remove from pending queue.
mPendingJobs.remove(cancelled);
// Cancel if running.
@@ -340,10 +399,25 @@ public class JobSchedulerService extends com.android.server.SystemService
}
}
+ void updateUidState(int uid, int procState) {
+ synchronized (mLock) {
+ if (procState == ActivityManager.PROCESS_STATE_TOP) {
+ // Only use this if we are exactly the top app. All others can live
+ // with just the foreground priority. This means that persistent processes
+ // can never be the top app priority... that is fine.
+ mUidPriorityOverride.put(uid, JobInfo.PRIORITY_TOP_APP);
+ } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_APP);
+ } else {
+ mUidPriorityOverride.delete(uid);
+ }
+ }
+ }
+
void updateIdleMode(boolean enabled) {
boolean changed = false;
boolean rocking;
- synchronized (mJobs) {
+ synchronized (mLock) {
if (mDeviceIdleMode != enabled) {
changed = true;
}
@@ -355,7 +429,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mControllers.get(i).deviceIdleModeChanged(enabled);
}
}
- synchronized (mJobs) {
+ synchronized (mLock) {
mDeviceIdleMode = enabled;
if (enabled) {
// When becoming idle, make sure no jobs are actively running.
@@ -449,12 +523,13 @@ public class JobSchedulerService extends com.android.server.SystemService
mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
try {
ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
- ActivityManager.UID_OBSERVER_IDLE);
+ ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
+ | ActivityManager.UID_OBSERVER_IDLE);
} catch (RemoteException e) {
// ignored; both services live in system_server
}
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- synchronized (mJobs) {
+ synchronized (mLock) {
// Let's go!
mReadyToRock = true;
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
@@ -468,14 +543,16 @@ public class JobSchedulerService extends com.android.server.SystemService
getContext().getMainLooper()));
}
// Attach jobs to their controllers.
- ArraySet<JobStatus> jobs = mJobs.getJobs();
- for (int i=0; i<jobs.size(); i++) {
- JobStatus job = jobs.valueAt(i);
- for (int controller=0; controller<mControllers.size(); controller++) {
- mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
- mControllers.get(controller).maybeStartTrackingJob(job, null);
+ mJobs.forEachJob(new JobStatusFunctor() {
+ @Override
+ public void process(JobStatus job) {
+ for (int controller = 0; controller < mControllers.size(); controller++) {
+ final StateController sc = mControllers.get(controller);
+ sc.deviceIdleModeChanged(mDeviceIdleMode);
+ sc.maybeStartTrackingJobLocked(job, null);
+ }
}
- }
+ });
// GO GO GO!
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@@ -488,19 +565,16 @@ public class JobSchedulerService extends com.android.server.SystemService
* about.
*/
private void startTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
- boolean update;
- boolean rocking;
- synchronized (mJobs) {
- update = mJobs.add(jobStatus);
- rocking = mReadyToRock;
- }
- if (rocking) {
- for (int i=0; i<mControllers.size(); i++) {
- StateController controller = mControllers.get(i);
- if (update) {
- controller.maybeStopTrackingJob(jobStatus, true);
+ synchronized (mLock) {
+ final boolean update = mJobs.add(jobStatus);
+ if (mReadyToRock) {
+ for (int i = 0; i < mControllers.size(); i++) {
+ StateController controller = mControllers.get(i);
+ if (update) {
+ controller.maybeStopTrackingJobLocked(jobStatus, true);
+ }
+ controller.maybeStartTrackingJobLocked(jobStatus, lastJob);
}
- controller.maybeStartTrackingJob(jobStatus, lastJob);
}
}
}
@@ -509,21 +583,18 @@ public class JobSchedulerService extends com.android.server.SystemService
* Called when we want to remove a JobStatus object that we've finished executing. Returns the
* object removed.
*/
- private boolean stopTrackingJob(JobStatus jobStatus) {
- boolean removed;
- boolean rocking;
- synchronized (mJobs) {
+ private boolean stopTrackingJob(JobStatus jobStatus, boolean writeBack) {
+ synchronized (mLock) {
// Remove from store as well as controllers.
- removed = mJobs.remove(jobStatus);
- rocking = mReadyToRock;
- }
- if (removed && rocking) {
- for (int i=0; i<mControllers.size(); i++) {
- StateController controller = mControllers.get(i);
- controller.maybeStopTrackingJob(jobStatus, false);
+ final boolean removed = mJobs.remove(jobStatus, writeBack);
+ if (removed && mReadyToRock) {
+ for (int i=0; i<mControllers.size(); i++) {
+ StateController controller = mControllers.get(i);
+ controller.maybeStopTrackingJobLocked(jobStatus, false);
+ }
}
+ return removed;
}
- return removed;
}
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
@@ -645,7 +716,9 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
- if (!stopTrackingJob(jobStatus)) {
+ // Do not write back immediately if this is a periodic job. The job may get lost if system
+ // shuts down before it is added back.
+ if (!stopTrackingJob(jobStatus, !jobStatus.getJob().isPeriodic())) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
@@ -694,14 +767,14 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override
public void handleMessage(Message message) {
- synchronized (mJobs) {
+ synchronized (mLock) {
if (!mReadyToRock) {
return;
}
}
switch (message.what) {
case MSG_JOB_EXPIRED:
- synchronized (mJobs) {
+ synchronized (mLock) {
JobStatus runNow = (JobStatus) message.obj;
// runNow can be null, which is a controller's way of indicating that its
// state is such that all ready jobs should be run immediately.
@@ -713,7 +786,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
break;
case MSG_CHECK_JOB:
- synchronized (mJobs) {
+ synchronized (mLock) {
if (mReportedActive) {
// if jobs are currently being run, queue all ready jobs for execution.
queueReadyJobsForExecutionLockedH();
@@ -724,7 +797,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
break;
case MSG_CHECK_JOB_GREEDY:
- synchronized (mJobs) {
+ synchronized (mLock) {
queueReadyJobsForExecutionLockedH();
}
break;
@@ -742,32 +815,50 @@ public class JobSchedulerService extends com.android.server.SystemService
* as many as we can.
*/
private void queueReadyJobsForExecutionLockedH() {
- ArraySet<JobStatus> jobs = mJobs.getJobs();
- mPendingJobs.clear();
if (DEBUG) {
Slog.d(TAG, "queuing all ready jobs for execution:");
}
- for (int i=0; i<jobs.size(); i++) {
- JobStatus job = jobs.valueAt(i);
+ mPendingJobs.clear();
+ mJobs.forEachJob(mReadyQueueFunctor);
+ mReadyQueueFunctor.postProcess();
+
+ if (DEBUG) {
+ final int queuedJobs = mPendingJobs.size();
+ if (queuedJobs == 0) {
+ Slog.d(TAG, "No jobs pending.");
+ } else {
+ Slog.d(TAG, queuedJobs + " jobs queued.");
+ }
+ }
+ }
+
+ class ReadyJobQueueFunctor implements JobStatusFunctor {
+ ArrayList<JobStatus> newReadyJobs;
+
+ @Override
+ public void process(JobStatus job) {
if (isReadyToBeExecutedLocked(job)) {
if (DEBUG) {
Slog.d(TAG, " queued " + job.toShortString());
}
- mPendingJobs.add(job);
- } else if (areJobConstraintsNotSatisfied(job)) {
+ if (newReadyJobs == null) {
+ newReadyJobs = new ArrayList<JobStatus>();
+ }
+ newReadyJobs.add(job);
+ } else if (areJobConstraintsNotSatisfiedLocked(job)) {
stopJobOnServiceContextLocked(job,
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
}
}
- if (DEBUG) {
- final int queuedJobs = mPendingJobs.size();
- if (queuedJobs == 0) {
- Slog.d(TAG, "No jobs pending.");
- } else {
- Slog.d(TAG, queuedJobs + " jobs queued.");
+
+ public void postProcess() {
+ if (newReadyJobs != null) {
+ mPendingJobs.addAll(newReadyJobs);
}
+ newReadyJobs = null;
}
}
+ private final ReadyJobQueueFunctor mReadyQueueFunctor = new ReadyJobQueueFunctor();
/**
* The state of at least one job has changed. Here is where we could enforce various
@@ -778,18 +869,21 @@ public class JobSchedulerService extends com.android.server.SystemService
* If more than 4 jobs total are ready we send them all off.
* TODO: It would be nice to consolidate these sort of high-level policies somewhere.
*/
- private void maybeQueueReadyJobsForExecutionLockedH() {
- mPendingJobs.clear();
- int chargingCount = 0;
- int idleCount = 0;
- int backoffCount = 0;
- int connectivityCount = 0;
- int contentCount = 0;
- List<JobStatus> runnableJobs = null;
- ArraySet<JobStatus> jobs = mJobs.getJobs();
- if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
- for (int i=0; i<jobs.size(); i++) {
- JobStatus job = jobs.valueAt(i);
+ class MaybeReadyJobQueueFunctor implements JobStatusFunctor {
+ int chargingCount;
+ int idleCount;
+ int backoffCount;
+ int connectivityCount;
+ int contentCount;
+ List<JobStatus> runnableJobs;
+
+ public MaybeReadyJobQueueFunctor() {
+ reset();
+ }
+
+ // Functor method invoked for each job via JobStore.forEachJob()
+ @Override
+ public void process(JobStatus job) {
if (isReadyToBeExecutedLocked(job)) {
try {
if (ActivityManagerNative.getDefault().getAppStartMode(job.getUid(),
@@ -798,7 +892,7 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.w(TAG, "Aborting job " + job.getUid() + ":"
+ job.getJob().toString() + " -- package not allowed to start");
mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget();
- continue;
+ return;
}
} catch (RemoteException e) {
}
@@ -821,29 +915,51 @@ public class JobSchedulerService extends com.android.server.SystemService
runnableJobs = new ArrayList<>();
}
runnableJobs.add(job);
- } else if (areJobConstraintsNotSatisfied(job)) {
+ } else if (areJobConstraintsNotSatisfiedLocked(job)) {
stopJobOnServiceContextLocked(job,
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
}
}
- if (backoffCount > 0 ||
- idleCount >= MIN_IDLE_COUNT ||
- connectivityCount >= MIN_CONNECTIVITY_COUNT ||
- chargingCount >= MIN_CHARGING_COUNT ||
- contentCount >= MIN_CONTENT_COUNT ||
- (runnableJobs != null && runnableJobs.size() >= MIN_READY_JOBS_COUNT)) {
- if (DEBUG) {
- Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
- }
- for (int i=0; i<runnableJobs.size(); i++) {
- mPendingJobs.add(runnableJobs.get(i));
- }
- } else {
- if (DEBUG) {
- Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
+
+ public void postProcess() {
+ if (backoffCount > 0 ||
+ idleCount >= MIN_IDLE_COUNT ||
+ connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+ chargingCount >= MIN_CHARGING_COUNT ||
+ contentCount >= MIN_CONTENT_COUNT ||
+ (runnableJobs != null && runnableJobs.size() >= MIN_READY_JOBS_COUNT)) {
+ if (DEBUG) {
+ Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
+ }
+ mPendingJobs.addAll(runnableJobs);
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
+ }
}
+
+ // Be ready for next time
+ reset();
+ }
+
+ private void reset() {
+ chargingCount = 0;
+ idleCount = 0;
+ backoffCount = 0;
+ connectivityCount = 0;
+ contentCount = 0;
+ runnableJobs = null;
}
}
+ private final MaybeReadyJobQueueFunctor mMaybeQueueFunctor = new MaybeReadyJobQueueFunctor();
+
+ private void maybeQueueReadyJobsForExecutionLockedH() {
+ if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
+
+ mPendingJobs.clear();
+ mJobs.forEachJob(mMaybeQueueFunctor);
+ mMaybeQueueFunctor.postProcess();
+ }
/**
* Criteria for moving a job into the pending queue:
@@ -851,18 +967,31 @@ public class JobSchedulerService extends com.android.server.SystemService
* - It's not pending.
* - It's not already running on a JSC.
* - The user that requested the job is running.
+ * - The component is enabled and runnable.
*/
private boolean isReadyToBeExecutedLocked(JobStatus job) {
final boolean jobReady = job.isReady();
final boolean jobPending = mPendingJobs.contains(job);
final boolean jobActive = isCurrentlyActiveLocked(job);
- final boolean userRunning = mStartedUsers.contains(job.getUserId());
+
+ final int userId = job.getUserId();
+ final boolean userStarted = ArrayUtils.contains(mStartedUsers, userId);
+ final boolean componentPresent;
+ try {
+ componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
+ job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ userId) != null);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+
if (DEBUG) {
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+ " ready=" + jobReady + " pending=" + jobPending
- + " active=" + jobActive + " userRunning=" + userRunning);
+ + " active=" + jobActive + " userStarted=" + userStarted
+ + " componentPresent=" + componentPresent);
}
- return userRunning && jobReady && !jobPending && !jobActive;
+ return userStarted && componentPresent && jobReady && !jobPending && !jobActive;
}
/**
@@ -870,7 +999,7 @@ public class JobSchedulerService extends com.android.server.SystemService
* - It's not ready
* - It's running on a JSC.
*/
- private boolean areJobConstraintsNotSatisfied(JobStatus job) {
+ private boolean areJobConstraintsNotSatisfiedLocked(JobStatus job) {
return !job.isReady() && isCurrentlyActiveLocked(job);
}
@@ -880,7 +1009,7 @@ public class JobSchedulerService extends com.android.server.SystemService
* here is where we decide whether to actually execute it.
*/
private void maybeRunPendingJobsH() {
- synchronized (mJobs) {
+ synchronized (mLock) {
if (mDeviceIdleMode) {
// If device is idle, we will not schedule jobs to run.
return;
@@ -888,41 +1017,73 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
}
- assignJobsToContextsH();
+ assignJobsToContextsLocked();
reportActive();
}
}
}
+ private int evaluateJobPriorityLocked(JobStatus job) {
+ int priority = job.getPriority();
+ if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
+ return priority;
+ }
+ int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
+ if (override != 0) {
+ return override;
+ }
+ return priority;
+ }
+
/**
* Takes jobs from pending queue and runs them on available contexts.
* If no contexts are available, preempts lower priority jobs to
* run higher priority ones.
* Lock on mJobs before calling this function.
*/
- private void assignJobsToContextsH() {
+ private void assignJobsToContextsLocked() {
if (DEBUG) {
Slog.d(TAG, printPendingQueue());
}
- // This array essentially stores the state of mActiveServices array.
- // ith index stores the job present on the ith JobServiceContext.
- // We manipulate this array until we arrive at what jobs should be running on
- // what JobServiceContext.
- JobStatus[] contextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
- // Indicates whether we need to act on this jobContext id
- boolean[] act = new boolean[MAX_JOB_CONTEXTS_COUNT];
- int[] preferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
- for (int i=0; i<mActiveServices.size(); i++) {
- contextIdToJobMap[i] = mActiveServices.get(i).getRunningJob();
- preferredUidForContext[i] = mActiveServices.get(i).getPreferredUid();
+ int memLevel;
+ try {
+ memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel();
+ } catch (RemoteException e) {
+ memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ }
+ switch (memLevel) {
+ case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+ mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3;
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3;
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ mMaxActiveJobs = 1;
+ break;
+ default:
+ mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+ break;
+ }
+
+ JobStatus[] contextIdToJobMap = mTmpAssignContextIdToJobMap;
+ boolean[] act = mTmpAssignAct;
+ int[] preferredUidForContext = mTmpAssignPreferredUidForContext;
+ int numActive = 0;
+ for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
+ final JobServiceContext js = mActiveServices.get(i);
+ if ((contextIdToJobMap[i] = js.getRunningJob()) != null) {
+ numActive++;
+ }
+ act[i] = false;
+ preferredUidForContext[i] = js.getPreferredUid();
}
if (DEBUG) {
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
}
- Iterator<JobStatus> it = mPendingJobs.iterator();
- while (it.hasNext()) {
- JobStatus nextPending = it.next();
+ for (int i=0; i<mPendingJobs.size(); i++) {
+ JobStatus nextPending = mPendingJobs.get(i);
// If job is already running, go to next job.
int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
@@ -930,33 +1091,41 @@ public class JobSchedulerService extends com.android.server.SystemService
continue;
}
+ final int priority = evaluateJobPriorityLocked(nextPending);
+ nextPending.lastEvaluatedPriority = priority;
+
// Find a context for nextPending. The context should be available OR
// it should have lowest priority among all running jobs
// (sharing the same Uid as nextPending)
int minPriority = Integer.MAX_VALUE;
int minPriorityContextId = -1;
- for (int i=0; i<mActiveServices.size(); i++) {
- JobStatus job = contextIdToJobMap[i];
- int preferredUid = preferredUidForContext[i];
- if (job == null && (preferredUid == nextPending.getUid() ||
- preferredUid == JobServiceContext.NO_PREFERRED_UID) ) {
- minPriorityContextId = i;
- break;
- }
+ for (int j=0; j<MAX_JOB_CONTEXTS_COUNT; j++) {
+ JobStatus job = contextIdToJobMap[j];
+ int preferredUid = preferredUidForContext[j];
if (job == null) {
+ if ((numActive < mMaxActiveJobs || priority >= JobInfo.PRIORITY_TOP_APP) &&
+ (preferredUid == nextPending.getUid() ||
+ preferredUid == JobServiceContext.NO_PREFERRED_UID)) {
+ // This slot is free, and we haven't yet hit the limit on
+ // concurrent jobs... we can just throw the job in to here.
+ minPriorityContextId = j;
+ numActive++;
+ break;
+ }
// No job on this context, but nextPending can't run here because
- // the context has a preferred Uid.
+ // the context has a preferred Uid or we have reached the limit on
+ // concurrent jobs.
continue;
}
if (job.getUid() != nextPending.getUid()) {
continue;
}
- if (job.getPriority() >= nextPending.getPriority()) {
+ if (evaluateJobPriorityLocked(job) >= nextPending.lastEvaluatedPriority) {
continue;
}
- if (minPriority > nextPending.getPriority()) {
- minPriority = nextPending.getPriority();
- minPriorityContextId = i;
+ if (minPriority > nextPending.lastEvaluatedPriority) {
+ minPriority = nextPending.lastEvaluatedPriority;
+ minPriorityContextId = j;
}
}
if (minPriorityContextId != -1) {
@@ -967,7 +1136,7 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
}
- for (int i=0; i<mActiveServices.size(); i++) {
+ for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
boolean preservePreferredUid = false;
if (act[i]) {
JobStatus js = mActiveServices.get(i).getRunningJob();
@@ -979,18 +1148,18 @@ public class JobSchedulerService extends com.android.server.SystemService
mActiveServices.get(i).preemptExecutingJob();
preservePreferredUid = true;
} else {
+ final JobStatus pendingJob = contextIdToJobMap[i];
if (DEBUG) {
Slog.d(TAG, "About to run job on context "
- + String.valueOf(i) + ", job: " + contextIdToJobMap[i]);
+ + String.valueOf(i) + ", job: " + pendingJob);
}
for (int ic=0; ic<mControllers.size(); ic++) {
- StateController controller = mControllers.get(ic);
- controller.prepareForExecution(contextIdToJobMap[i]);
+ mControllers.get(ic).prepareForExecutionLocked(pendingJob);
}
- if (!mActiveServices.get(i).executeRunnableJob(contextIdToJobMap[i])) {
- Slog.d(TAG, "Error executing " + contextIdToJobMap[i]);
+ if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
+ Slog.d(TAG, "Error executing " + pendingJob);
}
- mPendingJobs.remove(contextIdToJobMap[i]);
+ mPendingJobs.remove(pendingJob);
}
}
if (!preservePreferredUid) {
@@ -1024,7 +1193,9 @@ public class JobSchedulerService extends com.android.server.SystemService
final IPackageManager pm = AppGlobals.getPackageManager();
final ComponentName service = job.getService();
try {
- ServiceInfo si = pm.getServiceInfo(service, 0, UserHandle.getUserId(uid));
+ ServiceInfo si = pm.getServiceInfo(service,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ UserHandle.getUserId(uid));
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
@@ -1088,19 +1259,29 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
- public int scheduleAsPackage(JobInfo job, String packageName, int userId)
+ public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag)
throws RemoteException {
+ final int callerUid = Binder.getCallingUid();
if (DEBUG) {
- Slog.d(TAG, "Scheduling job: " + job.toString() + " on behalf of " + packageName);
+ Slog.d(TAG, "Caller uid " + callerUid + " scheduling job: " + job.toString()
+ + " on behalf of " + packageName);
}
- final int uid = Binder.getCallingUid();
- if (uid != Process.SYSTEM_UID) {
- throw new IllegalArgumentException("Only system process is allowed"
- + "to set packageName");
+
+ if (packageName == null) {
+ throw new NullPointerException("Must specify a package for scheduleAsPackage()");
}
+
+ int mayScheduleForOthers = getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.UPDATE_DEVICE_STATS);
+ if (mayScheduleForOthers != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller uid " + callerUid
+ + " not permitted to schedule jobs for other apps");
+ }
+
long ident = Binder.clearCallingIdentity();
try {
- return JobSchedulerService.this.scheduleAsPackage(job, uid, packageName, userId);
+ return JobSchedulerService.this.scheduleAsPackage(job, callerUid,
+ packageName, userId, tag);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1183,64 +1364,86 @@ public class JobSchedulerService extends com.android.server.SystemService
return s.toString();
}
- void dumpInternal(PrintWriter pw) {
+ void dumpInternal(final PrintWriter pw) {
final long now = SystemClock.elapsedRealtime();
- synchronized (mJobs) {
- pw.print("Started users: ");
- for (int i=0; i<mStartedUsers.size(); i++) {
- pw.print("u" + mStartedUsers.get(i) + " ");
- }
- pw.println();
+ synchronized (mLock) {
+ pw.println("Started users: " + Arrays.toString(mStartedUsers));
pw.println("Registered jobs:");
if (mJobs.size() > 0) {
- ArraySet<JobStatus> jobs = mJobs.getJobs();
- for (int i=0; i<jobs.size(); i++) {
- JobStatus job = jobs.valueAt(i);
- pw.print(" Job #"); pw.print(i); pw.print(": ");
- pw.println(job.toShortString());
- job.dump(pw, " ");
- pw.print(" Ready: ");
- pw.print(mHandler.isReadyToBeExecutedLocked(job));
- pw.print(" (job=");
- pw.print(job.isReady());
- pw.print(" pending=");
- pw.print(mPendingJobs.contains(job));
- pw.print(" active=");
- pw.print(isCurrentlyActiveLocked(job));
- pw.print(" user=");
- pw.print(mStartedUsers.contains(job.getUserId()));
- pw.println(")");
- }
+ mJobs.forEachJob(new JobStatusFunctor() {
+ private int index = 0;
+
+ @Override
+ public void process(JobStatus job) {
+ pw.print(" Job #"); pw.print(index++); pw.print(": ");
+ pw.println(job.toShortString());
+ job.dump(pw, " ", true);
+ pw.print(" Ready: ");
+ pw.print(mHandler.isReadyToBeExecutedLocked(job));
+ pw.print(" (job=");
+ pw.print(job.isReady());
+ pw.print(" pending=");
+ pw.print(mPendingJobs.contains(job));
+ pw.print(" active=");
+ pw.print(isCurrentlyActiveLocked(job));
+ pw.print(" user=");
+ pw.print(ArrayUtils.contains(mStartedUsers, job.getUserId()));
+ pw.println(")");
+ }
+ });
} else {
pw.println(" None.");
}
for (int i=0; i<mControllers.size(); i++) {
pw.println();
- mControllers.get(i).dumpControllerState(pw);
+ mControllers.get(i).dumpControllerStateLocked(pw);
+ }
+ pw.println();
+ pw.println("Uid priority overrides:");
+ for (int i=0; i< mUidPriorityOverride.size(); i++) {
+ pw.print(" "); pw.print(UserHandle.formatUid(mUidPriorityOverride.keyAt(i)));
+ pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i));
}
pw.println();
- pw.println(printPendingQueue());
+ pw.println("Pending queue:");
+ for (int i=0; i<mPendingJobs.size(); i++) {
+ JobStatus job = mPendingJobs.get(i);
+ pw.print(" Pending #"); pw.print(i); pw.print(": ");
+ pw.println(job.toShortString());
+ job.dump(pw, " ", false);
+ int priority = evaluateJobPriorityLocked(job);
+ if (priority != JobInfo.PRIORITY_DEFAULT) {
+ pw.print(" Evaluated priority: "); pw.println(priority);
+ }
+ pw.print(" Tag: "); pw.println(job.getTag());
+ }
pw.println();
pw.println("Active jobs:");
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
+ pw.print(" Slot #"); pw.print(i); pw.print(": ");
if (jsc.getRunningJob() == null) {
+ pw.println("inactive");
continue;
} else {
- final long timeout = jsc.getTimeoutElapsed();
- pw.print("Running for: ");
- pw.print((now - jsc.getExecutionStartTimeElapsed())/1000);
- pw.print("s timeout=");
- pw.print(timeout);
- pw.print(" fromnow=");
- pw.println(timeout-now);
- jsc.getRunningJob().dump(pw, " ");
+ pw.println(jsc.getRunningJob().toShortString());
+ pw.print(" Running for: ");
+ TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw);
+ pw.print(", timeout at: ");
+ TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
+ pw.println();
+ jsc.getRunningJob().dump(pw, " ", false);
+ int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
+ if (priority != JobInfo.PRIORITY_DEFAULT) {
+ pw.print(" Evaluated priority: "); pw.println(priority);
+ }
}
}
pw.println();
pw.print("mReadyToRock="); pw.println(mReadyToRock);
pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode);
pw.print("mReportedActive="); pw.println(mReportedActive);
+ pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs);
}
pw.println();
}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index b249739811a6..4239248549ce 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -103,6 +103,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
private final JobCompletedListener mCompletedListener;
/** Used for service binding, etc. */
private final Context mContext;
+ private final Object mLock;
private final IBatteryStats mBatteryStats;
private PowerManager.WakeLock mWakeLock;
@@ -124,7 +125,6 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
private int mPreferredUid;
IJobService service;
- private final Object mLock = new Object();
/**
* Whether this context is free. This is set to false at the start of execution, and reset to
* true when execution is complete.
@@ -137,13 +137,14 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
private long mTimeoutElapsed;
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
- this(service.getContext(), batteryStats, service, looper);
+ this(service.getContext(), service.getLock(), batteryStats, service, looper);
}
@VisibleForTesting
- JobServiceContext(Context context, IBatteryStats batteryStats,
+ JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
JobCompletedListener completedListener, Looper looper) {
mContext = context;
+ mLock = lock;
mBatteryStats = batteryStats;
mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
@@ -203,7 +204,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
return false;
}
try {
- mBatteryStats.noteJobStart(job.getName(), job.getSourceUid());
+ mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
@@ -368,6 +369,13 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
}
break;
case MSG_CANCEL:
+ if (mVerb == VERB_FINISHED) {
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Trying to process cancel for torn-down context, ignoring.");
+ }
+ return;
+ }
mParams.setStopReason(message.arg1);
if (message.arg1 == JobParameters.REASON_PREEMPT) {
mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
@@ -477,12 +485,6 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* _ENDING -> No point in doing anything here, so we ignore.
*/
private void handleCancelH() {
- if (mRunningJob == null) {
- if (DEBUG) {
- Slog.d(TAG, "Trying to process cancel for torn-down context, ignoring.");
- }
- return;
- }
if (JobSchedulerService.DEBUG) {
Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
+ VERB_STRINGS[mVerb]);
@@ -510,7 +512,6 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
/** Process MSG_TIMEOUT here. */
private void handleOpTimeoutH() {
- mParams.setStopReason(JobParameters.REASON_TIMEOUT);
switch (mVerb) {
case VERB_BINDING:
Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
@@ -535,6 +536,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
// Not an error - client ran out of time.
Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
" sending onStop. " + mRunningJob.toShortString());
+ mParams.setStopReason(JobParameters.REASON_TIMEOUT);
sendStopMessageH();
break;
default:
@@ -579,7 +581,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
}
completedJob = mRunningJob;
try {
- mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getSourceUid());
+ mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
+ mRunningJob.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index f796164ef8ce..4268dab01a92 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -29,6 +29,7 @@ import android.util.AtomicFile;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -44,7 +45,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -69,7 +69,8 @@ public class JobStore {
/** Threshold to adjust how often we want to write to the db. */
private static final int MAX_OPS_BEFORE_WRITE = 1;
- final ArraySet<JobStatus> mJobSet;
+ final Object mLock;
+ final JobSet mJobSet; // per-caller-uid tracking
final Context mContext;
private int mDirtyOperations;
@@ -85,7 +86,7 @@ public class JobStore {
synchronized (sSingletonLock) {
if (sSingleton == null) {
sSingleton = new JobStore(jobManagerService.getContext(),
- Environment.getDataDirectory());
+ jobManagerService.getLock(), Environment.getDataDirectory());
}
return sSingleton;
}
@@ -96,7 +97,7 @@ public class JobStore {
*/
@VisibleForTesting
public static JobStore initAndGetForTesting(Context context, File dataDir) {
- JobStore jobStoreUnderTest = new JobStore(context, dataDir);
+ JobStore jobStoreUnderTest = new JobStore(context, new Object(), dataDir);
jobStoreUnderTest.clear();
return jobStoreUnderTest;
}
@@ -104,7 +105,8 @@ public class JobStore {
/**
* Construct the instance of the job store. This results in a blocking read from disk.
*/
- private JobStore(Context context, File dataDir) {
+ private JobStore(Context context, Object lock, File dataDir) {
+ mLock = lock;
mContext = context;
mDirtyOperations = 0;
@@ -113,7 +115,7 @@ public class JobStore {
jobDir.mkdirs();
mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
- mJobSet = new ArraySet<JobStatus>();
+ mJobSet = new JobSet();
readJobMapFromDisk(mJobSet);
}
@@ -136,19 +138,6 @@ public class JobStore {
return replaced;
}
- /**
- * Whether this jobStatus object already exists in the JobStore.
- */
- public boolean containsJobIdForUid(int jobId, int uId) {
- for (int i=mJobSet.size()-1; i>=0; i--) {
- JobStatus ts = mJobSet.valueAt(i);
- if (ts.getUid() == uId && ts.getJobId() == jobId) {
- return true;
- }
- }
- return false;
- }
-
boolean containsJob(JobStatus jobStatus) {
return mJobSet.contains(jobStatus);
}
@@ -157,11 +146,16 @@ public class JobStore {
return mJobSet.size();
}
+ public int countJobsForUid(int uid) {
+ return mJobSet.countJobsForUid(uid);
+ }
+
/**
* Remove the provided job. Will also delete the job if it was persisted.
+ * @param writeBack If true, the job will be deleted (if it was persisted) immediately.
* @return Whether or not the job existed to be removed.
*/
- public boolean remove(JobStatus jobStatus) {
+ public boolean remove(JobStatus jobStatus, boolean writeBack) {
boolean removed = mJobSet.remove(jobStatus);
if (!removed) {
if (DEBUG) {
@@ -169,7 +163,7 @@ public class JobStore {
}
return false;
}
- if (jobStatus.isPersisted()) {
+ if (writeBack && jobStatus.isPersisted()) {
maybeWriteStatusToDiskAsync();
}
return removed;
@@ -186,14 +180,7 @@ public class JobStore {
* @return A list of all the jobs scheduled by the provided user. Never null.
*/
public List<JobStatus> getJobsByUser(int userHandle) {
- List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
- for (int i=mJobSet.size()-1; i>=0; i--) {
- JobStatus ts = mJobSet.valueAt(i);
- if (UserHandle.getUserId(ts.getUid()) == userHandle) {
- matchingJobs.add(ts);
- }
- }
- return matchingJobs;
+ return mJobSet.getJobsByUser(userHandle);
}
/**
@@ -201,14 +188,7 @@ public class JobStore {
* @return All JobStatus objects for a given uid from the master list. Never null.
*/
public List<JobStatus> getJobsByUid(int uid) {
- List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
- for (int i=mJobSet.size()-1; i>=0; i--) {
- JobStatus ts = mJobSet.valueAt(i);
- if (ts.getUid() == uid) {
- matchingJobs.add(ts);
- }
- }
- return matchingJobs;
+ return mJobSet.getJobsByUid(uid);
}
/**
@@ -217,20 +197,21 @@ public class JobStore {
* @return the JobStatus that matches the provided uId and jobId, or null if none found.
*/
public JobStatus getJobByUidAndJobId(int uid, int jobId) {
- for (int i=mJobSet.size()-1; i>=0; i--) {
- JobStatus ts = mJobSet.valueAt(i);
- if (ts.getUid() == uid && ts.getJobId() == jobId) {
- return ts;
- }
- }
- return null;
+ return mJobSet.get(uid, jobId);
}
/**
- * @return The live array of JobStatus objects.
+ * Iterate over the set of all jobs, invoking the supplied functor on each. This is for
+ * customers who need to examine each job; we'd much rather not have to generate
+ * transient unified collections for them to iterate over and then discard, or creating
+ * iterators every time a client needs to perform a sweep.
*/
- public ArraySet<JobStatus> getJobs() {
- return mJobSet;
+ public void forEachJob(JobStatusFunctor functor) {
+ mJobSet.forEachJob(functor);
+ }
+
+ public interface JobStatusFunctor {
+ public void process(JobStatus jobStatus);
}
/** Version of the db schema. */
@@ -259,34 +240,31 @@ public class JobStore {
}
@VisibleForTesting
- public void readJobMapFromDisk(ArraySet<JobStatus> jobSet) {
+ public void readJobMapFromDisk(JobSet jobSet) {
new ReadJobMapFromDiskRunnable(jobSet).run();
}
/**
* Runnable that writes {@link #mJobSet} out to xml.
- * NOTE: This Runnable locks on JobStore.this
+ * NOTE: This Runnable locks on mLock
*/
private class WriteJobsMapToDiskRunnable implements Runnable {
@Override
public void run() {
final long startElapsed = SystemClock.elapsedRealtime();
- List<JobStatus> mStoreCopy = new ArrayList<JobStatus>();
- synchronized (JobStore.this) {
- // Copy over the jobs so we can release the lock before writing.
- for (int i=0; i<mJobSet.size(); i++) {
- JobStatus jobStatus = mJobSet.valueAt(i);
-
- if (!jobStatus.isPersisted()){
- continue;
+ final List<JobStatus> storeCopy = new ArrayList<JobStatus>();
+ synchronized (mLock) {
+ // Clone the jobs so we can release the lock before writing.
+ mJobSet.forEachJob(new JobStatusFunctor() {
+ @Override
+ public void process(JobStatus job) {
+ if (job.isPersisted()) {
+ storeCopy.add(new JobStatus(job));
+ }
}
-
- JobStatus copy = new JobStatus(jobStatus.getJob(), jobStatus.getUid(),
- jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
- mStoreCopy.add(copy);
- }
+ });
}
- writeJobsMapImpl(mStoreCopy);
+ writeJobsMapImpl(storeCopy);
if (JobSchedulerService.DEBUG) {
Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
- startElapsed) + "ms");
@@ -345,6 +323,9 @@ public class JobStore {
if (jobStatus.getSourcePackageName() != null) {
out.attribute(null, "sourcePackageName", jobStatus.getSourcePackageName());
}
+ if (jobStatus.getSourceTag() != null) {
+ out.attribute(null, "sourceTag", jobStatus.getSourceTag());
+ }
out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
@@ -439,13 +420,13 @@ public class JobStore {
* need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}.
*/
private class ReadJobMapFromDiskRunnable implements Runnable {
- private final ArraySet<JobStatus> jobSet;
+ private final JobSet jobSet;
/**
* @param jobSet Reference to the (empty) set of JobStatus objects that back the JobStore,
* so that after disk read we can populate it directly.
*/
- ReadJobMapFromDiskRunnable(ArraySet<JobStatus> jobSet) {
+ ReadJobMapFromDiskRunnable(JobSet jobSet) {
this.jobSet = jobSet;
}
@@ -454,7 +435,7 @@ public class JobStore {
try {
List<JobStatus> jobs;
FileInputStream fis = mJobsFile.openRead();
- synchronized (JobStore.this) {
+ synchronized (mLock) {
jobs = readJobMapImpl(fis);
if (jobs != null) {
for (int i=0; i<jobs.size(); i++) {
@@ -543,7 +524,7 @@ public class JobStore {
private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
IOException {
JobInfo.Builder jobBuilder;
- int uid, userId;
+ int uid, sourceUserId;
// Read out job identifier attributes and priority.
try {
@@ -556,7 +537,7 @@ public class JobStore {
jobBuilder.setPriority(Integer.valueOf(val));
}
val = parser.getAttributeValue(null, "sourceUserId");
- userId = val == null ? -1 : Integer.valueOf(val);
+ sourceUserId = val == null ? -1 : Integer.valueOf(val);
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing job's required fields, skipping");
return null;
@@ -564,6 +545,8 @@ public class JobStore {
final String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
+ final String sourceTag = parser.getAttributeValue(null, "sourceTag");
+
int eventType;
// Read out constraints tag.
do {
@@ -607,9 +590,9 @@ public class JobStore {
try {
String val = parser.getAttributeValue(null, "period");
final long periodMillis = Long.valueOf(val);
- jobBuilder.setPeriodic(periodMillis);
val = parser.getAttributeValue(null, "flex");
final long flexMillis = (val != null) ? Long.valueOf(val) : periodMillis;
+ jobBuilder.setPeriodic(periodMillis, flexMillis);
// As a sanity check, cap the recreated run time to be no later than flex+period
// from now. This is the latest the periodic could be pushed out. This could
// happen if the periodic ran early (at flex time before period), and then the
@@ -678,10 +661,8 @@ public class JobStore {
parser.nextTag(); // Consume </extras>
JobStatus js = new JobStatus(
- jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second);
- if (userId != -1) {
- js.setSource(sourcePackageName, userId);
- }
+ jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
+ elapsedRuntimes.first, elapsedRuntimes.second);
return js;
}
@@ -760,4 +741,122 @@ public class JobStore {
return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
}
}
+
+ static class JobSet {
+ // Key is the getUid() originator of the jobs in each sheaf
+ private SparseArray<ArraySet<JobStatus>> mJobs;
+
+ public JobSet() {
+ mJobs = new SparseArray<ArraySet<JobStatus>>();
+ }
+
+ public List<JobStatus> getJobsByUid(int uid) {
+ ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+ ArraySet<JobStatus> jobs = mJobs.get(uid);
+ if (jobs != null) {
+ matchingJobs.addAll(jobs);
+ }
+ return matchingJobs;
+ }
+
+ // By user, not by uid, so we need to traverse by key and check
+ public List<JobStatus> getJobsByUser(int userId) {
+ ArrayList<JobStatus> result = new ArrayList<JobStatus>();
+ for (int i = mJobs.size() - 1; i >= 0; i--) {
+ if (UserHandle.getUserId(mJobs.keyAt(i)) == userId) {
+ ArraySet<JobStatus> jobs = mJobs.get(i);
+ if (jobs != null) {
+ result.addAll(jobs);
+ }
+ }
+ }
+ return result;
+ }
+
+ public boolean add(JobStatus job) {
+ final int uid = job.getUid();
+ ArraySet<JobStatus> jobs = mJobs.get(uid);
+ if (jobs == null) {
+ jobs = new ArraySet<JobStatus>();
+ mJobs.put(uid, jobs);
+ }
+ return jobs.add(job);
+ }
+
+ public boolean remove(JobStatus job) {
+ final int uid = job.getUid();
+ ArraySet<JobStatus> jobs = mJobs.get(uid);
+ boolean didRemove = (jobs != null) ? jobs.remove(job) : false;
+ if (didRemove && jobs.size() == 0) {
+ // no more jobs for this uid; let the now-empty set object be GC'd.
+ mJobs.remove(uid);
+ }
+ return didRemove;
+ }
+
+ public boolean contains(JobStatus job) {
+ final int uid = job.getUid();
+ ArraySet<JobStatus> jobs = mJobs.get(uid);
+ return jobs != null && jobs.contains(job);
+ }
+
+ public JobStatus get(int uid, int jobId) {
+ ArraySet<JobStatus> jobs = mJobs.get(uid);
+ if (jobs != null) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.valueAt(i);
+ if (job.getJobId() == jobId) {
+ return job;
+ }
+ }
+ }
+ return null;
+ }
+
+ // Inefficient; use only for testing
+ public List<JobStatus> getAllJobs() {
+ ArrayList<JobStatus> allJobs = new ArrayList<JobStatus>(size());
+ for (int i = mJobs.size(); i >= 0; i--) {
+ allJobs.addAll(mJobs.valueAt(i));
+ }
+ return allJobs;
+ }
+
+ public void clear() {
+ mJobs.clear();
+ }
+
+ public int size() {
+ int total = 0;
+ for (int i = mJobs.size() - 1; i >= 0; i--) {
+ total += mJobs.valueAt(i).size();
+ }
+ return total;
+ }
+
+ // We only want to count the jobs that this uid has scheduled on its own
+ // behalf, not those that the app has scheduled on someone else's behalf.
+ public int countJobsForUid(int uid) {
+ int total = 0;
+ ArraySet<JobStatus> jobs = mJobs.get(uid);
+ if (jobs != null) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.valueAt(i);
+ if (job.getUid() == job.getSourceUid()) {
+ total++;
+ }
+ }
+ }
+ return total;
+ }
+
+ public void forEachJob(JobStatusFunctor functor) {
+ for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) {
+ ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex);
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ functor.process(jobs.valueAt(i));
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 5f3da7577a5d..f0c579f1ae98 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -48,59 +48,56 @@ public class AppIdleController extends StateController {
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
- sController = new AppIdleController(service, service.getContext());
+ sController = new AppIdleController(service, service.getContext(),
+ service.getLock());
}
return sController;
}
}
- private AppIdleController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private AppIdleController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
}
@Override
- public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.add(jobStatus);
- String packageName = jobStatus.getSourcePackageName();
- final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- jobStatus.getSourceUid(), jobStatus.getSourceUserId());
- if (DEBUG) {
- Slog.d(LOG_TAG, "Start tracking, setting idle state of "
- + packageName + " to " + appIdle);
- }
- jobStatus.appNotIdleConstraintSatisfied.set(!appIdle);
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ mTrackedTasks.add(jobStatus);
+ String packageName = jobStatus.getSourcePackageName();
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
+ jobStatus.getSourceUid(), jobStatus.getSourceUserId());
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Start tracking, setting idle state of "
+ + packageName + " to " + appIdle);
}
+ jobStatus.setAppNotIdleConstraintSatisfied(!appIdle);
}
@Override
- public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(jobStatus);
- }
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
+ mTrackedTasks.remove(jobStatus);
}
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("AppIdle");
pw.println("Parole On: " + mAppIdleParoleOn);
- synchronized (mTrackedTasks) {
- for (JobStatus task : mTrackedTasks) {
- pw.print(task.getSourcePackageName());
- pw.print(":idle=" + !task.appNotIdleConstraintSatisfied.get());
- pw.print(", ");
- }
- pw.println();
+ for (JobStatus task : mTrackedTasks) {
+ pw.print(task.getSourcePackageName());
+ pw.print(":idle="
+ + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
+ pw.print(", ");
}
+ pw.println();
}
void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
// Flag if any app's idle state has changed
boolean changed = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
if (mAppIdleParoleOn == isAppIdleParoleOn) {
return;
}
@@ -112,8 +109,7 @@ public class AppIdleController extends StateController {
if (DEBUG) {
Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
}
- if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
- task.appNotIdleConstraintSatisfied.set(!appIdle);
+ if (task.setAppNotIdleConstraintSatisfied(!appIdle)) {
changed = true;
}
}
@@ -128,19 +124,18 @@ public class AppIdleController extends StateController {
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
boolean changed = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
if (mAppIdleParoleOn) {
return;
}
for (JobStatus task : mTrackedTasks) {
if (task.getSourcePackageName().equals(packageName)
&& task.getSourceUserId() == userId) {
- if (task.appNotIdleConstraintSatisfied.get() != !idle) {
+ if (task.setAppNotIdleConstraintSatisfied(!idle)) {
if (DEBUG) {
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+ packageName + " to " + idle);
}
- task.appNotIdleConstraintSatisfied.set(!idle);
changed = true;
}
}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index b322a3e96c14..ac9f42520195 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -53,7 +53,7 @@ public class BatteryController extends StateController {
synchronized (sCreationLock) {
if (sController == null) {
sController = new BatteryController(taskManagerService,
- taskManagerService.getContext());
+ taskManagerService.getContext(), taskManagerService.getLock());
}
}
return sController;
@@ -67,32 +67,29 @@ public class BatteryController extends StateController {
@VisibleForTesting
public static BatteryController getForTesting(StateChangedListener stateChangedListener,
Context context) {
- return new BatteryController(stateChangedListener, context);
+ return new BatteryController(stateChangedListener, context, new Object());
}
- private BatteryController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private BatteryController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
mChargeTracker = new ChargingTracker();
mChargeTracker.startTracking();
}
@Override
- public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
final boolean isOnStablePower = mChargeTracker.isOnStablePower();
if (taskStatus.hasChargingConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.add(taskStatus);
- taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
- }
+ mTrackedTasks.add(taskStatus);
+ taskStatus.setChargingConstraintSatisfied(isOnStablePower);
}
}
@Override
- public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
if (taskStatus.hasChargingConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(taskStatus);
- }
+ mTrackedTasks.remove(taskStatus);
}
}
@@ -102,9 +99,9 @@ public class BatteryController extends StateController {
Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
}
boolean reportChange = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
for (JobStatus ts : mTrackedTasks) {
- boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
+ boolean previous = ts.setChargingConstraintSatisfied(stablePower);
if (previous != stablePower) {
reportChange = true;
}
@@ -197,18 +194,16 @@ public class BatteryController extends StateController {
}
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Batt.");
pw.println("Stable power: " + mChargeTracker.isOnStablePower());
- synchronized (mTrackedTasks) {
- Iterator<JobStatus> it = mTrackedTasks.iterator();
- if (it.hasNext()) {
- pw.print(String.valueOf(it.next().hashCode()));
- }
- while (it.hasNext()) {
- pw.print("," + String.valueOf(it.next().hashCode()));
- }
- pw.println();
+ Iterator<JobStatus> it = mTrackedTasks.iterator();
+ if (it.hasNext()) {
+ pw.print(String.valueOf(it.next().hashCode()));
+ }
+ while (it.hasNext()) {
+ pw.print("," + String.valueOf(it.next().hashCode()));
}
+ pw.println();
}
}
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index b84658a7db96..bd06645b2b16 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -58,14 +58,15 @@ public class ConnectivityController extends StateController implements
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
if (mSingleton == null) {
- mSingleton = new ConnectivityController(jms, jms.getContext());
+ mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
}
return mSingleton;
}
}
- private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private ConnectivityController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
// Register connectivity changed BR.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -82,22 +83,18 @@ public class ConnectivityController extends StateController implements
}
@Override
- public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
- synchronized (mTrackedJobs) {
- jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
- jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
- mTrackedJobs.add(jobStatus);
- }
+ jobStatus.setConnectivityConstraintSatisfied(mNetworkConnected);
+ jobStatus.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
+ mTrackedJobs.add(jobStatus);
}
}
@Override
- public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
- synchronized (mTrackedJobs) {
- mTrackedJobs.remove(jobStatus);
- }
+ mTrackedJobs.remove(jobStatus);
}
}
@@ -105,18 +102,14 @@ public class ConnectivityController extends StateController implements
* @param userId Id of the user for whom we are updating the connectivity state.
*/
private void updateTrackedJobs(int userId) {
- synchronized (mTrackedJobs) {
+ synchronized (mLock) {
boolean changed = false;
for (JobStatus js : mTrackedJobs) {
if (js.getUserId() != userId) {
continue;
}
- boolean prevIsConnected =
- js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
- boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
- if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
- changed = true;
- }
+ changed |= js.setConnectivityConstraintSatisfied(mNetworkConnected);
+ changed |= js.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -128,7 +121,7 @@ public class ConnectivityController extends StateController implements
* We know the network has just come up. We want to run any jobs that are ready.
*/
public synchronized void onNetworkActive() {
- synchronized (mTrackedJobs) {
+ synchronized (mLock) {
for (JobStatus js : mTrackedJobs) {
if (js.isReady()) {
if (DEBUG) {
@@ -188,7 +181,7 @@ public class ConnectivityController extends StateController implements
};
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Conn.");
pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
for (JobStatus js: mTrackedJobs) {
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index 212cc949364d..c5cf30f4739d 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -57,7 +57,7 @@ public class ContentObserverController extends StateController {
synchronized (sCreationLock) {
if (sController == null) {
sController = new ContentObserverController(taskManagerService,
- taskManagerService.getContext());
+ taskManagerService.getContext(), taskManagerService.getLock());
}
}
return sController;
@@ -66,95 +66,90 @@ public class ContentObserverController extends StateController {
@VisibleForTesting
public static ContentObserverController getForTesting(StateChangedListener stateChangedListener,
Context context) {
- return new ContentObserverController(stateChangedListener, context);
+ return new ContentObserverController(stateChangedListener, context, new Object());
}
- private ContentObserverController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private ContentObserverController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
}
@Override
- public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
- if (taskStatus.contentObserverJobInstance == null) {
- taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
- }
- mTrackedTasks.add(taskStatus);
- boolean havePendingUris = false;
- // If there is a previous job associated with the new job, propagate over
- // any pending content URI trigger reports.
- if (lastJob != null && lastJob.contentObserverJobInstance != null
- && lastJob.contentObserverJobInstance
- != taskStatus.contentObserverJobInstance
- && lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
- havePendingUris = true;
+ if (taskStatus.contentObserverJobInstance == null) {
+ taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
+ }
+ mTrackedTasks.add(taskStatus);
+ boolean havePendingUris = false;
+ // If there is a previous job associated with the new job, propagate over
+ // any pending content URI trigger reports.
+ if (lastJob != null && lastJob.contentObserverJobInstance != null
+ && lastJob.contentObserverJobInstance
+ != taskStatus.contentObserverJobInstance
+ && lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
+ havePendingUris = true;
+ taskStatus.contentObserverJobInstance.mChangedAuthorities
+ = lastJob.contentObserverJobInstance.mChangedAuthorities;
+ taskStatus.contentObserverJobInstance.mChangedUris
+ = lastJob.contentObserverJobInstance.mChangedUris;
+ lastJob.contentObserverJobInstance.mChangedAuthorities = null;
+ lastJob.contentObserverJobInstance.mChangedUris = null;
+ }
+ // If we have previously reported changed authorities/uris, then we failed
+ // to complete the job with them so will re-record them to report again.
+ if (taskStatus.changedAuthorities != null) {
+ havePendingUris = true;
+ if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
taskStatus.contentObserverJobInstance.mChangedAuthorities
- = lastJob.contentObserverJobInstance.mChangedAuthorities;
- taskStatus.contentObserverJobInstance.mChangedUris
- = lastJob.contentObserverJobInstance.mChangedUris;
- lastJob.contentObserverJobInstance.mChangedAuthorities = null;
- lastJob.contentObserverJobInstance.mChangedUris = null;
+ = new ArraySet<>();
}
- // If we have previously reported changed authorities/uris, then we failed
- // to complete the job with them so will re-record them to report again.
- if (taskStatus.changedAuthorities != null) {
- havePendingUris = true;
- if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
- taskStatus.contentObserverJobInstance.mChangedAuthorities
- = new ArraySet<>();
+ for (String auth : taskStatus.changedAuthorities) {
+ taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
+ }
+ if (taskStatus.changedUris != null) {
+ if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
+ taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
}
- for (String auth : taskStatus.changedAuthorities) {
- taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
+ for (Uri uri : taskStatus.changedUris) {
+ taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
}
- if (taskStatus.changedUris != null) {
- if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
- taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
- }
- for (Uri uri : taskStatus.changedUris) {
- taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
- }
- }
- taskStatus.changedAuthorities = null;
- taskStatus.changedUris = null;
}
taskStatus.changedAuthorities = null;
taskStatus.changedUris = null;
- taskStatus.contentTriggerConstraintSatisfied.set(havePendingUris);
}
+ taskStatus.changedAuthorities = null;
+ taskStatus.changedUris = null;
+ taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
}
}
@Override
- public void prepareForExecution(JobStatus taskStatus) {
+ public void prepareForExecutionLocked(JobStatus taskStatus) {
if (taskStatus.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
- if (taskStatus.contentObserverJobInstance != null) {
- taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
- taskStatus.changedAuthorities
- = taskStatus.contentObserverJobInstance.mChangedAuthorities;
- taskStatus.contentObserverJobInstance.mChangedUris = null;
- taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
- }
+ if (taskStatus.contentObserverJobInstance != null) {
+ taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
+ taskStatus.changedAuthorities
+ = taskStatus.contentObserverJobInstance.mChangedAuthorities;
+ taskStatus.contentObserverJobInstance.mChangedUris = null;
+ taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
}
}
}
@Override
- public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
if (taskStatus.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
- if (!forUpdate) {
- // We won't do this reset if being called for an update, because
- // we know it will be immediately followed by maybeStartTrackingJob...
- // and we don't want to lose any content changes in-between.
- if (taskStatus.contentObserverJobInstance != null) {
- taskStatus.contentObserverJobInstance.detach();
- taskStatus.contentObserverJobInstance = null;
- }
+ if (!forUpdate) {
+ // We won't do this reset if being called for an update, because
+ // we know it will be immediately followed by maybeStartTrackingJobLocked...
+ // and we don't want to lose any content changes in-between.
+ if (taskStatus.contentObserverJobInstance != null) {
+ taskStatus.contentObserverJobInstance.detach();
+ taskStatus.contentObserverJobInstance = null;
}
- mTrackedTasks.remove(taskStatus);
}
+ mTrackedTasks.remove(taskStatus);
}
}
@@ -162,7 +157,7 @@ public class ContentObserverController extends StateController {
public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
if (failureToReschedule.hasContentTriggerConstraint()
&& newJob.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
// Our job has failed, and we are scheduling a new job for it.
// Copy the last reported content changes in to the new job, so when
// we schedule the new one we will pick them up and report them again.
@@ -184,7 +179,7 @@ public class ContentObserverController extends StateController {
@Override
public void onChange(boolean selfChange, Uri uri) {
boolean reportChange = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
final int N = mJobs.size();
for (int i=0; i<N; i++) {
JobInstance inst = mJobs.get(i);
@@ -198,9 +193,7 @@ public class ContentObserverController extends StateController {
inst.mChangedAuthorities = new ArraySet<>();
}
inst.mChangedAuthorities.add(uri.getAuthority());
- boolean previous
- = inst.mJobStatus.contentTriggerConstraintSatisfied.getAndSet(true);
- if (!previous) {
+ if (inst.mJobStatus.setContentTriggerConstraintSatisfied(true)) {
reportChange = true;
}
}
@@ -254,50 +247,48 @@ public class ContentObserverController extends StateController {
}
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Content.");
- synchronized (mTrackedTasks) {
- Iterator<JobStatus> it = mTrackedTasks.iterator();
- if (it.hasNext()) {
- pw.print(String.valueOf(it.next().hashCode()));
- }
- while (it.hasNext()) {
- pw.print("," + String.valueOf(it.next().hashCode()));
- }
- pw.println();
- int N = mObservers.size();
- if (N > 0) {
- pw.println("URIs:");
- for (int i = 0; i < N; i++) {
- ObserverInstance obs = mObservers.valueAt(i);
- pw.print(" ");
- pw.print(mObservers.keyAt(i));
- pw.println(":");
- pw.print(" ");
- pw.println(obs);
- pw.println(" Jobs:");
- int M = obs.mJobs.size();
- for (int j=0; j<M; j++) {
- JobInstance inst = obs.mJobs.get(j);
- pw.print(" ");
- pw.print(inst.hashCode());
- if (inst.mChangedAuthorities != null) {
- pw.println(":");
- pw.println(" Changed Authorities:");
- for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
+ Iterator<JobStatus> it = mTrackedTasks.iterator();
+ if (it.hasNext()) {
+ pw.print(String.valueOf(it.next().hashCode()));
+ }
+ while (it.hasNext()) {
+ pw.print("," + String.valueOf(it.next().hashCode()));
+ }
+ pw.println();
+ int N = mObservers.size();
+ if (N > 0) {
+ pw.println("URIs:");
+ for (int i = 0; i < N; i++) {
+ ObserverInstance obs = mObservers.valueAt(i);
+ pw.print(" ");
+ pw.print(mObservers.keyAt(i));
+ pw.println(":");
+ pw.print(" ");
+ pw.println(obs);
+ pw.println(" Jobs:");
+ int M = obs.mJobs.size();
+ for (int j=0; j<M; j++) {
+ JobInstance inst = obs.mJobs.get(j);
+ pw.print(" ");
+ pw.print(inst.hashCode());
+ if (inst.mChangedAuthorities != null) {
+ pw.println(":");
+ pw.println(" Changed Authorities:");
+ for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
+ pw.print(" ");
+ pw.println(inst.mChangedAuthorities.valueAt(k));
+ }
+ if (inst.mChangedUris != null) {
+ pw.println(" Changed URIs:");
+ for (int k = 0; k<inst.mChangedUris.size(); k++) {
pw.print(" ");
- pw.println(inst.mChangedAuthorities.valueAt(k));
- }
- if (inst.mChangedUris != null) {
- pw.println(" Changed URIs:");
- for (int k = 0; k<inst.mChangedUris.size(); k++) {
- pw.print(" ");
- pw.println(inst.mChangedUris.valueAt(k));
- }
+ pw.println(inst.mChangedUris.valueAt(k));
}
- } else {
- pw.println();
}
+ } else {
+ pw.println();
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 9f4cdef0e5f7..7638494eccb2 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -51,14 +51,15 @@ public class IdleController extends StateController {
public static IdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
- sController = new IdleController(service, service.getContext());
+ sController = new IdleController(service, service.getContext(), service.getLock());
}
return sController;
}
}
- private IdleController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private IdleController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
initIdleStateTracking();
}
@@ -66,29 +67,25 @@ public class IdleController extends StateController {
* StateController interface
*/
@Override
- public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasIdleConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.add(taskStatus);
- taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
- }
+ mTrackedTasks.add(taskStatus);
+ taskStatus.setIdleConstraintSatisfied(mIdleTracker.isIdle());
}
}
@Override
- public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(taskStatus);
- }
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
+ mTrackedTasks.remove(taskStatus);
}
/**
* Interaction with the task manager service
*/
void reportNewIdleState(boolean isIdle) {
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
for (JobStatus task : mTrackedTasks) {
- task.idleConstraintSatisfied.set(isIdle);
+ task.setIdleConstraintSatisfied(isIdle);
}
}
mStateChangedListener.onControllerStateChanged();
@@ -193,17 +190,15 @@ public class IdleController extends StateController {
}
@Override
- public void dumpControllerState(PrintWriter pw) {
- synchronized (mTrackedTasks) {
- pw.print("Idle: ");
- pw.println(mIdleTracker.isIdle() ? "true" : "false");
- pw.println(mTrackedTasks.size());
- for (int i = 0; i < mTrackedTasks.size(); i++) {
- final JobStatus js = mTrackedTasks.get(i);
- pw.print(" ");
- pw.print(String.valueOf(js.hashCode()).substring(0, 3));
- pw.println("..");
- }
+ public void dumpControllerStateLocked(PrintWriter pw) {
+ pw.print("Idle: ");
+ pw.println(mIdleTracker.isIdle() ? "true" : "false");
+ pw.println(mTrackedTasks.size());
+ for (int i = 0; i < mTrackedTasks.size(); i++) {
+ final JobStatus js = mTrackedTasks.get(i);
+ pw.print(" ");
+ pw.print(String.valueOf(js.hashCode()).substring(0, 3));
+ pw.println("..");
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index e749433b1e3f..98bf8a9a8d08 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -42,91 +42,143 @@ import java.util.concurrent.atomic.AtomicBoolean;
* but we don't enforce that so this is safer.
* @hide
*/
-public class JobStatus {
+public final class JobStatus {
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
+ static final int CONSTRAINT_CHARGING = 1<<0;
+ static final int CONSTRAINT_TIMING_DELAY = 1<<1;
+ static final int CONSTRAINT_DEADLINE = 1<<2;
+ static final int CONSTRAINT_IDLE = 1<<3;
+ static final int CONSTRAINT_UNMETERED = 1<<4;
+ static final int CONSTRAINT_CONNECTIVITY = 1<<5;
+ static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
+ static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
+
final JobInfo job;
/** Uid of the package requesting this job. */
- final int uId;
- final String name;
+ final int callingUid;
+ final String batteryName;
+
+ final String sourcePackageName;
+ final int sourceUserId;
+ final int sourceUid;
+ final String sourceTag;
+
final String tag;
- String sourcePackageName;
- int sourceUserId = -1;
- int sourceUid = -1;
+ /**
+ * Earliest point in the future at which this job will be eligible to run. A value of 0
+ * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
+ */
+ private final long earliestRunTimeElapsedMillis;
+ /**
+ * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
+ * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
+ */
+ private final long latestRunTimeElapsedMillis;
+
+ /** How many times this job has failed, used to compute back-off. */
+ private final int numFailures;
// Constraints.
- final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean appNotIdleConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean contentTriggerConstraintSatisfied = new AtomicBoolean();
+ final int requiredConstraints;
+ int satisfiedConstraints = 0;
// These are filled in by controllers when preparing for execution.
public ArraySet<Uri> changedUris;
public ArraySet<String> changedAuthorities;
+ public int lastEvaluatedPriority;
+
/**
* For use only by ContentObserverController: state it is maintaining about content URIs
* being observed.
*/
ContentObserverController.JobInstance contentObserverJobInstance;
- /**
- * Earliest point in the future at which this job will be eligible to run. A value of 0
- * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
- */
- private long earliestRunTimeElapsedMillis;
- /**
- * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
- * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
- */
- private long latestRunTimeElapsedMillis;
- /** How many times this job has failed, used to compute back-off. */
- private final int numFailures;
-
/** Provide a handle to the service that this job will be run on. */
public int getServiceToken() {
- return uId;
+ return callingUid;
}
- private JobStatus(JobInfo job, int uId, int numFailures) {
+ private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
+ int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
+ long latestRunTimeElapsedMillis) {
this.job = job;
- this.uId = uId;
- this.sourceUid = uId;
- this.name = job.getService().flattenToShortString();
- this.tag = "*job*/" + this.name;
+ this.callingUid = callingUid;
+
+ int tempSourceUid = -1;
+ if (sourceUserId != -1 && sourcePackageName != null) {
+ try {
+ tempSourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
+ sourceUserId);
+ } catch (RemoteException ex) {
+ // Can't happen, PackageManager runs in the same process.
+ }
+ }
+ if (tempSourceUid == -1) {
+ this.sourceUid = callingUid;
+ this.sourceUserId = UserHandle.getUserId(callingUid);
+ this.sourcePackageName = job.getService().getPackageName();
+ this.sourceTag = null;
+ } else {
+ this.sourceUid = tempSourceUid;
+ this.sourceUserId = sourceUserId;
+ this.sourcePackageName = sourcePackageName;
+ this.sourceTag = tag;
+ }
+
+ if (this.sourceTag != null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(job.getService().getPackageName());
+ sb.append('/');
+ sb.append(this.sourceTag);
+ if (sourcePackageName != null) {
+ sb.append('/');
+ sb.append(this.sourcePackageName);
+ }
+ this.batteryName = sb.toString();
+ } else {
+ this.batteryName = job.getService().flattenToShortString();
+ }
+ this.tag = "*job*/" + this.batteryName;
+
+ this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
+ this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
+
+ int requiredConstraints = 0;
+ if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
+ requiredConstraints |= CONSTRAINT_CONNECTIVITY;
+ }
+ if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
+ requiredConstraints |= CONSTRAINT_UNMETERED;
+ }
+ if (job.isRequireCharging()) {
+ requiredConstraints |= CONSTRAINT_CHARGING;
+ }
+ if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
+ requiredConstraints |= CONSTRAINT_TIMING_DELAY;
+ }
+ if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
+ requiredConstraints |= CONSTRAINT_DEADLINE;
+ }
+ if (job.isRequireDeviceIdle()) {
+ requiredConstraints |= CONSTRAINT_IDLE;
+ }
+ if (job.getTriggerContentUris() != null) {
+ requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
+ }
+ this.requiredConstraints = requiredConstraints;
}
/** Copy constructor. */
public JobStatus(JobStatus jobStatus) {
- this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
- this.sourceUserId = jobStatus.sourceUserId;
- this.sourcePackageName = jobStatus.sourcePackageName;
- this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
- this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
- }
-
- /** Create a newly scheduled job. */
- public JobStatus(JobInfo job, int uId) {
- this(job, uId, 0);
-
- final long elapsedNow = SystemClock.elapsedRealtime();
-
- if (job.isPeriodic()) {
- latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
- earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
- } else {
- earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
- elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
- latestRunTimeElapsedMillis = job.hasLateConstraint() ?
- elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
- }
+ this(jobStatus.getJob(), jobStatus.getUid(),
+ jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
+ jobStatus.getSourceTag(), jobStatus.getNumFailures(),
+ jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
}
/**
@@ -136,23 +188,43 @@ public class JobStatus {
* wallclock runtime rather than resetting it on every boot.
* We consider a freshly loaded job to no longer be in back-off.
*/
- public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis,
- long latestRunTimeElapsedMillis) {
- this(job, uId, 0);
-
- this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
- this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
+ public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
+ String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+ this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
}
/** Create a new job to be rescheduled with the provided parameters. */
public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt) {
- this(rescheduling.job, rescheduling.getUid(), backoffAttempt);
- this.sourceUserId = rescheduling.sourceUserId;
- this.sourcePackageName = rescheduling.sourcePackageName;
+ this(rescheduling.job, rescheduling.getUid(),
+ rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
+ rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
+ newLatestRuntimeElapsedMillis);
+ }
- earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
- latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
+ /**
+ * Create a newly scheduled job.
+ * @param callingUid Uid of the package that scheduled this job.
+ * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
+ * the calling package is the source.
+ * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
+ */
+ public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
+ int sourceUserId, String tag) {
+ final long elapsedNow = SystemClock.elapsedRealtime();
+ final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
+ if (job.isPeriodic()) {
+ latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
+ earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
+ } else {
+ earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
+ elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
+ latestRunTimeElapsedMillis = job.hasLateConstraint() ?
+ elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
+ }
+ return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
}
public JobInfo getJob() {
@@ -172,7 +244,7 @@ public class JobStatus {
}
public String getSourcePackageName() {
- return sourcePackageName != null ? sourcePackageName : job.getService().getPackageName();
+ return sourcePackageName;
}
public int getSourceUid() {
@@ -180,22 +252,23 @@ public class JobStatus {
}
public int getSourceUserId() {
- if (sourceUserId == -1) {
- sourceUserId = getUserId();
- }
return sourceUserId;
}
public int getUserId() {
- return UserHandle.getUserId(uId);
+ return UserHandle.getUserId(callingUid);
+ }
+
+ public String getSourceTag() {
+ return sourceTag;
}
public int getUid() {
- return uId;
+ return callingUid;
}
- public String getName() {
- return name;
+ public String getBatteryName() {
+ return batteryName;
}
public String getTag() {
@@ -211,31 +284,31 @@ public class JobStatus {
}
public boolean hasConnectivityConstraint() {
- return job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY;
+ return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
}
public boolean hasUnmeteredConstraint() {
- return job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED;
+ return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
}
public boolean hasChargingConstraint() {
- return job.isRequireCharging();
+ return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
}
public boolean hasTimingDelayConstraint() {
- return earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME;
+ return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
}
public boolean hasDeadlineConstraint() {
- return latestRunTimeElapsedMillis != NO_LATEST_RUNTIME;
+ return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
}
public boolean hasIdleConstraint() {
- return job.isRequireDeviceIdle();
+ return (requiredConstraints&CONSTRAINT_IDLE) != 0;
}
public boolean hasContentTriggerConstraint() {
- return job.getTriggerContentUris() != null;
+ return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
}
public boolean isPersisted() {
@@ -250,35 +323,78 @@ public class JobStatus {
return latestRunTimeElapsedMillis;
}
+ boolean setChargingConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
+ }
+
+ boolean setTimingDelayConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
+ }
+
+ boolean setDeadlineConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
+ }
+
+ boolean setIdleConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_IDLE, state);
+ }
+
+ boolean setUnmeteredConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
+ }
+
+ boolean setConnectivityConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
+ }
+
+ boolean setAppNotIdleConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
+ }
+
+ boolean setContentTriggerConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
+ }
+
+ boolean setConstraintSatisfied(int constraint, boolean state) {
+ boolean old = (satisfiedConstraints&constraint) != 0;
+ if (old == state) {
+ return false;
+ }
+ satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
+ return true;
+ }
+
/**
* @return Whether or not this job is ready to run, based on its requirements. This is true if
* the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
*/
- public synchronized boolean isReady() {
+ public boolean isReady() {
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
// (is an implementation detail. A periodic job should only run if it's constraints are
// satisfied).
// AppNotIdle implicit constraint trumps all!
return (isConstraintsSatisfied()
- || (!job.isPeriodic()
- && hasDeadlineConstraint() && deadlineConstraintSatisfied.get()))
- && appNotIdleConstraintSatisfied.get();
+ || (!job.isPeriodic()
+ && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
+ && (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
}
+ static final int CONSTRAINTS_OF_INTEREST =
+ CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
+ CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
+ CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
+
/**
* @return Whether the constraints set on this job are satisfied.
*/
- public synchronized boolean isConstraintsSatisfied() {
- return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
- && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
- && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
- && (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
- && (!hasIdleConstraint() || idleConstraintSatisfied.get())
- && (!hasContentTriggerConstraint() || contentTriggerConstraintSatisfied.get());
+ public boolean isConstraintsSatisfied() {
+ final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
+ final int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+ return (sat & req) == req;
}
public boolean matches(int uid, int jobId) {
- return this.job.getId() == jobId && this.uId == uid;
+ return this.job.getId() == jobId && this.callingUid == uid;
}
@Override
@@ -293,7 +409,7 @@ public class JobStatus {
+ ",I=" + job.isRequireDeviceIdle()
+ ",U=" + (job.getTriggerContentUris() != null)
+ ",F=" + numFailures + ",P=" + job.isPersisted()
- + ",ANI=" + appNotIdleConstraintSatisfied.get()
+ + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
+ (isReady() ? "(READY)" : "")
+ "]";
}
@@ -312,22 +428,6 @@ public class JobStatus {
}
}
- public void setSource(String sourcePackageName, int sourceUserId) {
- this.sourcePackageName = sourcePackageName;
- this.sourceUserId = sourceUserId;
- try {
- sourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
- sourceUserId);
- } catch (RemoteException ex) {
- // Can't happen, PackageManager runs in the same process.
- }
- if (sourceUid == -1) {
- sourceUid = uId;
- this.sourceUserId = getUserId();
- this.sourcePackageName = null;
- }
- }
-
/**
* Convenience function to identify a job uniquely without pulling all the data that
* {@link #toString()} returns.
@@ -337,109 +437,105 @@ public class JobStatus {
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" jId=");
sb.append(job.getId());
- sb.append(" uid=");
- UserHandle.formatUid(sb, uId);
sb.append(' ');
- sb.append(job.getService().flattenToShortString());
+ UserHandle.formatUid(sb, callingUid);
+ sb.append(' ');
+ sb.append(batteryName);
return sb.toString();
}
+ void dumpConstraints(PrintWriter pw, int constraints) {
+ if ((constraints&CONSTRAINT_CHARGING) != 0) {
+ pw.print(" CHARGING");
+ }
+ if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
+ pw.print(" TIMING_DELAY");
+ }
+ if ((constraints&CONSTRAINT_DEADLINE) != 0) {
+ pw.print(" DEADLINE");
+ }
+ if ((constraints&CONSTRAINT_IDLE) != 0) {
+ pw.print(" IDLE");
+ }
+ if ((constraints&CONSTRAINT_UNMETERED) != 0) {
+ pw.print(" UNMETERED");
+ }
+ if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
+ pw.print(" CONNECTIVITY");
+ }
+ if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
+ pw.print(" APP_NOT_IDLE");
+ }
+ if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
+ pw.print(" CONTENT_TRIGGER");
+ }
+ }
+
// Dumpsys infrastructure
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); UserHandle.formatUid(pw, uId);
+ public void dump(PrintWriter pw, String prefix, boolean full) {
+ pw.print(prefix); UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
pw.print(prefix);
pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
pw.print(" user="); pw.print(getSourceUserId());
pw.print(" pkg="); pw.println(getSourcePackageName());
- pw.print(prefix); pw.println("JobInfo:");
- pw.print(prefix); pw.print(" Service: ");
- pw.println(job.getService().flattenToShortString());
- if (job.isPeriodic()) {
- pw.print(prefix); pw.print(" PERIODIC: interval=");
- TimeUtils.formatDuration(job.getIntervalMillis(), pw);
- pw.print(" flex=");
- TimeUtils.formatDuration(job.getFlexMillis(), pw);
- pw.println();
- }
- if (job.isPersisted()) {
- pw.print(prefix); pw.println(" PERSISTED");
- }
- if (job.getPriority() != 0) {
- pw.print(prefix); pw.print(" Priority: ");
- pw.println(job.getPriority());
- }
- pw.print(prefix); pw.print(" Requires: charging=");
- pw.print(job.isRequireCharging());
- pw.print(" deviceIdle=");
- pw.println(job.isRequireDeviceIdle());
- if (job.getTriggerContentUris() != null) {
- pw.print(prefix); pw.println(" Trigger content URIs:");
- for (int i=0; i<job.getTriggerContentUris().length; i++) {
- JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
- pw.print(prefix); pw.print(" ");
- pw.print(Integer.toHexString(trig.getFlags()));
- pw.print(' ' );
- pw.println(trig.getUri());
+ if (full) {
+ pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix);
+ pw.print(" Service: "); pw.println(job.getService().flattenToShortString());
+ if (job.isPeriodic()) {
+ pw.print(prefix); pw.print(" PERIODIC: interval=");
+ TimeUtils.formatDuration(job.getIntervalMillis(), pw);
+ pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw);
+ pw.println();
}
- }
- if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
- pw.print(prefix); pw.print(" Network type: ");
- pw.println(job.getNetworkType());
- }
- if (job.getMinLatencyMillis() != 0) {
- pw.print(prefix); pw.print(" Minimum latency: ");
- TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
- pw.println();
- }
- if (job.getMaxExecutionDelayMillis() != 0) {
- pw.print(prefix); pw.print(" Max execution delay: ");
- TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
+ if (job.isPersisted()) {
+ pw.print(prefix); pw.println(" PERSISTED");
+ }
+ if (job.getPriority() != 0) {
+ pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
+ }
+ pw.print(prefix); pw.print(" Requires: charging=");
+ pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
+ pw.println(job.isRequireDeviceIdle());
+ if (job.getTriggerContentUris() != null) {
+ pw.print(prefix); pw.println(" Trigger content URIs:");
+ for (int i = 0; i < job.getTriggerContentUris().length; i++) {
+ JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i];
+ pw.print(prefix); pw.print(" ");
+ pw.print(Integer.toHexString(trig.getFlags()));
+ pw.print(' '); pw.println(trig.getUri());
+ }
+ }
+ if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
+ pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
+ }
+ if (job.getMinLatencyMillis() != 0) {
+ pw.print(prefix); pw.print(" Minimum latency: ");
+ TimeUtils.formatDuration(job.getMinLatencyMillis(), pw);
+ pw.println();
+ }
+ if (job.getMaxExecutionDelayMillis() != 0) {
+ pw.print(prefix); pw.print(" Max execution delay: ");
+ TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw);
+ pw.println();
+ }
+ pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy());
+ pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
pw.println();
+ if (job.hasEarlyConstraint()) {
+ pw.print(prefix); pw.println(" Has early constraint");
+ }
+ if (job.hasLateConstraint()) {
+ pw.print(prefix); pw.println(" Has late constraint");
+ }
}
- pw.print(prefix); pw.print(" Backoff: policy=");
- pw.print(job.getBackoffPolicy());
- pw.print(" initial=");
- TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw);
+ pw.print(prefix); pw.print("Required constraints:");
+ dumpConstraints(pw, requiredConstraints);
pw.println();
- if (job.hasEarlyConstraint()) {
- pw.print(prefix); pw.println(" Has early constraint");
- }
- if (job.hasLateConstraint()) {
- pw.print(prefix); pw.println(" Has late constraint");
- }
- pw.print(prefix); pw.println("Constraints:");
- if (hasChargingConstraint()) {
- pw.print(prefix); pw.print(" Charging: ");
- pw.println(chargingConstraintSatisfied.get());
- }
- if (hasTimingDelayConstraint()) {
- pw.print(prefix); pw.print(" Time delay: ");
- pw.println(timeDelayConstraintSatisfied.get());
- }
- if (hasDeadlineConstraint()) {
- pw.print(prefix); pw.print(" Deadline: ");
- pw.println(deadlineConstraintSatisfied.get());
- }
- if (hasIdleConstraint()) {
- pw.print(prefix); pw.print(" System idle: ");
- pw.println(idleConstraintSatisfied.get());
- }
- if (hasUnmeteredConstraint()) {
- pw.print(prefix); pw.print(" Unmetered: ");
- pw.println(unmeteredConstraintSatisfied.get());
- }
- if (hasConnectivityConstraint()) {
- pw.print(prefix); pw.print(" Connectivity: ");
- pw.println(connectivityConstraintSatisfied.get());
- }
- if (hasIdleConstraint()) {
- pw.print(prefix); pw.print(" App not idle: ");
- pw.println(appNotIdleConstraintSatisfied.get());
- }
- if (hasContentTriggerConstraint()) {
- pw.print(prefix); pw.print(" Content trigger: ");
- pw.println(contentTriggerConstraintSatisfied.get());
+ if (full) {
+ pw.print(prefix); pw.print("Satisfied constraints:");
+ dumpConstraints(pw, satisfiedConstraints);
+ pw.println();
}
if (changedAuthorities != null) {
pw.print(prefix); pw.println("Changed authorities:");
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index b619ea8cdd5d..7882bc4d86ab 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -30,13 +30,16 @@ import java.io.PrintWriter;
*/
public abstract class StateController {
protected static final boolean DEBUG = JobSchedulerService.DEBUG;
- protected Context mContext;
- protected StateChangedListener mStateChangedListener;
+ protected final Context mContext;
+ protected final Object mLock;
+ protected final StateChangedListener mStateChangedListener;
protected boolean mDeviceIdleMode;
- public StateController(StateChangedListener stateChangedListener, Context context) {
+ public StateController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
mStateChangedListener = stateChangedListener;
mContext = context;
+ mLock = lock;
}
public void deviceIdleModeChanged(boolean enabled) {
@@ -49,21 +52,21 @@ public abstract class StateController {
* Also called when updating a task, so implementing controllers have to be aware of
* preexisting tasks.
*/
- public abstract void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob);
+ public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);
/**
* Optionally implement logic here to prepare the job to be executed.
*/
- public void prepareForExecution(JobStatus jobStatus) {
+ public void prepareForExecutionLocked(JobStatus jobStatus) {
}
/**
* Remove task - this will happen if the task is cancelled, completed, etc.
*/
- public abstract void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate);
+ public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate);
/**
* Called when a new job is being created to reschedule an old failed job.
*/
public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
}
- public abstract void dumpControllerState(PrintWriter pw);
+ public abstract void dumpControllerStateLocked(PrintWriter pw);
}
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index a68c3adabb08..620800caaf67 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -54,13 +54,14 @@ public class TimeController extends StateController {
public static synchronized TimeController get(JobSchedulerService jms) {
if (mSingleton == null) {
- mSingleton = new TimeController(jms, jms.getContext());
+ mSingleton = new TimeController(jms, jms.getContext(), jms.getLock());
}
return mSingleton;
}
- private TimeController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private TimeController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
@@ -71,9 +72,9 @@ public class TimeController extends StateController {
* list.
*/
@Override
- public synchronized void maybeStartTrackingJob(JobStatus job, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
- maybeStopTrackingJob(job, false);
+ maybeStopTrackingJobLocked(job, false);
boolean isInsert = false;
ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
while (it.hasPrevious()) {
@@ -84,12 +85,11 @@ public class TimeController extends StateController {
break;
}
}
- if(isInsert)
- {
+ if (isInsert) {
it.next();
}
it.add(job);
- maybeUpdateAlarms(
+ maybeUpdateAlarmsLocked(
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
}
@@ -101,7 +101,7 @@ public class TimeController extends StateController {
* Really an == comparison should be enough, but why play with fate? We'll do <=.
*/
@Override
- public synchronized void maybeStopTrackingJob(JobStatus job, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus job, boolean forUpdate) {
if (mTrackedJobs.remove(job)) {
checkExpiredDelaysAndResetAlarm();
checkExpiredDeadlinesAndResetAlarm();
@@ -114,14 +114,14 @@ public class TimeController extends StateController {
* the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
* back and forth.
*/
- private boolean canStopTrackingJob(JobStatus job) {
+ private boolean canStopTrackingJobLocked(JobStatus job) {
return (!job.hasTimingDelayConstraint() ||
- job.timeDelayConstraintSatisfied.get()) &&
+ (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
(!job.hasDeadlineConstraint() ||
- job.deadlineConstraintSatisfied.get());
+ (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
}
- private void ensureAlarmService() {
+ private void ensureAlarmServiceLocked() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
}
@@ -131,71 +131,75 @@ public class TimeController extends StateController {
* Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
* if so, removing them from this list, and updating the alarm for the next expiry time.
*/
- private synchronized void checkExpiredDeadlinesAndResetAlarm() {
- long nextExpiryTime = Long.MAX_VALUE;
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ private void checkExpiredDeadlinesAndResetAlarm() {
+ synchronized (mLock) {
+ long nextExpiryTime = Long.MAX_VALUE;
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
- Iterator<JobStatus> it = mTrackedJobs.iterator();
- while (it.hasNext()) {
- JobStatus job = it.next();
- if (!job.hasDeadlineConstraint()) {
- continue;
- }
- final long jobDeadline = job.getLatestRunTimeElapsed();
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
+ while (it.hasNext()) {
+ JobStatus job = it.next();
+ if (!job.hasDeadlineConstraint()) {
+ continue;
+ }
+ final long jobDeadline = job.getLatestRunTimeElapsed();
- if (jobDeadline <= nowElapsedMillis) {
- job.deadlineConstraintSatisfied.set(true);
- mStateChangedListener.onRunJobNow(job);
- it.remove();
- } else { // Sorted by expiry time, so take the next one and stop.
- nextExpiryTime = jobDeadline;
- break;
+ if (jobDeadline <= nowElapsedMillis) {
+ job.setDeadlineConstraintSatisfied(true);
+ mStateChangedListener.onRunJobNow(job);
+ it.remove();
+ } else { // Sorted by expiry time, so take the next one and stop.
+ nextExpiryTime = jobDeadline;
+ break;
+ }
}
+ setDeadlineExpiredAlarmLocked(nextExpiryTime);
}
- setDeadlineExpiredAlarm(nextExpiryTime);
}
/**
* Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
* tracked jobs and marks them as ready as appropriate.
*/
- private synchronized void checkExpiredDelaysAndResetAlarm() {
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
- long nextDelayTime = Long.MAX_VALUE;
- boolean ready = false;
- Iterator<JobStatus> it = mTrackedJobs.iterator();
- while (it.hasNext()) {
- final JobStatus job = it.next();
- if (!job.hasTimingDelayConstraint()) {
- continue;
- }
- final long jobDelayTime = job.getEarliestRunTime();
- if (jobDelayTime <= nowElapsedMillis) {
- job.timeDelayConstraintSatisfied.set(true);
- if (canStopTrackingJob(job)) {
- it.remove();
- }
- if (job.isReady()) {
- ready = true;
+ private void checkExpiredDelaysAndResetAlarm() {
+ synchronized (mLock) {
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ long nextDelayTime = Long.MAX_VALUE;
+ boolean ready = false;
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
+ while (it.hasNext()) {
+ final JobStatus job = it.next();
+ if (!job.hasTimingDelayConstraint()) {
+ continue;
}
- } else { // Keep going through list to get next delay time.
- if (nextDelayTime > jobDelayTime) {
- nextDelayTime = jobDelayTime;
+ final long jobDelayTime = job.getEarliestRunTime();
+ if (jobDelayTime <= nowElapsedMillis) {
+ job.setTimingDelayConstraintSatisfied(true);
+ if (canStopTrackingJobLocked(job)) {
+ it.remove();
+ }
+ if (job.isReady()) {
+ ready = true;
+ }
+ } else { // Keep going through list to get next delay time.
+ if (nextDelayTime > jobDelayTime) {
+ nextDelayTime = jobDelayTime;
+ }
}
}
+ if (ready) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ setDelayExpiredAlarmLocked(nextDelayTime);
}
- if (ready) {
- mStateChangedListener.onControllerStateChanged();
- }
- setDelayExpiredAlarm(nextDelayTime);
}
- private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
+ private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed) {
if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
- setDelayExpiredAlarm(delayExpiredElapsed);
+ setDelayExpiredAlarmLocked(delayExpiredElapsed);
}
if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
- setDeadlineExpiredAlarm(deadlineExpiredElapsed);
+ setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed);
}
}
@@ -204,10 +208,11 @@ public class TimeController extends StateController {
* delay will expire.
* This alarm <b>will</b> wake up the phone.
*/
- private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
+ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithListener(DELAY_TAG, mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis);
+ updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
+ mNextDelayExpiredElapsedMillis);
}
/**
@@ -215,10 +220,11 @@ public class TimeController extends StateController {
* deadline will expire.
* This alarm <b>will</b> wake up the phone.
*/
- private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
+ private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithListener(DEADLINE_TAG, mDeadlineExpiredListener, mNextJobExpiredElapsedMillis);
+ updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
+ mNextJobExpiredElapsedMillis);
}
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
@@ -229,9 +235,9 @@ public class TimeController extends StateController {
return proposedAlarmTimeElapsedMillis;
}
- private void updateAlarmWithListener(String tag, OnAlarmListener listener,
+ private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
long alarmTimeElapsed) {
- ensureAlarmService();
+ ensureAlarmServiceLocked();
if (alarmTimeElapsed == Long.MAX_VALUE) {
mAlarmService.cancel(listener);
} else {
@@ -266,7 +272,7 @@ public class TimeController extends StateController {
};
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
final long nowElapsed = SystemClock.elapsedRealtime();
pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
pw.println(
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ffc52b31a7d5..ed68abe4a9a8 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -508,18 +508,18 @@ public class GnssLocationProvider implements LocationProviderInterface {
};
private void subscriptionOrSimChanged(Context context) {
- Log.d(TAG, "received SIM related action: ");
+ if (DEBUG) Log.d(TAG, "received SIM related action: ");
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
String mccMnc = phone.getSimOperator();
if (!TextUtils.isEmpty(mccMnc)) {
- Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
+ if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
synchronized (mLock) {
reloadGpsProperties(context, mProperties);
mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
}
} else {
- Log.d(TAG, "SIM MCC/MNC is still not available");
+ if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
}
}
@@ -569,7 +569,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
}
private void reloadGpsProperties(Context context, Properties properties) {
- Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
+ if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
loadPropertiesFromResource(context, properties);
boolean isPropertiesLoadedFromFile = false;
final String gpsHardware = SystemProperties.get("ro.hardware.gps");
@@ -582,7 +582,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
if (!isPropertiesLoadedFromFile) {
loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
}
- Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
+ if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
@@ -603,7 +603,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
properties.store(baos, null);
native_configuration_update(baos.toString());
- Log.d(TAG, "final config = " + baos.toString());
+ if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
} catch (IOException ex) {
Log.e(TAG, "failed to dump properties contents");
}
@@ -628,7 +628,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
String[] configValues = context.getResources().getStringArray(
com.android.internal.R.array.config_gpsParameters);
for (String item : configValues) {
- Log.d(TAG, "GpsParamsResource: " + item);
+ if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
// We need to support "KEY =", but not "=VALUE".
String[] split = item.split("=");
if (split.length == 2) {
@@ -917,11 +917,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
long certainty = mNtpTime.getCacheCertainty();
long now = System.currentTimeMillis();
- Log.d(TAG, "NTP server returned: "
- + time + " (" + new Date(time)
- + ") reference: " + timeReference
- + " certainty: " + certainty
- + " system time offset: " + (time - now));
+ if (DEBUG) {
+ Log.d(TAG, "NTP server returned: "
+ + time + " (" + new Date(time)
+ + ") reference: " + timeReference
+ + " certainty: " + certainty
+ + " system time offset: " + (time - now));
+ }
native_inject_time(time, timeReference, (int) certainty);
delay = NTP_INTERVAL;
@@ -1557,15 +1559,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
* called from native code to update SV info
*/
private void reportSvStatus() {
- int svCount = native_read_sv_status(mPrnWithFlags, mSnrs, mSvElevations, mSvAzimuths,
- mConstellationTypes);
+ int svCount = native_read_sv_status(mSvidWithFlags, mSnrs, mSvElevations, mSvAzimuths);
mListenerHelper.onSvStatusChanged(
svCount,
- mPrnWithFlags,
+ mSvidWithFlags,
mSnrs,
mSvElevations,
- mSvAzimuths,
- mConstellationTypes);
+ mSvAzimuths);
if (VERBOSE) {
Log.v(TAG, "SV count: " + svCount);
@@ -1573,19 +1573,19 @@ public class GnssLocationProvider implements LocationProviderInterface {
// Calculate number of sets used in fix.
int usedInFixCount = 0;
for (int i = 0; i < svCount; i++) {
- if ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+ if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
++usedInFixCount;
}
if (VERBOSE) {
- Log.v(TAG, "prn: " + (mPrnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH) +
+ Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
" snr: " + mSnrs[i]/10 +
" elev: " + mSvElevations[i] +
" azimuth: " + mSvAzimuths[i] +
- ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
+ ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
? " " : " E") +
- ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
+ ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
? " " : " A") +
- ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
+ ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
? "" : "U"));
}
}
@@ -1635,7 +1635,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
break;
default:
- Log.d(TAG, "Received Unknown AGPS status: " + status);
+ if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
}
}
@@ -1686,25 +1686,25 @@ public class GnssLocationProvider implements LocationProviderInterface {
/**
* Called from native code to inform us the hardware information.
*/
- private void setGpsYearOfHardware(int yearOfHardware) {
- if (DEBUG) Log.d(TAG, "setGpsYearOfHardware called with " + yearOfHardware);
+ private void setGnssYearOfHardware(int yearOfHardware) {
+ if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
mYearOfHardware = yearOfHardware;
}
- public interface GpsSystemInfoProvider {
+ public interface GnssSystemInfoProvider {
/**
* Returns the year of GPS hardware.
*/
- int getGpsYearOfHardware();
+ int getGnssYearOfHardware();
}
/**
* @hide
*/
- public GpsSystemInfoProvider getGpsSystemInfoProvider() {
- return new GpsSystemInfoProvider() {
+ public GnssSystemInfoProvider getGnssSystemInfoProvider() {
+ return new GnssSystemInfoProvider() {
@Override
- public int getGpsYearOfHardware() {
+ public int getGnssYearOfHardware() {
return mYearOfHardware;
}
};
@@ -2398,14 +2398,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
}
// for GPS SV statistics
- private static final int MAX_SVS = 512;
+ private static final int MAX_SVS = 64;
// preallocated arrays, to avoid memory allocation in reportStatus()
- private int mPrnWithFlags[] = new int[MAX_SVS];
+ private int mSvidWithFlags[] = new int[MAX_SVS];
private float mSnrs[] = new float[MAX_SVS];
private float mSvElevations[] = new float[MAX_SVS];
private float mSvAzimuths[] = new float[MAX_SVS];
- private int mConstellationTypes[] = new int[MAX_SVS];
private int mSvCount;
// preallocated to avoid memory allocation in reportNmea()
private byte[] mNmeaBuffer = new byte[120];
@@ -2426,7 +2425,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
// returns number of SVs
// mask[0] is ephemeris mask and mask[1] is almanac mask
private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
- float[] azimuths, int[] constellationTypes);
+ float[] azimuths);
private native int native_read_nmea(byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 9840c61ec516..0b3111cd726c 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -77,8 +77,7 @@ abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatus
final int[] prnWithFlags,
final float[] snrs,
final float[] elevations,
- final float[] azimuths,
- final int[] constellationTypes) {
+ final float[] azimuths) {
Operation operation = new Operation() {
@Override
public void execute(IGnssStatusListener listener) throws RemoteException {
@@ -87,8 +86,7 @@ abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatus
prnWithFlags,
snrs,
elevations,
- azimuths,
- constellationTypes);
+ azimuths);
}
};
foreach(operation);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 246da2e10de5..29c54e9bf78c 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -77,6 +77,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
*/
private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
+ private static final int UID_NOT_SET = -1;
+
private final MessageHandler mHandler;
private final int mOwnerPid;
@@ -122,6 +124,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private boolean mIsActive = false;
private boolean mDestroyed = false;
+ private int mCallingUid = UID_NOT_SET;
+ private String mCallingPackage;
+
public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
mOwnerPid = ownerPid;
@@ -419,7 +424,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
return mSessionCb.mCb;
}
- public void sendMediaButton(KeyEvent ke, int sequenceId, ResultReceiver cb) {
+ public void sendMediaButton(KeyEvent ke, int sequenceId,
+ ResultReceiver cb, int uid, String packageName) {
+ updateCallingPackage(uid, packageName);
mSessionCb.sendMediaButton(ke, sequenceId, cb);
}
@@ -680,6 +687,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
return -1;
}
+ private void updateCallingPackage() {
+ updateCallingPackage(UID_NOT_SET, null);
+ }
+
+ private void updateCallingPackage(int uid, String packageName) {
+ if (uid == UID_NOT_SET) {
+ uid = Binder.getCallingUid();
+ }
+ synchronized (mLock) {
+ if (mCallingUid == UID_NOT_SET || mCallingUid != uid) {
+ mCallingUid = uid;
+ mCallingPackage = packageName;
+ if (mCallingPackage != null) {
+ return;
+ }
+ Context context = mService.getContext();
+ if (context == null) {
+ return;
+ }
+ String[] packages = context.getPackageManager().getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ mCallingPackage = packages[0];
+ }
+ }
+ }
+ }
+
private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
@Override
public void run() {
@@ -831,6 +865,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
}
}
+
+ @Override
+ public String getCallingPackage() {
+ return mCallingPackage;
+ }
}
class SessionCb {
@@ -868,6 +907,38 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ public void prepare() {
+ try {
+ mCb.onPrepare();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepare.", e);
+ }
+ }
+
+ public void prepareFromMediaId(String mediaId, Bundle extras) {
+ try {
+ mCb.onPrepareFromMediaId(mediaId, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
+ }
+ }
+
+ public void prepareFromSearch(String query, Bundle extras) {
+ try {
+ mCb.onPrepareFromSearch(query, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
+ }
+ }
+
+ public void prepareFromUri(Uri uri, Bundle extras) {
+ try {
+ mCb.onPrepareFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepareFromUri.", e);
+ }
+ }
+
public void play() {
try {
mCb.onPlay();
@@ -880,7 +951,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
try {
mCb.onPlayFromMediaId(mediaId, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in playUri.", e);
+ Slog.e(TAG, "Remote failure in playFromMediaId.", e);
}
}
@@ -993,11 +1064,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void sendCommand(String command, Bundle args, ResultReceiver cb)
throws RemoteException {
+ updateCallingPackage();
mSessionCb.sendCommand(command, args, cb);
}
@Override
public boolean sendMediaButton(KeyEvent mediaButtonIntent) {
+ updateCallingPackage();
return mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
}
@@ -1079,6 +1152,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void adjustVolume(int direction, int flags, String packageName) {
+ updateCallingPackage();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
@@ -1090,6 +1164,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void setVolumeTo(int value, int flags, String packageName) {
+ updateCallingPackage();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
@@ -1100,74 +1175,112 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void prepare() throws RemoteException {
+ updateCallingPackage();
+ mSessionCb.prepare();
+ }
+
+ @Override
+ public void prepareFromMediaId(String mediaId, Bundle extras)
+ throws RemoteException {
+ updateCallingPackage();
+ mSessionCb.prepareFromMediaId(mediaId, extras);
+ }
+
+ @Override
+ public void prepareFromSearch(String query, Bundle extras) throws RemoteException {
+ updateCallingPackage();
+ mSessionCb.prepareFromSearch(query, extras);
+ }
+
+ @Override
+ public void prepareFromUri(Uri uri, Bundle extras) throws RemoteException {
+ updateCallingPackage();
+ mSessionCb.prepareFromUri(uri, extras);
+ }
+
+ @Override
public void play() throws RemoteException {
+ updateCallingPackage();
mSessionCb.play();
}
@Override
public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
+ updateCallingPackage();
mSessionCb.playFromMediaId(mediaId, extras);
}
@Override
public void playFromSearch(String query, Bundle extras) throws RemoteException {
+ updateCallingPackage();
mSessionCb.playFromSearch(query, extras);
}
@Override
public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
+ updateCallingPackage();
mSessionCb.playFromUri(uri, extras);
}
@Override
public void skipToQueueItem(long id) {
+ updateCallingPackage();
mSessionCb.skipToTrack(id);
}
-
@Override
public void pause() throws RemoteException {
+ updateCallingPackage();
mSessionCb.pause();
}
@Override
public void stop() throws RemoteException {
+ updateCallingPackage();
mSessionCb.stop();
}
@Override
public void next() throws RemoteException {
+ updateCallingPackage();
mSessionCb.next();
}
@Override
public void previous() throws RemoteException {
+ updateCallingPackage();
mSessionCb.previous();
}
@Override
public void fastForward() throws RemoteException {
+ updateCallingPackage();
mSessionCb.fastForward();
}
@Override
public void rewind() throws RemoteException {
+ updateCallingPackage();
mSessionCb.rewind();
}
@Override
public void seekTo(long pos) throws RemoteException {
+ updateCallingPackage();
mSessionCb.seekTo(pos);
}
@Override
public void rate(Rating rating) throws RemoteException {
+ updateCallingPackage();
mSessionCb.rate(rating);
}
@Override
public void sendCustomAction(String action, Bundle args)
throws RemoteException {
+ updateCallingPackage();
mSessionCb.sendCustomAction(action, args);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 745f4763c1ea..e3c540a54eb2 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -946,7 +946,8 @@ public class MediaSessionService extends SystemService implements Monitor {
// won't release it later
session.sendMediaButton(keyEvent,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
- mKeyEventReceiver);
+ mKeyEventReceiver, getContext().getApplicationInfo().uid,
+ getContext().getPackageName());
} else {
// Launch the last PendingIntent we had with priority
UserRecord user = mUserRecords.get(mCurrentUserId);
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index 90e26d848837..9f1435acd4c7 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -59,8 +59,12 @@ public class IpConfigStore {
protected static final int IPCONFIG_FILE_VERSION = 2;
+ public IpConfigStore(DelayedDiskWrite writer) {
+ mWriter = writer;
+ }
+
public IpConfigStore() {
- mWriter = new DelayedDiskWrite();
+ this(new DelayedDiskWrite());
}
private boolean writeConfig(DataOutputStream out, int configKey,
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b2e6adfd028a..09b7a18af40f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,6 +28,7 @@ import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
+
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIMAX;
@@ -165,6 +166,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
import com.google.android.collect.Lists;
import org.xmlpull.v1.XmlPullParser;
@@ -221,6 +223,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG_APP_POLICY = "app-policy";
private static final String TAG_WHITELIST = "whitelist";
private static final String TAG_RESTRICT_BACKGROUND = "restrict-background";
+ private static final String TAG_REVOKED_RESTRICT_BACKGROUND = "revoked-restrict-background";
private static final String ATTR_VERSION = "version";
private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
@@ -240,8 +243,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String ATTR_APP_ID = "appId";
private static final String ATTR_POLICY = "policy";
- private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
-
private static final String ACTION_ALLOW_BACKGROUND =
"com.android.server.net.action.ALLOW_BACKGROUND";
private static final String ACTION_SNOOZE_WARNING =
@@ -318,6 +319,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();
+ /**
+ * UIDs that have been initially white-listed by system to avoid restricted background.
+ */
+ private final SparseBooleanArray mDefaultRestrictBackgroundWhitelistUids =
+ new SparseBooleanArray();
+
+ /**
+ * UIDs that have been initially white-listed by system to avoid restricted background,
+ * but later revoked by user.
+ */
+ private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids =
+ new SparseBooleanArray();
+
/** Set of ifaces that are metered. */
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
/** Set of over-limit templates that have been notified. */
@@ -339,6 +353,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final AppOpsManager mAppOps;
private final MyPackageMonitor mPackageMonitor;
+ private final IPackageManager mIPm;
+
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
@@ -369,6 +385,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
Context.DEVICE_IDLE_CONTROLLER));
mTime = checkNotNull(time, "missing TrustedTime");
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mIPm = AppGlobals.getPackageManager();
HandlerThread thread = new HandlerThread(TAG);
thread.start();
@@ -411,6 +428,53 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ /**
+ * Whitelists pre-defined apps for restrict background, but only if the user didn't already
+ * revoke the whitelist.
+ *
+ * @return whether any uid has been added to {@link #mRestrictBackgroundWhitelistUids}.
+ */
+ boolean addDefaultRestrictBackgroundWhitelistUids() {
+ final SystemConfig sysConfig = SystemConfig.getInstance();
+ final PackageManager pm = mContext.getPackageManager();
+ final List<UserInfo> users = mUserManager.getUsers();
+ final int numberUsers = users.size();
+
+ final ArraySet<String> allowDataUsage = sysConfig.getAllowInDataUsageSave();
+ boolean changed = false;
+ for (int i = 0; i < allowDataUsage.size(); i++) {
+ final String pkg = allowDataUsage.valueAt(i);
+ if (LOGD)
+ Slog.d(TAG, "checking restricted background whitelisting for package " + pkg);
+ final ApplicationInfo app;
+ try {
+ app = pm.getApplicationInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Should not happen
+ Slog.wtf(TAG, "No ApplicationInfo for package " + pkg);
+ continue;
+ }
+ if (!app.isPrivilegedApp()) {
+ Slog.w(TAG, "getAllowInDataUsageSave() returned non-privileged app: " + pkg);
+ continue;
+ }
+ for (int j = 0; j < numberUsers; j++) {
+ final UserInfo user = users.get(i);
+ final int uid = UserHandle.getUid(user.id, app.uid);
+ mDefaultRestrictBackgroundWhitelistUids.append(uid, true);
+ if (LOGD) Slog.d(TAG, "revoked whistelist status for uid " + uid + ": "
+ + mRestrictBackgroundWhitelistRevokedUids.get(uid));
+ if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+ Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
+ + user.id + ") to restrict background whitelist");
+ mRestrictBackgroundWhitelistUids.append(uid, true);
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ }
+
void updatePowerSaveTempWhitelistLocked() {
try {
// Clear the states of the current whitelist
@@ -472,6 +536,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// read policy from disk
readPolicyLocked();
+ if (addDefaultRestrictBackgroundWhitelistUids()) {
+ writePolicyLocked();
+ }
+
updateRulesForGlobalChangeLocked(false);
updateNotificationsLocked();
}
@@ -841,11 +909,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- // ongoing notification when restricting background data
- if (mRestrictBackground) {
- enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
- }
-
// cancel stale notifications that we didn't renew above
for (int i = beforeNotifs.size()-1; i >= 0; i--) {
final String tag = beforeNotifs.valueAt(i);
@@ -1023,42 +1086,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- /**
- * Show ongoing notification to reflect that {@link #mRestrictBackground}
- * has been enabled.
- */
- private void enqueueRestrictedNotification(String tag) {
- final Resources res = mContext.getResources();
- final Notification.Builder builder = new Notification.Builder(mContext);
-
- final CharSequence title = res.getText(R.string.data_usage_restricted_title);
- final CharSequence body = res.getString(R.string.data_usage_restricted_body);
-
- builder.setOnlyAlertOnce(true);
- builder.setOngoing(true);
- builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
- builder.setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
-
- final Intent intent = buildAllowBackgroundDataIntent();
- builder.setContentIntent(
- PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
-
- // TODO: move to NotificationManager once we can mock it
- try {
- final String packageName = mContext.getPackageName();
- final int[] idReceived = new int[1];
- mNotifManager.enqueueNotificationWithTag(packageName, packageName, tag,
- 0x0, builder.getNotification(), idReceived, UserHandle.USER_ALL);
- mActiveNotifs.add(tag);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
- }
-
private void cancelNotification(String tag) {
// TODO: move to NotificationManager once we can mock it
try {
@@ -1461,6 +1488,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
final int uid = readIntAttribute(in, ATTR_UID);
mRestrictBackgroundWhitelistUids.put(uid, true);
+ } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
+ final int uid = readIntAttribute(in, ATTR_UID);
+ mRestrictBackgroundWhitelistRevokedUids.put(uid, true);
}
} else if (type == END_TAG) {
if (TAG_WHITELIST.equals(tag)) {
@@ -1559,7 +1589,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
out.startTag(null, TAG_WHITELIST);
// restrict background whitelist
- final int size = mRestrictBackgroundWhitelistUids.size();
+ int size = mRestrictBackgroundWhitelistUids.size();
for (int i = 0; i < size; i++) {
final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
out.startTag(null, TAG_RESTRICT_BACKGROUND);
@@ -1567,6 +1597,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
out.endTag(null, TAG_RESTRICT_BACKGROUND);
}
+ // revoked restrict background whitelist
+ size = mRestrictBackgroundWhitelistRevokedUids.size();
+ for (int i = 0; i < size; i++) {
+ final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i);
+ out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
+ writeIntAttribute(out, ATTR_UID, uid);
+ out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
+ }
+
out.endTag(null, TAG_WHITELIST);
out.endDocument();
@@ -1739,13 +1778,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public void setNetworkPolicies(NetworkPolicy[] policies) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- normalizePoliciesLocked(policies);
- updateNetworkEnabledLocked();
- updateNetworkRulesLocked();
- updateNotificationsLocked();
- writePolicyLocked();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ maybeRefreshTrustedTime();
+ synchronized (mRulesLock) {
+ normalizePoliciesLocked(policies);
+ updateNetworkEnabledLocked();
+ updateNetworkRulesLocked();
+ updateNotificationsLocked();
+ writePolicyLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
@@ -1848,13 +1892,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public void setRestrictBackground(boolean restrictBackground) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ maybeRefreshTrustedTime();
+ synchronized (mRulesLock) {
+ mRestrictBackground = restrictBackground;
+ updateRulesForGlobalChangeLocked(true);
+ updateNotificationsLocked();
+ writePolicyLocked();
+ }
- maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- mRestrictBackground = restrictBackground;
- updateRulesForGlobalChangeLocked(true);
- updateNotificationsLocked();
- writePolicyLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
@@ -1864,31 +1913,70 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public void addRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
+ if (!isUidValidForRules(uid)) return;
+ final boolean changed;
synchronized (mRulesLock) {
+ final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+ if (oldStatus) {
+ if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
+ return;
+ }
+ Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
mRestrictBackgroundWhitelistUids.append(uid, true);
- updateRulesForGlobalChangeLocked(true);
+ if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
+ && mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+ if (LOGD) Slog.d(TAG, "Removing uid " + uid
+ + " from revoked restrict background whitelist");
+ mRestrictBackgroundWhitelistRevokedUids.delete(uid);
+ }
+ changed = mRestrictBackground && !oldStatus;
+ if (changed && hasInternetPermissions(uid)) {
+ setUidNetworkRules(uid, false);
+ }
writePolicyLocked();
}
- mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget();
+ if (changed) {
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+ .sendToTarget();
+ }
}
@Override
public void removeRestrictBackgroundWhitelistedUid(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+ if (!isUidValidForRules(uid)) return;
+ final boolean changed;
synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+ changed = removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+ }
+ if (changed) {
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+ .sendToTarget();
}
- mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget();
}
- private void removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+ private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+ final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+ if (!oldStatus) {
+ if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
+ return false;
+ }
+ Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+ final boolean changed = mRestrictBackground && oldStatus;
mRestrictBackgroundWhitelistUids.delete(uid);
+ if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
+ && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+ if (LOGD) Slog.d(TAG, "Adding uid " + uid
+ + " to revoked restrict background whitelist");
+ mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
+ }
if (updateNow) {
- updateRulesForGlobalChangeLocked(true);
+ if (changed && hasInternetPermissions(uid)) {
+ setUidNetworkRules(uid, true);
+ }
writePolicyLocked();
}
+ return changed;
}
@Override
@@ -2128,6 +2216,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.decreaseIndent();
}
+ size = mDefaultRestrictBackgroundWhitelistUids.size();
+ if (size > 0) {
+ fout.println("Default restrict background whitelist uids:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
+ size = mRestrictBackgroundWhitelistRevokedUids.size();
+ if (size > 0) {
+ fout.println("Default restrict background whitelist uids revoked by users:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i));
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
collectKeys(mUidRules, knownUids);
@@ -2298,13 +2410,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
uidRules.clear();
// Fully update the app idle firewall chain.
+ final IPackageManager ipm = AppGlobals.getPackageManager();
final List<UserInfo> users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
for (int uid : idleUids) {
if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
- uidRules.put(uid, FIREWALL_RULE_DENY);
+ // quick check: if this uid doesn't have INTERNET permission, it
+ // doesn't have network access anyway, so it is a waste to mess
+ // with it here.
+ if (hasInternetPermissions(uid)) {
+ uidRules.put(uid, FIREWALL_RULE_DENY);
+ }
}
}
}
@@ -2408,22 +2526,27 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
/**
- * Applies network rules to bandwidth and firewall controllers based on uid policy.
- * @param uid The uid for which to apply the latest policy
+ * Checks if an uid has INTERNET permissions.
+ * <p>
+ * Useful for the cases where the lack of network access can simplify the rules.
*/
- void updateRulesForUidLocked(int uid) {
- if (!isUidValidForRules(uid)) return;
-
- // quick check: if this uid doesn't have INTERNET permission, it doesn't have
- // network access anyway, so it is a waste to mess with it here.
- final IPackageManager ipm = AppGlobals.getPackageManager();
+ private boolean hasInternetPermissions(int uid) {
try {
- if (ipm.checkUidPermission(Manifest.permission.INTERNET, uid)
+ if (mIPm.checkUidPermission(Manifest.permission.INTERNET, uid)
!= PackageManager.PERMISSION_GRANTED) {
- return;
+ return false;
}
} catch (RemoteException e) {
}
+ return true;
+ }
+
+ /**
+ * Applies network rules to bandwidth and firewall controllers based on uid policy.
+ * @param uid The uid for which to apply the latest policy
+ */
+ void updateRulesForUidLocked(int uid) {
+ if (!isUidValidForRules(uid) || !hasInternetPermissions(uid)) return;
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean uidForeground = isUidForegroundLocked(uid);
@@ -2590,15 +2713,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int uid = msg.arg1;
final PackageManager pm = mContext.getPackageManager();
final String[] packages = pm.getPackagesForUid(uid);
- final int userId = UserHandle.getUserId(uid);
- for (String packageName : packages) {
- final Intent intent =
- new Intent(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
- intent.setPackage(packageName);
- intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ if (packages != null) {
+ final int userId = UserHandle.getUserId(uid);
+ for (String packageName : packages) {
+ final Intent intent = new Intent(
+ ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
+ intent.setPackage(packageName);
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
+ } else {
+ Slog.w(TAG, "no packages for uid " + uid);
}
-
return true;
}
case MSG_ADVISE_PERSIST_THRESHOLD: {
@@ -2831,13 +2957,5 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
removeRestrictBackgroundWhitelistedUidLocked(uid, true);
}
}
-
- @Override
- public void onPackageRemovedAllUsers(String packageName, int uid) {
- if (LOGV) Slog.v(TAG, "onPackageRemovedAllUsers: " + packageName + " ->" + uid);
- synchronized (mRulesLock) {
- removeRestrictBackgroundWhitelistedUidLocked(uid, true);
- }
- }
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 5cd102556fc3..a5dc008d4e6c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -211,12 +211,7 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
if (enabled < 0) {
return enabled;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mInterface.setRestrictBackground(enabled > 0);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mInterface.setRestrictBackground(enabled > 0);
return 0;
}
@@ -225,12 +220,7 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
if (uid < 0) {
return uid;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mInterface.addRestrictBackgroundWhitelistedUid(uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mInterface.addRestrictBackgroundWhitelistedUid(uid);
return 0;
}
@@ -239,12 +229,7 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
if (uid < 0) {
return uid;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mInterface.removeRestrictBackgroundWhitelistedUid(uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mInterface.removeRestrictBackgroundWhitelistedUid(uid);
return 0;
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 479b065f5ced..98fe7707747c 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
@@ -48,6 +49,7 @@ public final class NetworkStatsAccess {
@IntDef({
Level.DEFAULT,
Level.USER,
+ Level.DEVICESUMMARY,
Level.DEVICE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -147,6 +149,12 @@ public final class NetworkStatsAccess {
// Device-level access - can access usage for any uid.
return true;
case NetworkStatsAccess.Level.DEVICESUMMARY:
+ // Can access usage for any app running in the same user, along
+ // with some special uids (system, removed, or tethering) and
+ // anonymized uids
+ return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
+ || uid == UID_TETHERING || uid == UID_ALL
+ || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
case NetworkStatsAccess.Level.USER:
// User-level access - can access usage for any app running in the same user, along
// with some special uids (system, removed, or tethering).
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index eec7d931d40e..d986e94b0253 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -135,7 +135,11 @@ public class NetworkStatsCollection implements FileRotator.Reader {
}
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
- final int callerUid = Binder.getCallingUid();
+ return getRelevantUids(accessLevel, Binder.getCallingUid());
+ }
+
+ public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel,
+ final int callerUid) {
IntArray uids = new IntArray();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
@@ -169,7 +173,17 @@ public class NetworkStatsCollection implements FileRotator.Reader {
public NetworkStatsHistory getHistory(
NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
@NetworkStatsAccess.Level int accessLevel) {
- final int callerUid = Binder.getCallingUid();
+ return getHistory(template, uid, set, tag, fields, start, end, accessLevel,
+ Binder.getCallingUid());
+ }
+
+ /**
+ * Combine all {@link NetworkStatsHistory} in this collection which match
+ * the requested parameters.
+ */
+ public NetworkStatsHistory getHistory(
+ NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel, int callerUid) {
if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
throw new SecurityException("Network stats history of uid " + uid
+ " is forbidden for caller " + callerUid);
@@ -198,6 +212,15 @@ public class NetworkStatsCollection implements FileRotator.Reader {
*/
public NetworkStats getSummary(NetworkTemplate template, long start, long end,
@NetworkStatsAccess.Level int accessLevel) {
+ return getSummary(template, start, end, accessLevel, Binder.getCallingUid());
+ }
+
+ /**
+ * Summarize all {@link NetworkStatsHistory} in this collection which match
+ * the requested parameters.
+ */
+ public NetworkStats getSummary(NetworkTemplate template, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel, int callerUid) {
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
@@ -207,7 +230,6 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final NetworkStats.Entry entry = new NetworkStats.Entry();
NetworkStatsHistory.Entry historyEntry = null;
- final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
if (templateMatches(template, key.ident)
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
new file mode 100644
index 000000000000..2f55562bc060
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -0,0 +1,493 @@
+/*
+ * 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.net;
+
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.app.usage.NetworkStatsManager;
+import android.net.DataUsageRequest;
+import android.net.NetworkStats;
+import android.net.NetworkStats.NonMonotonicObserver;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.IntArray;
+import android.util.SparseArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.VpnInfo;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages observers of {@link NetworkStats}. Allows observers to be notified when
+ * data usage has been reported in {@link NetworkStatsService}. An observer can set
+ * a threshold of how much data it cares about to be notified.
+ */
+class NetworkStatsObservers {
+ private static final String TAG = "NetworkStatsObservers";
+ private static final boolean LOGV = true;
+
+ private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES;
+
+ private static final int MSG_REGISTER = 1;
+ private static final int MSG_UNREGISTER = 2;
+ private static final int MSG_UPDATE_STATS = 3;
+
+ // All access to this map must be done from the handler thread.
+ // indexed by DataUsageRequest#requestId
+ private final SparseArray<RequestInfo> mDataUsageRequests = new SparseArray<>();
+
+ // Sequence number of DataUsageRequests
+ private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger();
+
+ // Lazily instantiated when an observer is registered.
+ private Handler mHandler;
+
+ /**
+ * Creates a wrapper that contains the caller context and a normalized request.
+ * The request should be returned to the caller app, and the wrapper should be sent to this
+ * object through #addObserver by the service handler.
+ *
+ * <p>It will register the observer asynchronously, so it is safe to call from any thread.
+ *
+ * @return the normalized request wrapped within {@link RequestInfo}.
+ */
+ public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger,
+ IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
+ checkVisibilityUids(callingUid, accessLevel, inputRequest.uids);
+
+ DataUsageRequest request = buildRequest(inputRequest);
+ RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
+ accessLevel);
+
+ if (LOGV) Slog.v(TAG, "Registering observer for " + request);
+ getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
+ return request;
+ }
+
+ /**
+ * Unregister a data usage observer.
+ *
+ * <p>It will unregister the observer asynchronously, so it is safe to call from any thread.
+ */
+ public void unregister(DataUsageRequest request, int callingUid) {
+ getHandler().sendMessage(mHandler.obtainMessage(MSG_UNREGISTER, callingUid, 0 /* ignore */,
+ request));
+ }
+
+ /**
+ * Updates data usage statistics of registered observers and notifies if limits are reached.
+ *
+ * <p>It will update stats asynchronously, so it is safe to call from any thread.
+ */
+ public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot,
+ ArrayMap<String, NetworkIdentitySet> activeIfaces,
+ ArrayMap<String, NetworkIdentitySet> activeUidIfaces,
+ VpnInfo[] vpnArray, long currentTime) {
+ StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces,
+ activeUidIfaces, vpnArray, currentTime);
+ getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext));
+ }
+
+ private Handler getHandler() {
+ if (mHandler == null) {
+ synchronized (this) {
+ if (mHandler == null) {
+ if (LOGV) Slog.v(TAG, "Creating handler");
+ mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback);
+ }
+ }
+ }
+ return mHandler;
+ }
+
+ @VisibleForTesting
+ protected Looper getHandlerLooperLocked() {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ return handlerThread.getLooper();
+ }
+
+ private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REGISTER: {
+ handleRegister((RequestInfo) msg.obj);
+ return true;
+ }
+ case MSG_UNREGISTER: {
+ handleUnregister((DataUsageRequest) msg.obj, msg.arg1 /* callingUid */);
+ return true;
+ }
+ case MSG_UPDATE_STATS: {
+ handleUpdateStats((StatsContext) msg.obj);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
+ };
+
+ /**
+ * Adds a {@link RequestInfo} as an observer.
+ * Should only be called from the handler thread otherwise there will be a race condition
+ * on mDataUsageRequests.
+ */
+ private void handleRegister(RequestInfo requestInfo) {
+ mDataUsageRequests.put(requestInfo.mRequest.requestId, requestInfo);
+ }
+
+ /**
+ * Removes a {@link DataUsageRequest} if the calling uid is authorized.
+ * Should only be called from the handler thread otherwise there will be a race condition
+ * on mDataUsageRequests.
+ */
+ private void handleUnregister(DataUsageRequest request, int callingUid) {
+ RequestInfo requestInfo;
+ requestInfo = mDataUsageRequests.get(request.requestId);
+ if (requestInfo == null) {
+ if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request);
+ return;
+ }
+ if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
+ Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
+ return;
+ }
+
+ if (LOGV) Slog.v(TAG, "Unregistering " + request);
+ mDataUsageRequests.remove(request.requestId);
+ requestInfo.unlinkDeathRecipient();
+ requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
+ }
+
+ private void handleUpdateStats(StatsContext statsContext) {
+ if (mDataUsageRequests.size() == 0) {
+ if (LOGV) Slog.v(TAG, "No registered listeners of data usage");
+ return;
+ }
+
+ if (LOGV) Slog.v(TAG, "Checking if any registered observer needs to be notified");
+ for (int i = 0; i < mDataUsageRequests.size(); i++) {
+ RequestInfo requestInfo = mDataUsageRequests.valueAt(i);
+ requestInfo.updateStats(statsContext);
+ }
+ }
+
+ private DataUsageRequest buildRequest(DataUsageRequest request) {
+ // Cap the minimum threshold to a safe default to avoid too many callbacks
+ long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes);
+ if (thresholdInBytes < request.thresholdInBytes) {
+ Slog.w(TAG, "Threshold was too low for " + request
+ + ". Overriding to a safer default of " + thresholdInBytes + " bytes");
+ }
+ return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
+ request.templates, request.uids, thresholdInBytes);
+ }
+
+ private RequestInfo buildRequestInfo(DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ if (accessLevel <= NetworkStatsAccess.Level.USER
+ || request.uids != null && request.uids.length > 0) {
+ return new UserUsageRequestInfo(this, request, messenger, binder, callingUid,
+ accessLevel);
+ } else {
+ // Safety check in case a new access level is added and we forgot to update this
+ checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY);
+ return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid,
+ accessLevel);
+ }
+ }
+
+ private void checkVisibilityUids(int callingUid, @NetworkStatsAccess.Level int accessLevel,
+ int[] uids) {
+ if (uids == null) {
+ return;
+ }
+ for (int i = 0; i < uids.length; i++) {
+ if (!NetworkStatsAccess.isAccessibleToUser(uids[i], callingUid, accessLevel)) {
+ throw new SecurityException("Caller " + callingUid + " cannot monitor network stats"
+ + " for uid " + uids[i] + " with accessLevel " + accessLevel);
+ }
+ }
+ }
+
+ /**
+ * Tracks information relevant to a data usage observer.
+ * It will notice when the calling process dies so we can self-expire.
+ */
+ private abstract static class RequestInfo implements IBinder.DeathRecipient {
+ private final NetworkStatsObservers mStatsObserver;
+ protected final DataUsageRequest mRequest;
+ private final Messenger mMessenger;
+ private final IBinder mBinder;
+ protected final int mCallingUid;
+ protected final @NetworkStatsAccess.Level int mAccessLevel;
+ protected NetworkStatsRecorder mRecorder;
+ protected NetworkStatsCollection mCollection;
+
+ RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ mStatsObserver = statsObserver;
+ mRequest = request;
+ mMessenger = messenger;
+ mBinder = binder;
+ mCallingUid = callingUid;
+ mAccessLevel = accessLevel;
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ if (LOGV) Slog.v(TAG, "RequestInfo binderDied("
+ + mRequest + ", " + mBinder + ")");
+ mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
+ callCallback(NetworkStatsManager.CALLBACK_RELEASED);
+ }
+
+ @Override
+ public String toString() {
+ return "RequestInfo from uid:" + mCallingUid
+ + " for " + mRequest + " accessLevel:" + mAccessLevel;
+ }
+
+ private void unlinkDeathRecipient() {
+ if (mBinder != null) {
+ mBinder.unlinkToDeath(this, 0);
+ }
+ }
+
+ /**
+ * Update stats given the samples and interface to identity mappings.
+ */
+ private void updateStats(StatsContext statsContext) {
+ if (mRecorder == null) {
+ // First run; establish baseline stats
+ resetRecorder();
+ recordSample(statsContext);
+ return;
+ }
+ recordSample(statsContext);
+
+ if (checkStats()) {
+ resetRecorder();
+ callCallback(NetworkStatsManager.CALLBACK_LIMIT_REACHED);
+ }
+ }
+
+ private void callCallback(int callbackType) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(DataUsageRequest.PARCELABLE_KEY, mRequest);
+ Message msg = Message.obtain();
+ msg.what = callbackType;
+ msg.setData(bundle);
+ try {
+ if (LOGV) {
+ Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+ + " for " + mRequest);
+ }
+ mMessenger.send(msg);
+ } catch (RemoteException e) {
+ // May occur naturally in the race of binder death.
+ Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
+ }
+ }
+
+ private void resetRecorder() {
+ mRecorder = new NetworkStatsRecorder();
+ mCollection = mRecorder.getSinceBoot();
+ }
+
+ protected abstract boolean checkStats();
+
+ protected abstract void recordSample(StatsContext statsContext);
+
+ private String callbackTypeToName(int callbackType) {
+ switch (callbackType) {
+ case NetworkStatsManager.CALLBACK_LIMIT_REACHED:
+ return "LIMIT_REACHED";
+ case NetworkStatsManager.CALLBACK_RELEASED:
+ return "RELEASED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ private static class NetworkUsageRequestInfo extends RequestInfo {
+ NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ super(statsObserver, request, messenger, binder, callingUid, accessLevel);
+ }
+
+ @Override
+ protected boolean checkStats() {
+ for (int i = 0; i < mRequest.templates.length; i++) {
+ long bytesSoFar = getTotalBytesForNetwork(mRequest.templates[i]);
+ if (LOGV) {
+ Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+ + mRequest.templates[i]);
+ }
+ if (bytesSoFar > mRequest.thresholdInBytes) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void recordSample(StatsContext statsContext) {
+ // Recorder does not need to be locked in this context since only the handler
+ // thread will update it
+ mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces,
+ statsContext.mVpnArray, statsContext.mCurrentTime);
+ }
+
+ /**
+ * Reads stats matching the given template. {@link NetworkStatsCollection} will aggregate
+ * over all buckets, which in this case should be only one since we built it big enough
+ * that it will outlive the caller. If it doesn't, then there will be multiple buckets.
+ */
+ private long getTotalBytesForNetwork(NetworkTemplate template) {
+ NetworkStats stats = mCollection.getSummary(template,
+ Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
+ mAccessLevel, mCallingUid);
+ if (LOGV) {
+ Slog.v(TAG, "Netstats for " + template + ": " + stats);
+ }
+ return stats.getTotalBytes();
+ }
+ }
+
+ private static class UserUsageRequestInfo extends RequestInfo {
+ UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ super(statsObserver, request, messenger, binder, callingUid, accessLevel);
+ }
+
+ @Override
+ protected boolean checkStats() {
+ int[] uidsToMonitor = getUidsToMonitor();
+
+ for (int i = 0; i < mRequest.templates.length; i++) {
+ for (int j = 0; j < uidsToMonitor.length; j++) {
+ long bytesSoFar = getTotalBytesForNetworkUid(mRequest.templates[i],
+ uidsToMonitor[j]);
+
+ if (LOGV) {
+ Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+ + mRequest.templates[i] + " for uid=" + uidsToMonitor[j]);
+ }
+ if (bytesSoFar > mRequest.thresholdInBytes) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void recordSample(StatsContext statsContext) {
+ // Recorder does not need to be locked in this context since only the handler
+ // thread will update it
+ mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces,
+ statsContext.mVpnArray, statsContext.mCurrentTime);
+ }
+
+ /**
+ * Reads all stats matching the given template and uid. Ther history will likely only
+ * contain one bucket per ident since we build it big enough that it will outlive the
+ * caller lifetime.
+ */
+ private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) {
+ try {
+ NetworkStatsHistory history = mCollection.getHistory(template, uid,
+ NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
+ NetworkStatsHistory.FIELD_ALL,
+ Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
+ mAccessLevel, mCallingUid);
+ return history.getTotalBytes();
+ } catch (SecurityException e) {
+ if (LOGV) {
+ Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+ + uid);
+ }
+ return 0;
+ }
+ }
+
+ private int[] getUidsToMonitor() {
+ if (mRequest.uids == null || mRequest.uids.length == 0) {
+ return mCollection.getRelevantUids(mAccessLevel, mCallingUid);
+ }
+ // Pick only uids from the request that are currently accessible to the user
+ IntArray accessibleUids = new IntArray(mRequest.uids.length);
+ for (int i = 0; i < mRequest.uids.length; i++) {
+ int uid = mRequest.uids[i];
+ if (NetworkStatsAccess.isAccessibleToUser(uid, mCallingUid, mAccessLevel)) {
+ accessibleUids.add(uid);
+ }
+ }
+ return accessibleUids.toArray();
+ }
+ }
+
+ private static class StatsContext {
+ NetworkStats mXtSnapshot;
+ NetworkStats mUidSnapshot;
+ ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
+ ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
+ VpnInfo[] mVpnArray;
+ long mCurrentTime;
+
+ StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot,
+ ArrayMap<String, NetworkIdentitySet> activeIfaces,
+ ArrayMap<String, NetworkIdentitySet> activeUidIfaces,
+ VpnInfo[] vpnArray, long currentTime) {
+ mXtSnapshot = xtSnapshot;
+ mUidSnapshot = uidSnapshot;
+ mActiveIfaces = activeIfaces;
+ mActiveUidIfaces = activeUidIfaces;
+ mVpnArray = vpnArray;
+ mCurrentTime = currentTime;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index c09196006be2..04dc917ec3ab 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -19,6 +19,7 @@ package com.android.server.net;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.net.NetworkStats;
@@ -54,7 +55,7 @@ import libcore.io.IoUtils;
* Logic to record deltas between periodic {@link NetworkStats} snapshots into
* {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
* Keeps pending changes in memory until they pass a specific threshold, in
- * bytes. Uses {@link FileRotator} for persistence logic.
+ * bytes. Uses {@link FileRotator} for persistence logic if present.
* <p>
* Not inherently thread safe.
*/
@@ -86,6 +87,29 @@ public class NetworkStatsRecorder {
private WeakReference<NetworkStatsCollection> mComplete;
+ /**
+ * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
+ */
+ public NetworkStatsRecorder() {
+ mRotator = null;
+ mObserver = null;
+ mDropBox = null;
+ mCookie = null;
+
+ // set the bucket big enough to have all data in one bucket, but allow some
+ // slack to avoid overflow
+ mBucketDuration = YEAR_IN_MILLIS;
+ mOnlyTags = false;
+
+ mPending = null;
+ mSinceBoot = new NetworkStatsCollection(mBucketDuration);
+
+ mPendingRewriter = null;
+ }
+
+ /**
+ * Persisted recorder.
+ */
public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
mRotator = checkNotNull(rotator, "missing FileRotator");
@@ -110,9 +134,15 @@ public class NetworkStatsRecorder {
public void resetLocked() {
mLastSnapshot = null;
- mPending.reset();
- mSinceBoot.reset();
- mComplete.clear();
+ if (mPending != null) {
+ mPending.reset();
+ }
+ if (mSinceBoot != null) {
+ mSinceBoot.reset();
+ }
+ if (mComplete != null) {
+ mComplete.clear();
+ }
}
public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
@@ -120,6 +150,10 @@ public class NetworkStatsRecorder {
NetworkStatsAccess.Level.DEVICE).getTotal(null);
}
+ public NetworkStatsCollection getSinceBoot() {
+ return mSinceBoot;
+ }
+
/**
* Load complete history represented by {@link FileRotator}. Caches
* internally as a {@link WeakReference}, and updated with future
@@ -127,6 +161,7 @@ public class NetworkStatsRecorder {
* as reference is valid.
*/
public NetworkStatsCollection getOrLoadCompleteLocked() {
+ checkNotNull(mRotator, "missing FileRotator");
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
if (res == null) {
res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
@@ -136,6 +171,7 @@ public class NetworkStatsRecorder {
}
public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
+ checkNotNull(mRotator, "missing FileRotator");
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
if (res == null) {
res = loadLocked(start, end);
@@ -205,7 +241,9 @@ public class NetworkStatsRecorder {
// only record tag data when requested
if ((entry.tag == TAG_NONE) != mOnlyTags) {
- mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+ if (mPending != null) {
+ mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+ }
// also record against boot stats when present
if (mSinceBoot != null) {
@@ -231,6 +269,7 @@ public class NetworkStatsRecorder {
* {@link #mPersistThresholdBytes}.
*/
public void maybePersistLocked(long currentTimeMillis) {
+ checkNotNull(mRotator, "missing FileRotator");
final long pendingBytes = mPending.getTotalBytes();
if (pendingBytes >= mPersistThresholdBytes) {
forcePersistLocked(currentTimeMillis);
@@ -243,6 +282,7 @@ public class NetworkStatsRecorder {
* Force persisting any pending deltas.
*/
public void forcePersistLocked(long currentTimeMillis) {
+ checkNotNull(mRotator, "missing FileRotator");
if (mPending.isDirty()) {
if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
try {
@@ -264,20 +304,26 @@ public class NetworkStatsRecorder {
* to {@link TrafficStats#UID_REMOVED}.
*/
public void removeUidsLocked(int[] uids) {
- try {
- // Rewrite all persisted data to migrate UID stats
- mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
- } catch (IOException e) {
- Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
- recoverFromWtf();
- } catch (OutOfMemoryError e) {
- Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
- recoverFromWtf();
+ if (mRotator != null) {
+ try {
+ // Rewrite all persisted data to migrate UID stats
+ mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
+ recoverFromWtf();
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
+ recoverFromWtf();
+ }
}
// Remove any pending stats
- mPending.removeUids(uids);
- mSinceBoot.removeUids(uids);
+ if (mPending != null) {
+ mPending.removeUids(uids);
+ }
+ if (mSinceBoot != null) {
+ mSinceBoot.removeUids(uids);
+ }
// Clear UID from current stats snapshot
if (mLastSnapshot != null) {
@@ -361,6 +407,8 @@ public class NetworkStatsRecorder {
}
public void importLegacyNetworkLocked(File file) throws IOException {
+ checkNotNull(mRotator, "missing FileRotator");
+
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
@@ -379,6 +427,8 @@ public class NetworkStatsRecorder {
}
public void importLegacyUidLocked(File file) throws IOException {
+ checkNotNull(mRotator, "missing FileRotator");
+
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
@@ -397,7 +447,9 @@ public class NetworkStatsRecorder {
}
public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
- pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
+ if (mPending != null) {
+ pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
+ }
if (fullHistory) {
pw.println("Complete history:");
getOrLoadCompleteLocked().dump(pw);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 3aeceef51de7..2c2e9b91b586 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -57,6 +57,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -72,6 +73,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.DataUsageRequest;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
@@ -90,8 +92,10 @@ import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message;
+import android.os.Messenger;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -152,6 +156,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final TrustedTime mTime;
private final TelephonyManager mTeleManager;
private final NetworkStatsSettings mSettings;
+ private final NetworkStatsObservers mStatsObservers;
private final File mSystemDir;
private final File mBaseDir;
@@ -233,43 +238,65 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/** Data layer operation counters for splicing into other structures. */
private NetworkStats mUidOperations = new NetworkStats(0L, 10);
- private final Handler mHandler;
+ /** Must be set in factory by calling #setHandler. */
+ private Handler mHandler;
+ private Handler.Callback mHandlerCallback;
private boolean mSystemReady;
private long mPersistThreshold = 2 * MB_IN_BYTES;
private long mGlobalAlertBytes;
- public NetworkStatsService(
- Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
- this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
- getDefaultSystemDir(), new DefaultNetworkStatsSettings(context));
- }
-
private static File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
- public NetworkStatsService(Context context, INetworkManagementService networkManager,
- IAlarmManager alarmManager, TrustedTime time, File systemDir,
- NetworkStatsSettings settings) {
+ private static File getDefaultBaseDir() {
+ File baseDir = new File(getDefaultSystemDir(), "netstats");
+ baseDir.mkdirs();
+ return baseDir;
+ }
+
+ public static NetworkStatsService create(Context context,
+ INetworkManagementService networkManager) {
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock =
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
+ wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(),
+ new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(),
+ getDefaultSystemDir(), getDefaultBaseDir());
+
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ Handler.Callback callback = new HandlerCallback(service);
+ handlerThread.start();
+ Handler handler = new Handler(handlerThread.getLooper(), callback);
+ service.setHandler(handler, callback);
+ return service;
+ }
+
+ @VisibleForTesting
+ NetworkStatsService(Context context, INetworkManagementService networkManager,
+ AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time,
+ TelephonyManager teleManager, NetworkStatsSettings settings,
+ NetworkStatsObservers statsObservers, File systemDir, File baseDir) {
mContext = checkNotNull(context, "missing Context");
mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
+ mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
mTime = checkNotNull(time, "missing TrustedTime");
- mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
- mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
- final PowerManager powerManager = (PowerManager) context.getSystemService(
- Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new Handler(thread.getLooper(), mHandlerCallback);
+ mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
+ mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
+ mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
+ mSystemDir = checkNotNull(systemDir, "missing systemDir");
+ mBaseDir = checkNotNull(baseDir, "missing baseDir");
+ }
- mSystemDir = checkNotNull(systemDir);
- mBaseDir = new File(systemDir, "netstats");
- mBaseDir.mkdirs();
+ @VisibleForTesting
+ void setHandler(Handler handler, Handler.Callback callback) {
+ mHandler = handler;
+ mHandlerCallback = callback;
}
public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -733,6 +760,46 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
registerGlobalAlert();
}
+ @Override
+ public DataUsageRequest registerDataUsageCallback(String callingPackage,
+ DataUsageRequest request, Messenger messenger, IBinder binder) {
+ checkNotNull(callingPackage, "calling package is null");
+ checkNotNull(request, "DataUsageRequest is null");
+ checkNotNull(request.templates, "NetworkTemplate is null");
+ checkArgument(request.templates.length > 0);
+ checkNotNull(messenger, "messenger is null");
+ checkNotNull(binder, "binder is null");
+
+ int callingUid = Binder.getCallingUid();
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
+ DataUsageRequest normalizedRequest;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ normalizedRequest = mStatsObservers.register(request, messenger, binder,
+ callingUid, accessLevel);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ // Create baseline stats
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL));
+
+ return normalizedRequest;
+ }
+
+ @Override
+ public void unregisterDataUsageRequest(DataUsageRequest request) {
+ checkNotNull(request, "DataUsageRequest is null");
+
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mStatsObservers.unregister(request, callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
* reflect current {@link #mPersistThreshold} value. Always defers to
@@ -945,6 +1012,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
+
+ // We need to make copies of member fields that are sent to the observer to avoid
+ // a race condition between the service handler thread and the observer's
+ mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces),
+ new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime);
}
/**
@@ -1243,21 +1315,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ @VisibleForTesting
+ static class HandlerCallback implements Handler.Callback {
+ private final NetworkStatsService mService;
+
+ HandlerCallback(NetworkStatsService service) {
+ this.mService = service;
+ }
+
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERFORM_POLL: {
final int flags = msg.arg1;
- performPoll(flags);
+ mService.performPoll(flags);
return true;
}
case MSG_UPDATE_IFACES: {
- updateIfaces();
+ mService.updateIfaces();
return true;
}
case MSG_REGISTER_GLOBAL_ALERT: {
- registerGlobalAlert();
+ mService.registerGlobalAlert();
return true;
}
default: {
@@ -1265,7 +1344,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
}
- };
+ }
private void assertBandwidthControlEnabled() {
if (!isBandwidthControlEnabled()) {
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index ce18818c1fba..9820a1261684 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -234,9 +234,13 @@ public class ConditionProviders extends ManagedServices {
final ConditionRecord r = getRecordLocked(c.id, info.component, true /*create*/);
r.info = info;
r.condition = c;
- if (mCallback != null) {
- mCallback.onConditionChanged(c.id, c);
- }
+ }
+ }
+ final int N = conditions.length;
+ for (int i = 0; i < N; i++) {
+ final Condition c = conditions[i];
+ if (mCallback != null) {
+ mCallback.onConditionChanged(c.id, c);
}
}
}
diff --git a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java b/services/core/java/com/android/server/notification/ImportanceExtractor.java
index c6b3e0fdb0d6..885b9b7919a7 100644
--- a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/ImportanceExtractor.java
@@ -21,7 +21,7 @@ import android.util.Slog;
/**
* Determines the importance of the given notification.
*/
-public class TopicImportanceExtractor implements NotificationSignalExtractor {
+public class ImportanceExtractor implements NotificationSignalExtractor {
private static final String TAG = "ImportantTopicExtractor";
private static final boolean DBG = false;
@@ -42,9 +42,8 @@ public class TopicImportanceExtractor implements NotificationSignalExtractor {
return null;
}
- final int topicImportance = mConfig.getImportance(record.sbn.getPackageName(),
- record.sbn.getUid(), record.sbn.getNotification().getTopic());
- record.setTopicImportance(topicImportance);
+ record.setUserImportance(
+ mConfig.getImportance(record.sbn.getPackageName(), record.sbn.getUid()));
return null;
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 29d52c1739ba..0d6e3e5c947c 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -53,6 +53,7 @@ import com.android.server.notification.NotificationManagerService.DumpFilter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
@@ -547,14 +548,14 @@ abstract public class ManagedServices {
loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
}
- final ArrayList<ManagedServiceInfo> toRemove = new ArrayList<>();
- final SparseArray<ArrayList<ComponentName>> toAdd = new SparseArray<>();
+ final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
+ final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
synchronized (mMutex) {
- // Unbind automatically bound services, retain system services.
+ // Potentially unbind automatically bound services, retain system services.
for (ManagedServiceInfo service : mServices) {
if (!service.isSystem && !service.isGuest(this)) {
- toRemove.add(service);
+ removableBoundServices.add(service);
}
}
@@ -565,11 +566,11 @@ abstract public class ManagedServices {
// decode the list of components
final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
if (null == userComponents) {
- toAdd.put(userIds[i], new ArrayList<ComponentName>());
+ toAdd.put(userIds[i], new HashSet<ComponentName>());
continue;
}
- final ArrayList<ComponentName> add = new ArrayList<>(userComponents);
+ final Set<ComponentName> add = new HashSet<>(userComponents);
// Remove components from disabled categories so that those services aren't run.
for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
@@ -594,19 +595,26 @@ abstract public class ManagedServices {
mEnabledServicesPackageNames = newPackages;
}
- for (ManagedServiceInfo info : toRemove) {
+ for (ManagedServiceInfo info : removableBoundServices) {
final ComponentName component = info.component;
final int oldUser = info.userid;
- Slog.v(TAG, "disabling " + getCaption() + " for user "
- + oldUser + ": " + component);
- unregisterService(component, info.userid);
+ final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
+ if (allowedComponents != null) {
+ if (allowedComponents.contains(component)) {
+ // Already bound, don't need to bind again.
+ allowedComponents.remove(component);
+ } else {
+ // No longer allowed to be bound.
+ Slog.v(TAG, "disabling " + getCaption() + " for user "
+ + oldUser + ": " + component);
+ unregisterService(component, oldUser);
+ }
+ }
}
for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
- final int N = add.size();
- for (int j = 0; j < N; j++) {
- final ComponentName component = add.get(j);
+ final Set<ComponentName> add = toAdd.get(userIds[i]);
+ for (ComponentName component : add) {
Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
+ component);
registerService(component, userIds[i]);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bf8e8fb4eb47..e4c3c1432167 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,7 +16,6 @@
package com.android.server.notification;
-import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL;
import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL;
@@ -31,14 +30,14 @@ import static android.service.notification.NotificationAssistantService.REASON_P
import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_SUSPENDED;
import static android.service.notification.NotificationAssistantService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationAssistantService.REASON_TOPIC_BANNED;
import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -460,7 +459,7 @@ public class NotificationManagerService extends SystemService {
/** Use this to check if a package can post a notification or toast. */
private boolean checkNotificationOp(String pkg, int uid) {
return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
- == AppOpsManager.MODE_ALLOWED && !isApplicationSuspended(pkg, uid);
+ == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
}
private static final class ToastRecord
@@ -754,7 +753,7 @@ public class NotificationManagerService extends SystemService {
for (String pkgName : pkgList) {
if (cancelNotifications) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
- changeUserId, reason, null, null);
+ changeUserId, reason, null);
}
}
}
@@ -787,14 +786,14 @@ public class NotificationManagerService extends SystemService {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
- REASON_USER_STOPPED, null, null);
+ REASON_USER_STOPPED, null);
}
} else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (inQuietMode && userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
- REASON_PROFILE_TURNED_OFF, null, null);
+ REASON_PROFILE_TURNED_OFF, null);
}
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
// turn off LED when user passes through lock screen
@@ -1086,7 +1085,7 @@ public class NotificationManagerService extends SystemService {
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
- REASON_PACKAGE_BANNED, null, null);
+ REASON_PACKAGE_BANNED, null);
}
}
@@ -1133,14 +1132,14 @@ public class NotificationManagerService extends SystemService {
}
final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
- final boolean isApplicationSuspended =
- isApplicationSuspended(pkg, Binder.getCallingUid());
+ final boolean isPackageSuspended =
+ isPackageSuspendedForUser(pkg, Binder.getCallingUid());
if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
- || isApplicationSuspended)) {
+ || isPackageSuspended)) {
if (!isSystemToast) {
Slog.e(TAG, "Suppressing toast from package " + pkg
- + (isApplicationSuspended
+ + (isPackageSuspended
? " due to package suspended by administrator."
: " by user request."));
return;
@@ -1250,7 +1249,7 @@ public class NotificationManagerService extends SystemService {
// running foreground services.
cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
- REASON_APP_CANCEL_ALL, null, null);
+ REASON_APP_CANCEL_ALL, null);
}
@Override
@@ -1264,80 +1263,65 @@ public class NotificationManagerService extends SystemService {
* Use this when you just want to know if notifications are OK for this package.
*/
@Override
- public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
- checkCallerIsSystem();
- return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
- == AppOpsManager.MODE_ALLOWED) && !isApplicationSuspended(pkg, uid);
- }
-
- @Override
- public boolean hasBannedTopics(String pkg, int uid) {
- checkCallerIsSystem();
- return mRankingHelper.hasBannedTopics(pkg, uid);
+ public boolean areNotificationsEnabled(String pkg) {
+ return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
}
+ /**
+ * Use this when you just want to know if notifications are OK for this package.
+ */
@Override
- public ParceledListSlice<Notification.Topic> getTopics(String pkg, int uid) {
- checkCallerIsSystem();
- return new ParceledListSlice<Notification.Topic>(mRankingHelper.getTopics(pkg, uid));
+ public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
+ checkCallerIsSystemOrSameApp(pkg);
+ return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
+ == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
}
@Override
- public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) {
+ public void setPriority(String pkg, int uid, int priority) {
checkCallerIsSystem();
- mRankingHelper.setPriority(pkg, uid, topic, priority);
+ mRankingHelper.setPriority(pkg, uid, priority);
savePolicyFile();
}
@Override
- public int getPriority(String pkg, int uid, Notification.Topic topic) {
+ public int getPriority(String pkg, int uid) {
checkCallerIsSystem();
- return mRankingHelper.getPriority(pkg, uid, topic);
+ return mRankingHelper.getPriority(pkg, uid);
}
@Override
- public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic,
- int visibility) {
+ public void setVisibilityOverride(String pkg, int uid, int visibility) {
checkCallerIsSystem();
- mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility);
+ mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
savePolicyFile();
}
@Override
- public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
+ public int getVisibilityOverride(String pkg, int uid) {
checkCallerIsSystem();
- return mRankingHelper.getVisibilityOverride(pkg, uid, topic);
+ return mRankingHelper.getVisibilityOverride(pkg, uid);
}
@Override
- public void setImportance(String pkg, int uid, Notification.Topic topic,
- int importance) {
+ public void setImportance(String pkg, int uid, int importance) {
enforceSystemOrSystemUI("Caller not system or systemui");
- if (topic == null) {
- // App wide, potentially store block in app ops.
- setNotificationsEnabledForPackageImpl(pkg, uid,
- importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
- } else {
- if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
- UserHandle.getUserId(uid),
- REASON_TOPIC_BANNED, topic, null);
- }
- }
- mRankingHelper.setImportance(pkg, uid, topic, importance);
+ setNotificationsEnabledForPackageImpl(pkg, uid,
+ importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
+ mRankingHelper.setImportance(pkg, uid, importance);
savePolicyFile();
}
@Override
- public int getImportance(String pkg, int uid, Notification.Topic topic) {
- checkCallerIsSystem();
- return mRankingHelper.getImportance(pkg, uid, topic);
+ public int getPackageImportance(String pkg) {
+ checkCallerIsSystemOrSameApp(pkg);
+ return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
}
@Override
- public boolean doesAppUseTopics(String pkg, int uid) {
- enforceSystemOrSystemUI("Caller not system or systemui");
- return mRankingHelper.doesAppUseTopics(pkg, uid);
+ public int getImportance(String pkg, int uid) {
+ checkCallerIsSystem();
+ return mRankingHelper.getImportance(pkg, uid);
}
/**
@@ -2001,6 +1985,9 @@ public class NotificationManagerService extends SystemService {
@Override
public void setImportanceFromAssistant(INotificationListener token, String key,
int importance, CharSequence explanation) throws RemoteException {
+ if (importance == IMPORTANCE_NONE) {
+ throw new IllegalArgumentException("blocking not allowed: key=" + key);
+ }
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
@@ -2320,7 +2307,7 @@ public class NotificationManagerService extends SystemService {
synchronized (mNotificationList) {
final StatusBarNotification n = r.sbn;
- Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
+ if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
NotificationRecord old = mNotificationsByKey.get(n.getKey());
if (old != null) {
// Retain ranking information from previous record
@@ -2341,7 +2328,7 @@ public class NotificationManagerService extends SystemService {
handleGroupedNotificationLocked(r, old, callingUid, callingPid);
boolean ignoreNotification =
removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
- Slog.d(TAG, "ignoreNotification is " + ignoreNotification);
+ if (DBG) Slog.d(TAG, "ignoreNotification is " + ignoreNotification);
// This conditional is a dirty hack to limit the logging done on
// behalf of the download manager without affecting other apps.
@@ -2364,15 +2351,13 @@ public class NotificationManagerService extends SystemService {
mRankingHelper.extractSignals(r);
- // why is this here?
- savePolicyFile();
- final boolean isApplicationSuspended = isApplicationSuspended(pkg, callingUid);
+ final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
- // blocked apps/topics
+ // blocked apps
if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
- || !noteNotificationOp(pkg, callingUid) || isApplicationSuspended) {
+ || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
if (!isSystemNotification) {
- if (isApplicationSuspended) {
+ if (isPackageSuspended) {
Slog.e(TAG, "Suppressing notification from package due to package "
+ "suspended by administrator.");
mUsageStats.registerSuspendedByAdmin(r);
@@ -2539,7 +2524,7 @@ public class NotificationManagerService extends SystemService {
final Notification notification = record.sbn.getNotification();
// Should this notification make noise, vibe, or use the LED?
- final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_HIGH;
+ final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
if (DBG || record.isIntercepted())
Slog.v(TAG,
@@ -3165,11 +3150,11 @@ public class NotificationManagerService extends SystemService {
}
/**
- * Cancels all notifications from a given package or topic that have all of the
+ * Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
*/
boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
- int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic,
+ int mustNotHaveFlags, boolean doit, int userId, int reason,
ManagedServiceInfo listener) {
String listenerName = listener == null ? null : listener.component.toShortString();
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
@@ -3197,10 +3182,6 @@ public class NotificationManagerService extends SystemService {
if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
continue;
}
- if (topic != null
- && !topic.getId().equals(r.getNotification().getTopic().getId())) {
- continue;
- }
if (canceledNotifications == null) {
canceledNotifications = new ArrayList<>();
}
@@ -3474,22 +3455,13 @@ public class NotificationManagerService extends SystemService {
return true;
}
- private boolean isApplicationSuspended(String pkg, int uid) {
+ private boolean isPackageSuspendedForUser(String pkg, int uid) {
int userId = UserHandle.getUserId(uid);
- ApplicationInfo ai;
try {
- // TODO: it might be faster to return a boolean from package manager rather than the
- // whole application info. Revisit and make the API change.
- ai = AppGlobals.getPackageManager().getApplicationInfo(pkg, 0, userId);
- if (ai == null) {
- Slog.w(TAG, "No application info for package " + pkg + " and user " + userId);
- return false;
- }
+ return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
} catch (RemoteException re) {
throw new SecurityException("Could not talk to package manager service");
}
-
- return ((ai.flags & FLAG_SUSPENDED) != 0);
}
private class TrimCache {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 484b0e95b359..fd893fa081a5 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MIN;
import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
@@ -23,17 +24,20 @@ import static android.service.notification.NotificationListenerService.Ranking.I
import android.app.Notification;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
+import android.os.Build;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
@@ -54,6 +58,8 @@ import java.util.Objects;
* {@hide}
*/
public final class NotificationRecord {
+ static final String TAG = "NotificationRecord";
+ static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
final StatusBarNotification sbn;
final int mOriginalFlags;
private final Context mContext;
@@ -90,12 +96,12 @@ public final class NotificationRecord {
private int mAuthoritativeRank;
private String mGlobalSortKey;
private int mPackageVisibility;
- private int mTopicImportance = IMPORTANCE_UNSPECIFIED;
+ private int mUserImportance = IMPORTANCE_UNSPECIFIED;
private int mImportance = IMPORTANCE_UNSPECIFIED;
private CharSequence mImportanceExplanation = null;
private int mSuppressedVisualEffects = 0;
- private String mTopicExplanation;
+ private String mUserExplanation;
private String mPeopleExplanation;
@VisibleForTesting
@@ -122,6 +128,8 @@ public final class NotificationRecord {
switch (n.priority) {
case Notification.PRIORITY_MIN:
+ importance = IMPORTANCE_MIN;
+ break;
case Notification.PRIORITY_LOW:
importance = IMPORTANCE_LOW;
break;
@@ -142,8 +150,15 @@ public final class NotificationRecord {
|| n.sound != null
|| n.vibrate != null;
stats.isNoisy = isNoisy;
- if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
- importance = IMPORTANCE_DEFAULT;
+
+ if (!isNoisy && importance > IMPORTANCE_LOW) {
+ importance = IMPORTANCE_LOW;
+ }
+
+ if (isNoisy) {
+ if (importance < IMPORTANCE_DEFAULT) {
+ importance = IMPORTANCE_DEFAULT;
+ }
}
if (n.fullScreenIntent != null) {
@@ -164,7 +179,7 @@ public final class NotificationRecord {
mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
mCreationTimeMs = previous.mCreationTimeMs;
mVisibleSinceMs = previous.mVisibleSinceMs;
- mTopicImportance = previous.mTopicImportance;
+ mUserImportance = previous.mUserImportance;
mImportance = previous.mImportance;
mImportanceExplanation = previous.mImportanceExplanation;
// Don't copy mGlobalSortKey, recompute it.
@@ -209,12 +224,14 @@ public final class NotificationRecord {
final int N = notification.actions.length;
for (int i=0; i<N; i++) {
final Notification.Action action = notification.actions[i];
- pw.println(String.format("%s [%d] \"%s\" -> %s",
- prefix,
- i,
- action.title,
- action.actionIntent.toString()
- ));
+ if (action != null) {
+ pw.println(String.format("%s [%d] \"%s\" -> %s",
+ prefix,
+ i,
+ action.title,
+ action.actionIntent == null ? "null" : action.actionIntent.toString()
+ ));
+ }
}
pw.println(prefix + " }");
}
@@ -256,8 +273,8 @@ public final class NotificationRecord {
pw.println(prefix + " mRecentlyIntrusive=" + mRecentlyIntrusive);
pw.println(prefix + " mPackagePriority=" + mPackagePriority);
pw.println(prefix + " mPackageVisibility=" + mPackageVisibility);
- pw.println(prefix + " mTopicImportance="
- + NotificationListenerService.Ranking.importanceToString(mTopicImportance));
+ pw.println(prefix + " mUserImportance="
+ + NotificationListenerService.Ranking.importanceToString(mUserImportance));
pw.println(prefix + " mImportance="
+ NotificationListenerService.Ranking.importanceToString(mImportance));
pw.println(prefix + " mImportanceExplanation=" + mImportanceExplanation);
@@ -338,17 +355,17 @@ public final class NotificationRecord {
return mPackageVisibility;
}
- public void setTopicImportance(int importance) {
- mTopicImportance = importance;
- applyTopicImportance();
+ public void setUserImportance(int importance) {
+ mUserImportance = importance;
+ applyUserImportance();
}
- private String getTopicExplanation() {
- if (mTopicExplanation == null) {
- mTopicExplanation =
- mContext.getString(com.android.internal.R.string.importance_from_topic);
+ private String getUserExplanation() {
+ if (mUserExplanation == null) {
+ mUserExplanation =
+ mContext.getString(com.android.internal.R.string.importance_from_user);
}
- return mTopicExplanation;
+ return mUserExplanation;
}
private String getPeopleExplanation() {
@@ -359,15 +376,15 @@ public final class NotificationRecord {
return mPeopleExplanation;
}
- private void applyTopicImportance() {
- if (mTopicImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
- mImportance = mTopicImportance;
- mImportanceExplanation = getTopicExplanation();
+ private void applyUserImportance() {
+ if (mUserImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
+ mImportance = mUserImportance;
+ mImportanceExplanation = getUserExplanation();
}
}
- public int getTopicImportance() {
- return mTopicImportance;
+ public int getUserImportance() {
+ return mUserImportance;
}
public void setImportance(int importance, CharSequence explanation) {
@@ -375,7 +392,7 @@ public final class NotificationRecord {
mImportance = importance;
mImportanceExplanation = explanation;
}
- applyTopicImportance();
+ applyUserImportance();
}
public int getImportance() {
@@ -510,6 +527,6 @@ public final class NotificationRecord {
}
public boolean isImportanceFromUser() {
- return mImportance == mTopicImportance;
+ return mImportance == mUserImportance;
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 027285087de3..538f95146efc 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -597,8 +597,9 @@ public class NotificationUsageStats {
private static class ImportanceHistogram {
// TODO define these somewhere else
- private static final int NUM_IMPORTANCES = 5;
- private static final String[] IMPORTANCE_NAMES = {"none", "low", "default", "high", "max"};
+ private static final int NUM_IMPORTANCES = 6;
+ private static final String[] IMPORTANCE_NAMES =
+ {"none", "min", "low", "default", "high", "max"};
private final Context mContext;
private final String[] mCounterNames;
private final String mPrefix;
diff --git a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java b/services/core/java/com/android/server/notification/PriorityExtractor.java
index 1df5c2b5fb2a..6c764761d738 100644
--- a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/PriorityExtractor.java
@@ -21,7 +21,7 @@ import android.util.Slog;
/**
* Determines if the given notification can bypass Do Not Disturb.
*/
-public class TopicPriorityExtractor implements NotificationSignalExtractor {
+public class PriorityExtractor implements NotificationSignalExtractor {
private static final String TAG = "ImportantTopicExtractor";
private static final boolean DBG = false;
@@ -42,9 +42,8 @@ public class TopicPriorityExtractor implements NotificationSignalExtractor {
return null;
}
- final int packagePriority = mConfig.getPriority(record.sbn.getPackageName(),
- record.sbn.getUid(), record.sbn.getNotification().getTopic());
- record.setPackagePriority(packagePriority);
+ record.setPackagePriority(
+ mConfig.getPriority(record.sbn.getPackageName(), record.sbn.getUid()));
return null;
}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 1a7e3550d8e3..b5cc2efcabc2 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -15,28 +15,17 @@
*/
package com.android.server.notification;
-import android.app.Notification;
-
-import java.util.List;
-
public interface RankingConfig {
- List<Notification.Topic> getTopics(String packageName, int uid);
-
- int getPriority(String packageName, int uid, Notification.Topic topic);
-
- void setPriority(String packageName, int uid, Notification.Topic topic, int priority);
-
- int getVisibilityOverride(String packageName, int uid, Notification.Topic topic);
+ int getPriority(String packageName, int uid);
- void setVisibilityOverride(String packageName, int uid, Notification.Topic topic,
- int visibility);
+ void setPriority(String packageName, int uid, int priority);
- void setImportance(String packageName, int uid, Notification.Topic topic, int importance);
+ int getVisibilityOverride(String packageName, int uid);
- int getImportance(String packageName, int uid, Notification.Topic topic);
+ void setVisibilityOverride(String packageName, int uid, int visibility);
- boolean doesAppUseTopics(String packageName, int uid);
+ void setImportance(String packageName, int uid, int importance);
- boolean hasBannedTopics(String packageName, int uid);
+ int getImportance(String packageName, int uid);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index aa36e298bb45..fd96a784122f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -25,8 +25,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
-import com.android.internal.R;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -35,8 +33,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
-import java.util.Map;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -46,7 +42,6 @@ public class RankingHelper implements RankingConfig {
private static final String TAG_RANKING = "ranking";
private static final String TAG_PACKAGE = "package";
private static final String ATT_VERSION = "version";
- private static final String TAG_TOPIC = "topic";
private static final String ATT_NAME = "name";
private static final String ATT_UID = "uid";
@@ -140,8 +135,6 @@ public class RankingHelper implements RankingConfig {
if (type == XmlPullParser.START_TAG) {
if (TAG_PACKAGE.equals(tag)) {
int uid = safeInt(parser, ATT_UID, Record.UNKNOWN_UID);
- int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
- int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
@@ -164,16 +157,8 @@ public class RankingHelper implements RankingConfig {
r = getOrCreateRecord(name, uid);
}
r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
- r.priority = priority;
- r.visibility = vis;
-
- // Migrate package level settings to the default topic.
- // Might be overwritten by parseTopics.
- Topic defaultTopic = r.topics.get(Notification.TOPIC_DEFAULT);
- defaultTopic.priority = priority;
- defaultTopic.visibility = vis;
-
- parseTopics(r, parser);
+ r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
+ r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
}
}
}
@@ -181,42 +166,6 @@ public class RankingHelper implements RankingConfig {
throw new IllegalStateException("Failed to reach END_DOCUMENT");
}
- public void parseTopics(Record r, XmlPullParser parser)
- throws XmlPullParserException, IOException {
- final int innerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (TAG_TOPIC.equals(tagName)) {
- int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
- int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
- int importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
- String id = parser.getAttributeValue(null, ATT_TOPIC_ID);
- CharSequence label = parser.getAttributeValue(null, ATT_TOPIC_LABEL);
-
- if (!TextUtils.isEmpty(id)) {
- Topic topic = new Topic(new Notification.Topic(id, label));
-
- if (priority != DEFAULT_PRIORITY) {
- topic.priority = priority;
- }
- if (vis != DEFAULT_VISIBILITY) {
- topic.visibility = vis;
- }
- if (importance != DEFAULT_IMPORTANCE) {
- topic.importance = importance;
- }
- r.topics.put(id, topic);
- }
- }
- }
- }
-
private static String recordKey(String pkg, int uid) {
return pkg + "|" + uid;
}
@@ -228,7 +177,6 @@ public class RankingHelper implements RankingConfig {
r = new Record();
r.pkg = pkg;
r.uid = uid;
- r.topics.put(Notification.TOPIC_DEFAULT, new Topic(createDefaultTopic()));
mRecords.put(key, r);
}
return r;
@@ -245,44 +193,29 @@ public class RankingHelper implements RankingConfig {
if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
continue;
}
- out.startTag(null, TAG_PACKAGE);
- out.attribute(null, ATT_NAME, r.pkg);
- if (r.importance != DEFAULT_IMPORTANCE) {
- out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
- }
- if (r.priority != DEFAULT_PRIORITY) {
- out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
- }
- if (r.visibility != DEFAULT_VISIBILITY) {
- out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
- }
-
- if (!forBackup) {
- out.attribute(null, ATT_UID, Integer.toString(r.uid));
- }
+ final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
+ || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY;
+ if (hasNonDefaultSettings) {
+ out.startTag(null, TAG_PACKAGE);
+ out.attribute(null, ATT_NAME, r.pkg);
+ if (r.importance != DEFAULT_IMPORTANCE) {
+ out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+ }
+ if (r.priority != DEFAULT_PRIORITY) {
+ out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+ }
+ if (r.visibility != DEFAULT_VISIBILITY) {
+ out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+ }
- writeTopicsXml(out, r);
- out.endTag(null, TAG_PACKAGE);
- }
- out.endTag(null, TAG_RANKING);
- }
+ if (!forBackup) {
+ out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ }
- public void writeTopicsXml(XmlSerializer out, Record r) throws IOException {
- for (Topic t : r.topics.values()) {
- out.startTag(null, TAG_TOPIC);
- out.attribute(null, ATT_TOPIC_ID, t.topic.getId());
- out.attribute(null, ATT_TOPIC_LABEL, t.topic.getLabel().toString());
- if (t.priority != DEFAULT_PRIORITY) {
- out.attribute(null, ATT_PRIORITY, Integer.toString(t.priority));
- }
- if (t.visibility != DEFAULT_VISIBILITY) {
- out.attribute(null, ATT_VISIBILITY, Integer.toString(t.visibility));
+ out.endTag(null, TAG_PACKAGE);
}
- if (t.importance != DEFAULT_IMPORTANCE) {
- out.attribute(null, ATT_IMPORTANCE, Integer.toString(t.importance));
- }
- out.endTag(null, TAG_TOPIC);
}
+ out.endTag(null, TAG_RANKING);
}
private void updateConfig() {
@@ -369,172 +302,62 @@ public class RankingHelper implements RankingConfig {
}
}
- private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
- final String val = parser.getAttributeValue(null, att);
- return tryParseBool(val, defValue);
- }
-
private static boolean tryParseBool(String value, boolean defValue) {
if (TextUtils.isEmpty(value)) return defValue;
return Boolean.valueOf(value);
}
- @Override
- public List<Notification.Topic> getTopics(String packageName, int uid) {
- final Record r = getOrCreateRecord(packageName, uid);
- List<Notification.Topic> topics = new ArrayList<>();
- for (Topic t : r.topics.values()) {
- topics.add(t.topic);
- }
- return topics;
- }
-
- @Override
- public boolean hasBannedTopics(String packageName, int uid) {
- final Record r = getOrCreateRecord(packageName, uid);
- for (Topic t : r.topics.values()) {
- if (t.importance == Ranking.IMPORTANCE_NONE) {
- return true;
- }
- }
- return false;
- }
-
/**
- * Gets priority. If a topic is given, returns the priority of that topic. Otherwise, the
- * priority of the app.
+ * Gets priority.
*/
@Override
- public int getPriority(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- return r.priority;
- }
- return getOrCreateTopic(r, topic).priority;
+ public int getPriority(String packageName, int uid) {
+ return getOrCreateRecord(packageName, uid).priority;
}
/**
- * Sets priority. If a topic is given, sets the priority of that topic. If not,
- * sets the default priority for all new topics that appear in the future, and resets
- * the priority of all current topics.
+ * Sets priority.
*/
@Override
- public void setPriority(String packageName, int uid, Notification.Topic topic,
- int priority) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- r.priority = priority;
- for (Topic t : r.topics.values()) {
- t.priority = priority;
- }
- } else {
- getOrCreateTopic(r, topic).priority = priority;
- }
+ public void setPriority(String packageName, int uid, int priority) {
+ getOrCreateRecord(packageName, uid).priority = priority;
updateConfig();
}
/**
- * Gets visual override. If a topic is given, returns the override of that topic. Otherwise, the
- * override of the app.
+ * Gets visual override.
*/
@Override
- public int getVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- return r.visibility;
- }
- return getOrCreateTopic(r, topic).visibility;
+ public int getVisibilityOverride(String packageName, int uid) {
+ return getOrCreateRecord(packageName, uid).visibility;
}
/**
- * Sets visibility override. If a topic is given, sets the override of that topic. If not,
- * sets the default override for all new topics that appear in the future, and resets
- * the override of all current topics.
+ * Sets visibility override.
*/
@Override
- public void setVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
- int visibility) {
- final Record r = getOrCreateRecord(pkgName, uid);
- if (topic == null) {
- r.visibility = visibility;
- for (Topic t : r.topics.values()) {
- t.visibility = visibility;
- }
- } else {
- getOrCreateTopic(r, topic).visibility = visibility;
- }
+ public void setVisibilityOverride(String pkgName, int uid, int visibility) {
+ getOrCreateRecord(pkgName, uid).visibility = visibility;
updateConfig();
}
/**
- * Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
- * importance of the app.
+ * Gets importance.
*/
@Override
- public int getImportance(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- return r.importance;
- }
- return getOrCreateTopic(r, topic).importance;
+ public int getImportance(String packageName, int uid) {
+ return getOrCreateRecord(packageName, uid).importance;
}
/**
- * Sets importance. If a topic is given, sets the importance of that topic. If not, sets the
- * default importance for all new topics that appear in the future, and resets
- * the importance of all current topics (unless the app is being blocked).
+ * Sets importance.
*/
@Override
- public void setImportance(String pkgName, int uid, Notification.Topic topic,
- int importance) {
- final Record r = getOrCreateRecord(pkgName, uid);
- if (topic == null) {
- r.importance = importance;
- if (Ranking.IMPORTANCE_NONE != importance) {
- for (Topic t : r.topics.values()) {
- t.importance = importance;
- }
- }
- } else {
- getOrCreateTopic(r, topic).importance = importance;
- }
+ public void setImportance(String pkgName, int uid, int importance) {
+ getOrCreateRecord(pkgName, uid).importance = importance;
updateConfig();
}
- @Override
- public boolean doesAppUseTopics(String pkgName, int uid) {
- final Record r = getOrCreateRecord(pkgName, uid);
- int numTopics = r.topics.size();
- if (numTopics == 0
- || (numTopics == 1 && r.topics.containsKey(Notification.TOPIC_DEFAULT))) {
- return false;
- } else {
- return true;
- }
- }
-
- private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
- if (topic == null) {
- topic = createDefaultTopic();
- }
- Topic t = r.topics.get(topic.getId());
- if (t != null) {
- return t;
- } else {
- t = new Topic(topic);
- t.importance = r.importance;
- t.priority = r.priority;
- t.visibility = r.visibility;
- r.topics.put(topic.getId(), t);
- return t;
- }
- }
-
- private Notification.Topic createDefaultTopic() {
- return new Notification.Topic(Notification.TOPIC_DEFAULT,
- mContext.getString(R.string.default_notification_topic_label));
- }
-
public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
if (filter == null) {
final int N = mSignalExtractors.length;
@@ -582,25 +405,6 @@ public class RankingHelper implements RankingConfig {
pw.print(Ranking.importanceToString(r.visibility));
}
pw.println();
- for (Topic t : r.topics.values()) {
- pw.print(prefix);
- pw.print(" ");
- pw.print(" ");
- pw.print(t.topic.getId());
- if (t.priority != DEFAULT_PRIORITY) {
- pw.print(" priority=");
- pw.print(Notification.priorityToString(t.priority));
- }
- if (t.visibility != DEFAULT_VISIBILITY) {
- pw.print(" visibility=");
- pw.print(Notification.visibilityToString(t.visibility));
- }
- if (t.importance != DEFAULT_IMPORTANCE) {
- pw.print(" importance=");
- pw.print(Ranking.importanceToString(t.importance));
- }
- pw.println();
- }
}
}
}
@@ -639,17 +443,5 @@ public class RankingHelper implements RankingConfig {
int importance = DEFAULT_IMPORTANCE;
int priority = DEFAULT_PRIORITY;
int visibility = DEFAULT_VISIBILITY;
- Map<String, Topic> topics = new ArrayMap<>();
}
-
- private static class Topic {
- Notification.Topic topic;
- int priority = DEFAULT_PRIORITY;
- int visibility = DEFAULT_VISIBILITY;
- int importance = DEFAULT_IMPORTANCE;
-
- public Topic(Notification.Topic topic) {
- this.topic = topic;
- }
- }
}
diff --git a/services/core/java/com/android/server/notification/ScheduleCalendar.java b/services/core/java/com/android/server/notification/ScheduleCalendar.java
index cea611d8ca6d..4c57c1dc0e94 100644
--- a/services/core/java/com/android/server/notification/ScheduleCalendar.java
+++ b/services/core/java/com/android/server/notification/ScheduleCalendar.java
@@ -40,16 +40,12 @@ public class ScheduleCalendar {
updateDays();
}
- public long nextScheduleStart(long time) {
- if (mSchedule == null || mDays.size() == 0) return Long.MAX_VALUE;
- final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
- for (int i = 0; i < Calendar.SATURDAY; i++) {
- final long t = addDays(start, i);
- if (t > time && isInSchedule(t)) {
- return t;
+ public void maybeSetNextAlarm(long now, long nextAlarm) {
+ if (mSchedule != null) {
+ if (mSchedule.exitAtAlarm && now > mSchedule.nextAlarm) {
+ mSchedule.nextAlarm = nextAlarm;
}
}
- return Long.MAX_VALUE;
}
public void setTimeZone(TimeZone tz) {
@@ -60,7 +56,13 @@ public class ScheduleCalendar {
if (mSchedule == null) return 0;
final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute);
- return Math.min(nextStart, nextEnd);
+ long nextScheduleTime = Math.min(nextStart, nextEnd);
+
+ if (mSchedule.exitAtAlarm && mSchedule.nextAlarm > now) {
+ return Math.min(nextScheduleTime, mSchedule.nextAlarm);
+ } else {
+ return nextScheduleTime;
+ }
}
private long getNextTime(long now, int hr, int min) {
@@ -84,7 +86,15 @@ public class ScheduleCalendar {
if (end <= start) {
end = addDays(end, 1);
}
- return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
+ boolean isInSchedule =
+ isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
+ if (isInSchedule && mSchedule.exitAtAlarm
+ && mSchedule.nextAlarm != 0
+ && time >= mSchedule.nextAlarm) {
+ return false;
+ } else {
+ return isInSchedule;
+ }
}
private boolean isInSchedule(int daysOffset, long time, long start, long end) {
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index c9b0ebbfa469..8d0ad96be44e 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -28,7 +29,7 @@ import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
-import android.util.ArraySet;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -42,7 +43,7 @@ import java.util.TimeZone;
*/
public class ScheduleConditionProvider extends SystemConditionProviderService {
private static final String TAG = "ConditionProviders.SCP";
- private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
+ private static final boolean DEBUG = true || Log.isLoggable("ConditionProviders", Log.DEBUG);
public static final ComponentName COMPONENT =
new ComponentName("android", ScheduleConditionProvider.class.getName());
@@ -53,8 +54,9 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
private static final String EXTRA_TIME = "time";
private final Context mContext = this;
- private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
+ private final ArrayMap<Uri, ScheduleCalendar> mSubscriptions = new ArrayMap<>();
+ private AlarmManager mAlarmManager;
private boolean mConnected;
private boolean mRegistered;
private long mNextAlarmTime;
@@ -80,9 +82,9 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
pw.print(" mRegistered="); pw.println(mRegistered);
pw.println(" mSubscriptions=");
final long now = System.currentTimeMillis();
- for (Uri conditionId : mSubscriptions) {
+ for (Uri conditionId : mSubscriptions.keySet()) {
pw.print(" ");
- pw.print(meetsSchedule(conditionId, now) ? "* " : " ");
+ pw.print(meetsSchedule(mSubscriptions.get(conditionId), now) ? "* " : " ");
pw.println(conditionId);
}
dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
@@ -113,7 +115,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
return;
}
- mSubscriptions.add(conditionId);
+ mSubscriptions.put(conditionId, toScheduleCalendar(conditionId));
evaluateSubscriptions();
}
@@ -135,13 +137,18 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
}
private void evaluateSubscriptions() {
+ if (mAlarmManager == null) {
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ }
setRegistered(!mSubscriptions.isEmpty());
final long now = System.currentTimeMillis();
mNextAlarmTime = 0;
- for (Uri conditionId : mSubscriptions) {
- final ScheduleCalendar cal = toScheduleCalendar(conditionId);
+ long nextUserAlarmTime = getNextAlarm();
+ for (Uri conditionId : mSubscriptions.keySet()) {
+ final ScheduleCalendar cal = mSubscriptions.get(conditionId);
if (cal != null && cal.isInSchedule(now)) {
notifyCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
+ cal.maybeSetNextAlarm(now, nextUserAlarmTime);
} else {
notifyCondition(conditionId, Condition.STATE_FALSE, "!meetsSchedule");
}
@@ -175,8 +182,13 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
}
}
- private static boolean meetsSchedule(Uri conditionId, long time) {
- final ScheduleCalendar cal = toScheduleCalendar(conditionId);
+ public long getNextAlarm() {
+ final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(
+ ActivityManager.getCurrentUser());
+ return info != null ? info.getTriggerTime() : 0;
+ }
+
+ private static boolean meetsSchedule(ScheduleCalendar cal, long time) {
return cal != null && cal.isInSchedule(time);
}
@@ -198,6 +210,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(ACTION_EVALUATE);
+ filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
registerReceiver(mReceiver, filter);
} else {
unregisterReceiver(mReceiver);
diff --git a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java b/services/core/java/com/android/server/notification/VisibilityExtractor.java
index eaa3ed3623e1..2da2b2f3c264 100644
--- a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/VisibilityExtractor.java
@@ -21,8 +21,8 @@ import android.util.Slog;
/**
* Determines if the given notification can display sensitive content on the lockscreen.
*/
-public class TopicVisibilityExtractor implements NotificationSignalExtractor {
- private static final String TAG = "TopicVisibilityExtractor";
+public class VisibilityExtractor implements NotificationSignalExtractor {
+ private static final String TAG = "VisibilityExtractor";
private static final boolean DBG = false;
private RankingConfig mConfig;
@@ -42,10 +42,8 @@ public class TopicVisibilityExtractor implements NotificationSignalExtractor {
return null;
}
- final int packageVisibility = mConfig.getVisibilityOverride(
- record.sbn.getPackageName(), record.sbn.getUid(),
- record.sbn.getNotification().getTopic());
- record.setPackageVisibilityOverride(packageVisibility);
+ record.setPackageVisibilityOverride(
+ mConfig.getVisibilityOverride(record.sbn.getPackageName(), record.sbn.getUid()));
return null;
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index bba0d402c90e..383c1ab5ebef 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -578,7 +578,8 @@ public class ZenModeHelper {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
try {
- mPm.getPackageInfo(rule.component.getPackageName(), 0);
+ mPm.getPackageInfo(rule.component.getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (PackageManager.NameNotFoundException e) {
newConfig.automaticRules.removeAt(i);
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 6c338c184e4a..9a5a183233e2 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -35,6 +35,7 @@ import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.Telephony.Sms.Intents;
+import android.telephony.TelephonyManager;
import android.security.Credentials;
import android.util.ArraySet;
import android.util.Log;
@@ -124,7 +125,6 @@ final class DefaultPermissionGrantPolicy {
private final PackageManagerService mService;
- private PackagesProvider mImePackagesProvider;
private PackagesProvider mLocationPackagesProvider;
private PackagesProvider mVoiceInteractionPackagesProvider;
private PackagesProvider mSmsAppPackagesProvider;
@@ -136,10 +136,6 @@ final class DefaultPermissionGrantPolicy {
mService = service;
}
- public void setImePackagesProviderLPr(PackagesProvider provider) {
- mImePackagesProvider = provider;
- }
-
public void setLocationPackagesProviderLPw(PackagesProvider provider) {
mLocationPackagesProvider = provider;
}
@@ -198,7 +194,6 @@ final class DefaultPermissionGrantPolicy {
private void grantDefaultSystemHandlerPermissions(int userId) {
Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
- final PackagesProvider imePackagesProvider;
final PackagesProvider locationPackagesProvider;
final PackagesProvider voiceInteractionPackagesProvider;
final PackagesProvider smsAppPackagesProvider;
@@ -207,7 +202,6 @@ final class DefaultPermissionGrantPolicy {
final SyncAdapterPackagesProvider syncAdapterPackagesProvider;
synchronized (mService.mPackages) {
- imePackagesProvider = mImePackagesProvider;
locationPackagesProvider = mLocationPackagesProvider;
voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
smsAppPackagesProvider = mSmsAppPackagesProvider;
@@ -216,8 +210,6 @@ final class DefaultPermissionGrantPolicy {
syncAdapterPackagesProvider = mSyncAdapterPackagesProvider;
}
- String[] imePackageNames = (imePackagesProvider != null)
- ? imePackagesProvider.getPackages(userId) : null;
String[] voiceInteractPackageNames = (voiceInteractionPackagesProvider != null)
? voiceInteractionPackagesProvider.getPackages(userId) : null;
String[] locationPackageNames = (locationPackagesProvider != null)
@@ -262,6 +254,7 @@ final class DefaultPermissionGrantPolicy {
grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(setupPackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(setupPackage, CAMERA_PERMISSIONS, userId);
}
// Camera
@@ -499,17 +492,6 @@ final class DefaultPermissionGrantPolicy {
grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS, userId);
}
- // IME
- if (imePackageNames != null) {
- for (String imePackageName : imePackageNames) {
- PackageParser.Package imePackage = getSystemPackageLPr(imePackageName);
- if (imePackage != null
- && doesPackageSupportRuntimePermissions(imePackage)) {
- grantRuntimePermissionsLPw(imePackage, CONTACTS_PERMISSIONS, userId);
- }
- }
- }
-
// Voice interaction
if (voiceInteractPackageNames != null) {
for (String voiceInteractPackageName : voiceInteractPackageNames) {
@@ -576,7 +558,7 @@ final class DefaultPermissionGrantPolicy {
}
// Android Wear Home
- if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
@@ -603,6 +585,16 @@ final class DefaultPermissionGrantPolicy {
grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
}
+ // EmergencyInfo
+ Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
+ PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackageLPr(
+ emergencyInfoIntent, userId);
+ if (emergencyInfoPckg != null
+ && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
+ grantRuntimePermissionsLPw(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
+ grantRuntimePermissionsLPw(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
+ }
+
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
@@ -611,7 +603,7 @@ final class DefaultPermissionGrantPolicy {
PackageParser.Package dialerPackage, int userId) {
if (doesPackageSupportRuntimePermissions(dialerPackage)) {
boolean isPhonePermFixed =
- mService.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
grantRuntimePermissionsLPw(
dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId);
diff --git a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
index 878635083b3a..389e0a15bfb9 100644
--- a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
+++ b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
@@ -210,6 +210,9 @@ class EphemeralApplicationRegistry {
}
public void onPackageUninstalledLPw(PackageParser.Package pkg) {
+ if (pkg == null) {
+ return;
+ }
PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d82bb3d1ed9f..8d75f603928e 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -201,8 +201,7 @@ public class LauncherAppsService extends SystemService {
long ident = Binder.clearCallingIdentity();
try {
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return new ParceledListSlice<>(apps);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -220,7 +219,7 @@ public class LauncherAppsService extends SystemService {
long ident = Binder.clearCallingIdentity();
try {
ResolveInfo app = mPm.resolveActivityAsUser(intent,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return app;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -239,7 +238,7 @@ public class LauncherAppsService extends SystemService {
try {
IPackageManager pm = AppGlobals.getPackageManager();
PackageInfo info = pm.getPackageInfo(packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return info != null && info.applicationInfo.enabled;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -277,7 +276,7 @@ public class LauncherAppsService extends SystemService {
try {
IPackageManager pm = AppGlobals.getPackageManager();
ActivityInfo info = pm.getActivityInfo(component,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
return info != null;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -303,7 +302,7 @@ public class LauncherAppsService extends SystemService {
try {
IPackageManager pm = AppGlobals.getPackageManager();
ActivityInfo info = pm.getActivityInfo(component,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
if (!info.exported) {
throw new SecurityException("Cannot launch non-exported components "
+ component);
@@ -313,7 +312,7 @@ public class LauncherAppsService extends SystemService {
// as calling startActivityAsUser ignores the category and just
// resolves based on the component if present.
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.getIdentifier());
final int size = apps.size();
for (int i = 0; i < size; ++i) {
ActivityInfo activityInfo = apps.get(i).activityInfo;
@@ -347,8 +346,7 @@ public class LauncherAppsService extends SystemService {
String packageName = component.getPackageName();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setSourceBounds(sourceBounds);
mContext.startActivityAsUser(intent, opts, user);
} finally {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index da62a2d6fc84..94b3b2d613cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -55,8 +55,6 @@ import static com.android.server.pm.Installer.DEXOPT_OTA;
public class OtaDexoptService extends IOtaDexopt.Stub {
private final static String TAG = "OTADexopt";
private final static boolean DEBUG_DEXOPT = true;
- // Apps used in the last 7 days.
- private final static long DEXOPT_LRU_THRESHOLD_IN_MINUTES = 7 * 24 * 60;
private final Context mContext;
private final PackageDexOptimizer mPackageDexOptimizer;
@@ -94,69 +92,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
if (mDexoptPackages != null) {
throw new IllegalStateException("already called prepare()");
}
-
- mDexoptPackages = new LinkedList<>();
-
- ArrayList<PackageParser.Package> pkgs;
synchronized (mPackageManagerService.mPackages) {
- pkgs = new ArrayList<PackageParser.Package>(mPackageManagerService.mPackages.values());
- }
-
- // Sort apps by importance for dexopt ordering. Important apps are given more priority
- // in case the device runs out of space.
-
- // Give priority to core apps.
- for (PackageParser.Package pkg : pkgs) {
- if (pkg.coreApp) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding core app " + mDexoptPackages.size() + ": " + pkg.packageName);
- }
- mDexoptPackages.add(pkg);
- }
- }
- pkgs.removeAll(mDexoptPackages);
-
- // Give priority to system apps that listen for pre boot complete.
- Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
- ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- for (PackageParser.Package pkg : pkgs) {
- if (pkgNames.contains(pkg.packageName)) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding pre boot system app " + mDexoptPackages.size() + ": " +
- pkg.packageName);
- }
- mDexoptPackages.add(pkg);
- }
- }
- pkgs.removeAll(mDexoptPackages);
-
- // Filter out packages that aren't recently used, add all remaining apps.
- // TODO: add a property to control this?
- if (mPackageManagerService.isHistoricalPackageUsageAvailable()) {
- filterRecentlyUsedApps(pkgs, DEXOPT_LRU_THRESHOLD_IN_MINUTES * 60 * 1000);
- }
- mDexoptPackages.addAll(pkgs);
-
- // Now go ahead and also add the libraries required for these packages.
- // TODO: Think about interleaving things.
- Set<PackageParser.Package> dependencies = new HashSet<>();
- for (PackageParser.Package p : mDexoptPackages) {
- dependencies.addAll(mPackageManagerService.findSharedNonSystemLibraries(p));
- }
- if (!dependencies.isEmpty()) {
- dependencies.removeAll(mDexoptPackages);
- }
- mDexoptPackages.addAll(dependencies);
-
- if (DEBUG_DEXOPT) {
- StringBuilder sb = new StringBuilder();
- for (PackageParser.Package pkg : mDexoptPackages) {
- if (sb.length() > 0) {
- sb.append(", ");
- }
- sb.append(pkg.packageName);
- }
- Log.i(TAG, "Packages to be optimized: " + sb.toString());
+ mDexoptPackages = PackageManagerServiceUtils.getPackagesForDexopt(
+ mPackageManagerService.mPackages.values(), mPackageManagerService);
}
}
@@ -228,29 +166,6 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
return pkgNames;
}
- private void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
- long dexOptLRUThresholdInMills) {
- // Filter out packages that aren't recently used.
- int total = pkgs.size();
- int skipped = 0;
- long now = System.currentTimeMillis();
- for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
- PackageParser.Package pkg = i.next();
- long then = pkg.mLastPackageUsageTimeInMills;
- if (then + dexOptLRUThresholdInMills < now) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
- ((then == 0) ? "never" : new Date(then)));
- }
- i.remove();
- skipped++;
- }
- }
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
- }
- }
-
private static class OTADexoptPackageDexOptimizer extends
PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 23a58d06eed1..928c19fa84be 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -212,8 +212,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
mCallbacks = new Callbacks(mInstallThread.getLooper());
mSessionsFile = new AtomicFile(
- new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
- mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
+ new File(Environment.getDataSystemDirectory(), "install_sessions.xml"));
+ mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
mSessionsDir.mkdirs();
synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c8645b467ca2..998869472c17 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -65,6 +65,7 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
@@ -99,7 +100,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
@@ -141,7 +141,6 @@ import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
-import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageStats;
@@ -265,7 +264,6 @@ import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
-import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@@ -1421,160 +1419,33 @@ public class PackageManagerService extends IPackageManager.Stub {
PostInstallData data = mRunningInstalls.get(msg.arg1);
mRunningInstalls.delete(msg.arg1);
- boolean deleteOld = false;
if (data != null) {
InstallArgs args = data.args;
- PackageInstalledInfo res = data.res;
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- //TODO: Broadcast for child packages too
- final String packageName = res.pkg.applicationInfo.packageName;
- res.removedInfo.sendBroadcast(false, true, false);
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, res.uid);
-
- // Now that we successfully installed the package, grant runtime
- // permissions if requested before broadcasting the install.
- if ((args.installFlags
- & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
- && res.pkg.applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.M) {
- grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),
- args.installGrantPermissions);
- }
-
- synchronized (mPackages) {
- mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
- }
-
- // Determine the set of users who are adding this
- // package for the first time vs. those who are seeing
- // an update.
- int[] firstUsers;
- int[] updateUsers = new int[0];
- if (res.origUsers == null || res.origUsers.length == 0) {
- firstUsers = res.newUsers;
- } else {
- firstUsers = new int[0];
- for (int i=0; i<res.newUsers.length; i++) {
- int user = res.newUsers[i];
- boolean isNew = true;
- for (int j=0; j<res.origUsers.length; j++) {
- if (res.origUsers[j] == user) {
- isNew = false;
- break;
- }
- }
- if (isNew) {
- int[] newFirst = new int[firstUsers.length+1];
- System.arraycopy(firstUsers, 0, newFirst, 0,
- firstUsers.length);
- newFirst[firstUsers.length] = user;
- firstUsers = newFirst;
- } else {
- int[] newUpdate = new int[updateUsers.length+1];
- System.arraycopy(updateUsers, 0, newUpdate, 0,
- updateUsers.length);
- newUpdate[updateUsers.length] = user;
- updateUsers = newUpdate;
- }
- }
- }
- // don't broadcast for ephemeral installs/updates
- final boolean isEphemeral = isEphemeral(res.pkg);
- if (!isEphemeral) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/, null /*targetPackage*/,
- null /*finishedReceiver*/, firstUsers);
- }
- final boolean update = res.removedInfo.removedPackage != null;
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
- if (!isEphemeral) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0 /*flags*/, null /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
- }
- if (update) {
- if (!isEphemeral) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUsers);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null /*package*/, null /*extras*/, 0 /*flags*/,
- packageName /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
- }
-
- // treat asec-hosted packages like removable media on upgrade
- if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.pkg
- + " is ASEC-hosted -> AVAILABLE");
- }
- int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
- ArrayList<String> pkgList = new ArrayList<String>(1);
- pkgList.add(packageName);
- sendResourcesChangedBroadcast(true, true,
- pkgList,uidArray, null);
- }
- }
- if (res.removedInfo.args != null) {
- // Remove the replaced package's older resources safely now
- deleteOld = true;
- }
-
-
- // Work that needs to happen on first install within each user
- if (firstUsers.length > 0) {
- for (int userId : firstUsers) {
- synchronized (mPackages) {
- // If this app is a browser and it's newly-installed for
- // some users, clear any default-browser state in those
- // users. The app's nature doesn't depend on the user,
- // so we can just check its browser nature in any user
- // and generalize.
- if (packageIsBrowser(packageName, firstUsers[0])) {
- mSettings.setDefaultBrowserPackageNameLPw(
- null, userId);
- }
-
- // We may also need to apply pending (restored) runtime
- // permission grants within these users.
- mSettings.applyPendingPermissionGrantsLPw(
- packageName, userId);
- }
- }
- }
- // Log current value of "unknown sources" setting
- EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
- getUnknownSourcesSettings());
- }
- // Force a gc to clear up things
- Runtime.getRuntime().gc();
- // We delete after a gc for applications on sdcard.
- if (deleteOld) {
- synchronized (mInstallLock) {
- res.removedInfo.args.doPostDeleteLI(true);
- }
- }
- if (args.observer != null) {
- try {
- Bundle extras = extrasForInstallResult(res);
- args.observer.onPackageInstalled(res.name, res.returnCode,
- res.returnMsg, extras);
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
+ PackageInstalledInfo parentRes = data.res;
+
+ final boolean grantPermissions = (args.installFlags
+ & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+ final String[] grantedPermissions = args.installGrantPermissions;
+
+ // Handle the parent package
+ handlePackagePostInstall(parentRes, grantPermissions, grantedPermissions,
+ args.observer);
+
+ // Handle the child packages
+ final int childCount = (parentRes.addedChildPackages != null)
+ ? parentRes.addedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
+ handlePackagePostInstall(childRes, grantPermissions, grantedPermissions,
+ args.observer);
}
+
+ // Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
- return;
} else {
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
@@ -1761,6 +1632,185 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
+ String[] grantedPermissions, IPackageInstallObserver2 installObserver) {
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ // Send the removed broadcasts
+ if (res.removedInfo != null) {
+ res.removedInfo.sendPackageRemovedBroadcasts();
+ }
+
+ // Now that we successfully installed the package, grant runtime
+ // permissions if requested before broadcasting the install.
+ if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.M) {
+ grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
+ }
+
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
+
+ // If this is the first time we have child packages for a disabled privileged
+ // app that had no children, we grant requested runtime permissions to the new
+ // children if the parent on the system image had them already granted.
+ if (res.pkg.parentPackage != null) {
+ synchronized (mPackages) {
+ grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
+ }
+ }
+
+ synchronized (mPackages) {
+ mEphemeralApplicationRegistry.onPackageInstalledLPw(res.pkg);
+ }
+
+ final String packageName = res.pkg.applicationInfo.packageName;
+ Bundle extras = new Bundle(1);
+ extras.putInt(Intent.EXTRA_UID, res.uid);
+
+ // Determine the set of users who are adding this package for
+ // the first time vs. those who are seeing an update.
+ int[] firstUsers = EMPTY_INT_ARRAY;
+ int[] updateUsers = EMPTY_INT_ARRAY;
+ if (res.origUsers == null || res.origUsers.length == 0) {
+ firstUsers = res.newUsers;
+ } else {
+ for (int newUser : res.newUsers) {
+ boolean isNew = true;
+ for (int origUser : res.origUsers) {
+ if (origUser == newUser) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ } else {
+ updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
+ }
+ }
+ }
+
+ // Send installed broadcasts if the install/update is not ephemeral
+ if (!isEphemeral(res.pkg)) {
+ // Send added for users that see the package for the first time
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/, null /*targetPackage*/,
+ null /*finishedReceiver*/, firstUsers);
+
+ // Send added for users that don't see the package for the first time
+ if (update) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/, null /*targetPackage*/,
+ null /*finishedReceiver*/, updateUsers);
+
+ // Send replaced for users that don't see the package for the first time
+ if (update) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ packageName, extras, 0 /*flags*/,
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUsers);
+ sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
+ null /*package*/, null /*extras*/, 0 /*flags*/,
+ packageName /*targetPackage*/,
+ null /*finishedReceiver*/, updateUsers);
+ }
+
+ // Send broadcast package appeared if forward locked/external for all users
+ // treat asec-hosted packages like removable media on upgrade
+ if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
+ if (DEBUG_INSTALL) {
+ Slog.i(TAG, "upgrading pkg " + res.pkg
+ + " is ASEC-hosted -> AVAILABLE");
+ }
+ final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
+ ArrayList<String> pkgList = new ArrayList<>(1);
+ pkgList.add(packageName);
+ sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
+ }
+ }
+
+ // Work that needs to happen on first install within each user
+ if (firstUsers != null && firstUsers.length > 0) {
+ synchronized (mPackages) {
+ for (int userId : firstUsers) {
+ // If this app is a browser and it's newly-installed for some
+ // users, clear any default-browser state in those users. The
+ // app's nature doesn't depend on the user, so we can just check
+ // its browser nature in any user and generalize.
+ if (packageIsBrowser(packageName, userId)) {
+ mSettings.setDefaultBrowserPackageNameLPw(null, userId);
+ }
+
+ // We may also need to apply pending (restored) runtime
+ // permission grants within these users.
+ mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
+ }
+ }
+ }
+
+ // Log current value of "unknown sources" setting
+ EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
+ getUnknownSourcesSettings());
+
+ // Force a gc to clear up things
+ Runtime.getRuntime().gc();
+
+ // Remove the replaced package's older resources safely now
+ // We delete after a gc for applications on sdcard.
+ if (res.removedInfo != null && res.removedInfo.args != null) {
+ synchronized (mInstallLock) {
+ res.removedInfo.args.doPostDeleteLI(true);
+ }
+ }
+ }
+
+ // If someone is watching installs - notify them
+ if (installObserver != null) {
+ try {
+ Bundle extras = extrasForInstallResult(res);
+ installObserver.onPackageInstalled(res.name, res.returnCode,
+ res.returnMsg, extras);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+
+ private void grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(
+ PackageParser.Package pkg) {
+ if (pkg.parentPackage == null) {
+ return;
+ }
+ if (pkg.requestedPermissions == null) {
+ return;
+ }
+ final PackageSetting disabledSysParentPs = mSettings
+ .getDisabledSystemPkgLPr(pkg.parentPackage.packageName);
+ if (disabledSysParentPs == null || disabledSysParentPs.pkg == null
+ || !disabledSysParentPs.isPrivileged()
+ || (disabledSysParentPs.childPackageNames != null
+ && !disabledSysParentPs.childPackageNames.isEmpty())) {
+ return;
+ }
+ final int[] allUserIds = sUserManager.getUserIds();
+ final int permCount = pkg.requestedPermissions.size();
+ for (int i = 0; i < permCount; i++) {
+ String permission = pkg.requestedPermissions.get(i);
+ BasePermission bp = mSettings.mPermissions.get(permission);
+ if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
+ continue;
+ }
+ for (int userId : allUserIds) {
+ if (disabledSysParentPs.getPermissionsState().hasRuntimePermission(
+ permission, userId)) {
+ grantRuntimePermission(pkg.packageName, permission, userId);
+ }
+ }
+ }
+ }
+
private StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
@@ -1815,18 +1865,10 @@ public class PackageManagerService extends IPackageManager.Stub {
}
};
- private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId,
+ private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
String[] grantedPermissions) {
- if (userId >= UserHandle.USER_SYSTEM) {
+ for (int userId : userIds) {
grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
- } else if (userId == UserHandle.USER_ALL) {
- final int[] userIds;
- synchronized (mPackages) {
- userIds = UserManagerService.getInstance().getUserIds();
- }
- for (int someUserId : userIds) {
- grantRequestedRuntimePermissionsForUser(pkg, someUserId, grantedPermissions);
- }
}
// We could have touched GID membership, so flush out packages.list
@@ -2229,7 +2271,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
+ scannedPkg.mVersionCode);
- removePackageSettingLI(scannedPkg, true);
+ removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
@@ -2407,33 +2449,6 @@ public class PackageManagerService extends IPackageManager.Stub {
reconcileAppsData(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
storageFlags);
- if (!StorageManager.isFileBasedEncryptionEnabled()
- && PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
- // When upgrading a non-FBE device, we might need to shuffle
- // around the default storage location of system apps
- final List<UserInfo> users = sUserManager.getUsers(true);
- for (PackageSetting ps : mSettings.mPackages.values()) {
- if (ps.pkg == null || !ps.isSystem()) continue;
- final int storageTarget = ps.pkg.applicationInfo.isForceDeviceEncrypted()
- ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
- for (UserInfo user : users) {
- if (ps.getInstalled(user.id)) {
- try {
- mInstaller.migrateAppData(StorageManager.UUID_PRIVATE_INTERNAL,
- ps.name, user.id, storageTarget);
- } catch (InstallerException e) {
- logCriticalInfo(Log.WARN,
- "Failed to migrate " + ps.name + ": " + e.getMessage());
- }
- // We may have just shuffled around app data
- // directories, so prepare it one more time
- prepareAppData(StorageManager.UUID_PRIVATE_INTERNAL, user.id,
- storageFlags, ps.pkg, false);
- }
- }
- }
- }
-
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
if (mIsUpgrade && !onlyCore) {
@@ -2855,6 +2870,10 @@ public class PackageManagerService extends IPackageManager.Stub {
throw new SecurityException("Package " + packageName + " was not found!");
}
+ if (mSafeMode && !ps.isSystem()) {
+ throw new SecurityException("Package " + packageName + " not a system app!");
+ }
+
if (ps.frozen) {
throw new SecurityException("Package " + packageName + " is currently frozen!");
}
@@ -3234,12 +3253,6 @@ public class PackageManagerService extends IPackageManager.Stub {
flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
}
}
-
- // Safe mode means we should ignore any third-party apps
- if (mSafeMode) {
- flags |= PackageManager.MATCH_SYSTEM_ONLY;
- }
-
return flags;
}
@@ -3299,6 +3312,7 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
+ " with flags 0x" + Integer.toHexString(flags), new Throwable());
}
+
return updateFlags(flags, userId);
}
@@ -3306,6 +3320,11 @@ public class PackageManagerService extends IPackageManager.Stub {
* Update given flags when being used to request {@link ResolveInfo}.
*/
int updateFlagsForResolve(int flags, int userId, Object cookie) {
+ // Safe mode means we shouldn't match any third-party components
+ if (mSafeMode) {
+ flags |= PackageManager.MATCH_SYSTEM_ONLY;
+ }
+
return updateFlagsForComponent(flags, userId, cookie);
}
@@ -3427,6 +3446,18 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public @Nullable String getServicesSystemSharedLibraryPackageName() {
+ synchronized (mPackages) {
+ SharedLibraryEntry libraryEntry = mSharedLibraries.get(
+ PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
+ if (libraryEntry != null) {
+ return libraryEntry.apk;
+ }
+ }
+ return null;
+ }
+
+ @Override
public FeatureInfo[] getSystemAvailableFeatures() {
Collection<FeatureInfo> featSet;
synchronized (mPackages) {
@@ -3446,9 +3477,14 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public boolean hasSystemFeature(String name) {
+ public boolean hasSystemFeature(String name, int version) {
synchronized (mPackages) {
- return mAvailableFeatures.containsKey(name);
+ final FeatureInfo feat = mAvailableFeatures.get(name);
+ if (feat == null) {
+ return false;
+ } else {
+ return feat.version >= version;
+ }
}
}
@@ -4181,7 +4217,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} else if (actionName != null) {
// TODO: remove these terrible hacks
if (actionName.startsWith("android.net.netmon.lingerExpired")
- || actionName.startsWith("com.android.server.sip.SipWakeupTimer")) {
+ || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
+ || actionName.startsWith("com.android.internal.telephony.data-reconnect")) {
return true;
}
}
@@ -4937,8 +4974,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// cross-profile app linking works only towards the parent.
final UserInfo parent = getProfileParent(sourceUserId);
synchronized(mPackages) {
+ int flags = updateFlagsForResolve(0, parent.id, intent);
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
- intent, resolvedType, 0, sourceUserId, parent.id);
+ intent, resolvedType, flags, sourceUserId, parent.id);
return xpDomainInfo != null;
}
}
@@ -6564,7 +6602,7 @@ public class PackageManagerService extends IPackageManager.Stub {
!= PackageManager.SIGNATURE_MATCH) {
logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+ " signatures don't match existing userdata copy; removing");
- deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false, null);
+ deletePackageLI(pkg.packageName, null, true, null, 0, null, false, null);
ps = null;
} else {
/*
@@ -6765,31 +6803,38 @@ public class PackageManagerService extends IPackageManager.Stub {
// Extract pacakges only if profile-guided compilation is enabled because
// otherwise BackgroundDexOptService will not dexopt them later.
- if (mUseJitProfiles) {
- ArraySet<String> pkgs = getOptimizablePackages();
- if (pkgs != null) {
- for (String pkg : pkgs) {
- performDexOpt(pkg, null /* instructionSet */, false /* useProfiles */,
- true /* extractOnly */, false /* force */);
- }
- }
+ if (!mUseJitProfiles || !isUpgrade()) {
+ return;
}
- }
- private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
- List<ResolveInfo> ris = null;
- try {
- ris = AppGlobals.getPackageManager().queryIntentReceivers(
- intent, null, 0, userId);
- } catch (RemoteException e) {
+ List<PackageParser.Package> pkgs;
+ synchronized (mPackages) {
+ pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
- ArraySet<String> pkgNames = new ArraySet<String>();
- if (ris != null) {
- for (ResolveInfo ri : ris) {
- pkgNames.add(ri.activityInfo.packageName);
+
+ int curr = 0;
+ int total = pkgs.size();
+ for (PackageParser.Package pkg : pkgs) {
+ curr++;
+
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
+ }
+
+ if (!isFirstBoot()) {
+ try {
+ ActivityManagerNative.getDefault().showBootMessage(
+ mContext.getResources().getString(R.string.android_upgrading_apk,
+ curr, total), true);
+ } catch (RemoteException e) {
+ }
+ }
+
+ if (PackageDexOptimizer.canOptimizePackage(pkg)) {
+ performDexOpt(pkg.packageName, null /* instructionSet */,
+ false /* useProfiles */, true /* extractOnly */, false /* force */);
}
}
- return pkgNames;
}
@Override
@@ -8220,7 +8265,7 @@ public class PackageManagerService extends IPackageManager.Stub {
*
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
- public void derivePackageAbi(PackageParser.Package pkg, File scanFile,
+ private void derivePackageAbi(PackageParser.Package pkg, File scanFile,
String cpuAbiOverride, boolean extractLibs)
throws PackageManagerException {
// TODO: We can probably be smarter about this stuff. For installed apps,
@@ -8301,16 +8346,17 @@ public class PackageManagerService extends IPackageManager.Stub {
if (abi32 >= 0) {
final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
if (abi64 >= 0) {
- pkg.applicationInfo.secondaryCpuAbi = abi;
+ if (cpuAbiOverride == null && pkg.use32bitAbi) {
+ pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
+ pkg.applicationInfo.primaryCpuAbi = abi;
+ } else {
+ pkg.applicationInfo.secondaryCpuAbi = abi;
+ }
} else {
pkg.applicationInfo.primaryCpuAbi = abi;
}
}
- if (cpuAbiOverride != null &&
- cpuAbiOverride.equals(pkg.applicationInfo.secondaryCpuAbi)) {
- pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
- pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
- }
+
} else {
String[] abiList = (cpuAbiOverride != null) ?
new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
@@ -8720,11 +8766,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- private void removePackageSettingLI(PackageParser.Package pkg, boolean chatty) {
+ private void removePackageLI(PackageParser.Package pkg, boolean chatty) {
// Remove the parent package setting
PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps != null) {
- removePackageSettingLI(ps, chatty);
+ removePackageLI(ps, chatty);
}
// Remove the child package setting
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -8732,12 +8778,12 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package childPkg = pkg.childPackages.get(i);
ps = (PackageSetting) childPkg.mExtras;
if (ps != null) {
- removePackageSettingLI(ps, chatty);
+ removePackageLI(ps, chatty);
}
}
}
- void removePackageSettingLI(PackageSetting ps, boolean chatty) {
+ void removePackageLI(PackageSetting ps, boolean chatty) {
if (DEBUG_INSTALL) {
if (chatty)
Log.d(TAG, "Removing package " + ps.name);
@@ -10438,16 +10484,21 @@ public class PackageManagerService extends IPackageManager.Stub {
mHandler.sendMessage(msg);
}
- private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting, int userId) {
+ private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
+ int userId) {
+ final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
+ sendPackageAddedForUser(packageName, isSystem, pkgSetting.appId, userId);
+ }
+
+ private void sendPackageAddedForUser(String packageName, boolean isSystem,
+ int appId, int userId) {
Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
+ extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, appId));
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0, null, null, new int[] {userId});
try {
IActivityManager am = ActivityManagerNative.getDefault();
- final boolean isSystem =
- isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
if (isSystem && am.isUserRunning(userId, 0)) {
// The just-installed/enabled app is bundled on the system, so presumed
// to be able to run automatically without needing an explicit launch.
@@ -10520,7 +10571,7 @@ public class PackageManagerService extends IPackageManager.Stub {
info.removedPackage = packageName;
info.removedUsers = new int[] {userId};
info.uid = UserHandle.getUid(userId, pkgSetting.appId);
- info.sendBroadcast(false, false, false);
+ info.sendPackageRemovedBroadcasts();
}
private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
@@ -10590,14 +10641,14 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgSetting.setInstalled(true, userId);
pkgSetting.setHidden(false, userId);
mSettings.writePackageRestrictionsLPr(userId);
- if (pkgSetting.pkg != null) {
- prepareAppDataAfterInstall(pkgSetting.pkg);
- }
installed = true;
}
}
if (installed) {
+ if (pkgSetting.pkg != null) {
+ prepareAppDataAfterInstall(pkgSetting.pkg);
+ }
sendPackageAddedForUser(packageName, pkgSetting, userId);
}
} finally {
@@ -10617,47 +10668,110 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+ int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true,
- "setPackageSuspended for user " + userId);
+ "setPackagesSuspended for user " + userId);
- // TODO: investigate and add more restrictions for suspending crucial packages.
- if (isPackageDeviceAdmin(packageName, userId)) {
- Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
- + "\": has active device admin");
- return false;
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return packageNames;
}
- long callingId = Binder.clearCallingIdentity();
- try {
- boolean changed = false;
- boolean success = false;
- int appId = -1;
- synchronized (mPackages) {
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting != null) {
+ // List of package names for whom the suspended state has changed.
+ List<String> changedPackages = new ArrayList<>(packageNames.length);
+ // List of package names for whom the suspended state is not set as requested in this
+ // method.
+ List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+ for (int i = 0; i < packageNames.length; i++) {
+ String packageName = packageNames[i];
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ boolean changed = false;
+ final int appId;
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null) {
+ Slog.w(TAG, "Could not find package setting for package \"" + packageName
+ + "\". Skipping suspending/un-suspending.");
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ appId = pkgSetting.appId;
if (pkgSetting.getSuspended(userId) != suspended) {
+ if (!canSuspendPackageForUserLocked(packageName, userId)) {
+ unactionedPackages.add(packageName);
+ continue;
+ }
pkgSetting.setSuspended(suspended, userId);
mSettings.writePackageRestrictionsLPr(userId);
- appId = pkgSetting.appId;
changed = true;
+ changedPackages.add(packageName);
}
- success = true;
}
- }
- if (changed) {
- sendPackagesSuspendedForUser(new String[]{packageName}, userId, suspended);
- if (suspended) {
+ if (changed && suspended) {
killApplication(packageName, UserHandle.getUid(userId, appId),
"suspending package");
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
- return success;
- } finally {
- Binder.restoreCallingIdentity(callingId);
}
+
+ if (!changedPackages.isEmpty()) {
+ sendPackagesSuspendedForUser(changedPackages.toArray(
+ new String[changedPackages.size()]), userId, suspended);
+ }
+
+ return unactionedPackages.toArray(new String[unactionedPackages.size()]);
+ }
+
+ @Override
+ public boolean isPackageSuspendedForUser(String packageName, int userId) {
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true,
+ false, "isPackageSuspendedForUser for user " + userId);
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ return pkgSetting != null && pkgSetting.getSuspended(userId);
+ }
+ }
+
+ // TODO: investigate and add more restrictions for suspending crucial packages.
+ private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
+ if (isPackageDeviceAdmin(packageName, userId)) {
+ Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
+ + "\": has active device admin");
+ return false;
+ }
+
+ String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+ if (packageName.equals(activeLauncherPackageName)) {
+ Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
+ + "\" because it is set as the active launcher");
+ return false;
+ }
+
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null && isPrivilegedApp(pkg)) {
+ Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
+ + "\" because it is a privileged app");
+ return false;
+ }
+
+ return true;
+ }
+
+ private String getActiveLauncherPackageName(int userId) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = resolveIntent(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ userId);
+
+ return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
}
@Override
@@ -11071,10 +11185,10 @@ public class PackageManagerService extends IPackageManager.Stub {
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
- res.returnCode = currentStatus;
+ res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
- res.removedInfo = new PackageRemovedInfo();
+ res.removedInfo = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
@@ -11086,7 +11200,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
- final boolean update = res.removedInfo.removedPackage != null;
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
@@ -11432,20 +11547,41 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
// reader
synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null) {
- if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
- // Check for downgrading.
- if ((installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) {
- try {
- checkDowngrade(pkg, pkgLite);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Downgrade detected: " + e.getMessage());
- return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
- }
+ // Currently installed package which the new package is attempting to replace or
+ // null if no such package is installed.
+ PackageParser.Package installedPkg = mPackages.get(packageName);
+ // Package which currently owns the data which the new package will own if installed.
+ // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
+ // will be null whereas dataOwnerPkg will contain information about the package
+ // which was uninstalled while keeping its data.
+ PackageParser.Package dataOwnerPkg = installedPkg;
+ if (dataOwnerPkg == null) {
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ dataOwnerPkg = ps.pkg;
+ }
+ }
+
+ if (dataOwnerPkg != null) {
+ // If installed, the package will get access to data left on the device by its
+ // predecessor. As a security measure, this is permited only if this is not a
+ // version downgrade or if the predecessor package is marked as debuggable and
+ // a downgrade is explicitly requested.
+ if (((dataOwnerPkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0)
+ || ((installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0)) {
+ try {
+ checkDowngrade(dataOwnerPkg, pkgLite);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Downgrade detected: " + e.getMessage());
+ return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
}
+ }
+ }
+
+ if (installedPkg != null) {
+ if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// Check for updated system application.
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
if (onSd) {
Slog.w(TAG, "Cannot install update to system app on sdcard");
return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION;
@@ -11464,7 +11600,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// App explictly prefers external. Let policy decide
} else {
// Prefer previous location
- if (isExternal(pkg)) {
+ if (isExternal(installedPkg)) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
@@ -12675,25 +12811,42 @@ public class PackageManagerService extends IPackageManager.Stub {
int returnCode;
String returnMsg;
PackageRemovedInfo removedInfo;
+ ArrayMap<String, PackageInstalledInfo> addedChildPackages;
public void setError(int code, String msg) {
- returnCode = code;
- returnMsg = msg;
+ setReturnCode(code);
+ setReturnMessage(msg);
Slog.w(TAG, msg);
}
public void setError(String msg, PackageParserException e) {
- returnCode = e.error;
- returnMsg = ExceptionUtils.getCompleteMessage(msg, e);
+ setReturnCode(e.error);
+ setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
public void setError(String msg, PackageManagerException e) {
returnCode = e.error;
- returnMsg = ExceptionUtils.getCompleteMessage(msg, e);
+ setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ addedChildPackages.valueAt(i).returnCode = returnCode;
+ }
+ }
+
+ private void setReturnMessage(String returnMsg) {
+ this.returnMsg = returnMsg;
+ final int childCount = (addedChildPackages != null) ? addedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ addedChildPackages.valueAt(i).returnMsg = returnMsg;
+ }
+ }
+
// In some error cases we want to convey more info back to the observer
String origPackage;
String origPermission;
@@ -12711,9 +12864,6 @@ public class PackageManagerService extends IPackageManager.Stub {
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
- // TODO: b/23350563
- final boolean dataDirExists = Environment
- .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_SYSTEM, pkgName).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
@@ -12738,21 +12888,17 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
- prepareAppDataAfterInstall(newPackage);
+ updateSettingsLI(newPackage, installerPackageName, null, res, user);
- // delete the partially installed application. the data directory will have to be
- // restored if it was already existing
- if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- // remove package from internal structures. Note that we want deletePackageX to
- // delete the package data and cache directories that it created in
- // scanPackageLocked, unless those directories existed before we even tried to
- // install.
- deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
- dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
- res.removedInfo, true, null);
- }
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ prepareAppDataAfterInstall(newPackage);
+ } else {
+ // Remove package from internal structures, but keep around any
+ // data that might have already existed
+ deletePackageLI(pkgName, UserHandle.ALL, false, null,
+ PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
+ }
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
@@ -12797,14 +12943,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
- UserHandle user, String installerPackageName, String volumeUuid,
- PackageInstalledInfo res) {
+ UserHandle user, String installerPackageName, PackageInstalledInfo res) {
final boolean isEphemeral = (parseFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
final PackageParser.Package oldPackage;
final String pkgName = pkg.packageName;
final int[] allUsers;
- final boolean[] perUserInstalled;
// First find the old package info and check signatures
synchronized(mPackages) {
@@ -12813,7 +12957,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isEphemeral && !oldIsEphemeral) {
// can't downgrade from full to ephemeral
Slog.w(TAG, "Can't replace app with ephemeral: " + pkgName);
- res.returnCode = PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
+ res.setReturnCode(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID);
return;
}
if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
@@ -12837,26 +12981,58 @@ public class PackageManagerService extends IPackageManager.Stub {
// In case of rollback, remember per-user/profile install state
allUsers = sUserManager.getUserIds();
- perUserInstalled = new boolean[allUsers.length];
- for (int i = 0; i < allUsers.length; i++) {
- perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
+ }
+
+ // Update what is removed
+ res.removedInfo = new PackageRemovedInfo();
+ res.removedInfo.uid = oldPackage.applicationInfo.uid;
+ res.removedInfo.removedPackage = oldPackage.packageName;
+ res.removedInfo.isUpdate = true;
+ final int childCount = (oldPackage.childPackages != null)
+ ? oldPackage.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ boolean childPackageUpdated = false;
+ PackageParser.Package childPkg = oldPackage.childPackages.get(i);
+ if (res.addedChildPackages != null) {
+ PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
+ if (childRes != null) {
+ childRes.removedInfo.uid = childPkg.applicationInfo.uid;
+ childRes.removedInfo.removedPackage = childPkg.packageName;
+ childRes.removedInfo.isUpdate = true;
+ childPackageUpdated = true;
+ }
+ }
+ if (!childPackageUpdated) {
+ PackageRemovedInfo childRemovedRes = new PackageRemovedInfo();
+ childRemovedRes.removedPackage = childPkg.packageName;
+ childRemovedRes.isUpdate = false;
+ childRemovedRes.dataRemoved = true;
+ synchronized (mPackages) {
+ PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
+ }
+ }
+ if (res.removedInfo.removedChildPackages == null) {
+ res.removedInfo.removedChildPackages = new ArrayMap<>();
+ }
+ res.removedInfo.removedChildPackages.put(childPkg.packageName, childRemovedRes);
}
}
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
- user, allUsers, perUserInstalled, installerPackageName, res);
+ user, allUsers, installerPackageName, res);
} else {
replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
- user, allUsers, perUserInstalled, installerPackageName, res);
+ user, allUsers, installerPackageName, res);
}
}
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
- int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
- PackageInstalledInfo res) {
+ int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
+ deletedPackage);
@@ -12868,7 +13044,7 @@ public class PackageManagerService extends IPackageManager.Stub {
? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
// First delete the existing package while retaining the data directory
- if (!deletePackageLI(pkgName, null, true, null, null, PackageManager.DELETE_KEEP_DATA,
+ if (!deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
res.removedInfo, true, pkg)) {
// If the existing package wasn't successfully deleted
res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
@@ -12893,8 +13069,7 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, allUsers,
- perUserInstalled, res, user);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
prepareAppDataAfterInstall(newPackage);
addedPkg = true;
} catch (PackageManagerException e) {
@@ -12907,8 +13082,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Revert all internal state mutations and added folders for the failed install
if (addedPkg) {
- deletePackageLI(pkgName, null, true, allUsers, perUserInstalled,
- PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
+ deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+ res.removedInfo, true, null);
}
// Restore the old package
@@ -12942,13 +13117,34 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
}
+ } else {
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.peekPackageLPr(pkg.packageName);
+ if (ps != null) {
+ res.removedInfo.removedForAllUsers = mPackages.get(ps.name) == null;
+ if (res.removedInfo.removedChildPackages != null) {
+ final int childCount = res.removedInfo.removedChildPackages.size();
+ // Iterate in reverse as we may modify the collection
+ for (int i = childCount - 1; i >= 0; i--) {
+ String childPackageName = res.removedInfo.removedChildPackages.keyAt(i);
+ if (res.addedChildPackages.containsKey(childPackageName)) {
+ res.removedInfo.removedChildPackages.removeAt(i);
+ } else {
+ PackageRemovedInfo childInfo = res.removedInfo
+ .removedChildPackages.valueAt(i);
+ childInfo.removedForAllUsers = mPackages.get(
+ childInfo.removedPackage) == null;
+ }
+ }
+ }
+ }
+ }
}
}
private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
- int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
- PackageInstalledInfo res) {
+ int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + deletedPackage);
@@ -12964,12 +13160,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Kill package processes including services, providers, etc.
killPackage(deletedPackage, "replace sys pkg");
- // Report the result for the parent package only
- res.removedInfo.uid = deletedPackage.applicationInfo.uid;
- res.removedInfo.removedPackage = deletedPackage.packageName;
-
// Remove existing system package
- removePackageSettingLI(deletedPackage, true);
+ removePackageLI(deletedPackage, true);
disabledSystem = disableSystemPackageLPw(deletedPackage, pkg);
if (!disabledSystem) {
@@ -12987,7 +13179,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Successfully disabled the old package. Now proceed with re-installation
deleteCodeCacheDirsLI(pkg);
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
@@ -13002,7 +13194,8 @@ public class PackageManagerService extends IPackageManager.Stub {
System.currentTimeMillis());
// Check for shared user id changes
- String invalidPackageName = getParentOrChildPackageChangedSharedUser(deletedPackage, newPackage);
+ String invalidPackageName = getParentOrChildPackageChangedSharedUser(
+ deletedPackage, newPackage);
if (invalidPackageName != null) {
res.setError(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Forbidding shared user change from " + deletedPkgSetting.sharedUser
@@ -13030,18 +13223,20 @@ public class PackageManagerService extends IPackageManager.Stub {
if (childPackageDeleted) {
PackageSetting ps = mSettings.getDisabledSystemPkgLPr(
deletedChildPkg.packageName);
- if (ps != null) {
- removePackageDataLI(ps, allUsers, perUserInstalled, null, 0, false);
+ if (ps != null && res.removedInfo.removedChildPackages != null) {
+ PackageRemovedInfo removedChildRes = res.removedInfo
+ .removedChildPackages.get(deletedChildPkg.packageName);
+ removePackageDataLI(ps, allUsers, removedChildRes, 0, false);
+ removedChildRes.removedForAllUsers = mPackages.get(ps.name) == null;
}
}
}
- updateSettingsLI(newPackage, installerPackageName, allUsers,
- perUserInstalled, res, user);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
prepareAppDataAfterInstall(newPackage);
}
} catch (PackageManagerException e) {
- res.returnCode = INSTALL_FAILED_INTERNAL_ERROR;
+ res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
@@ -13108,18 +13303,21 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
- private void removeNativeBinariesLI(PackageParser.Package pkg) {
+ private void removeNativeBinariesLI(PackageSetting ps) {
// Remove the lib path for the parent package
- PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps != null) {
NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
- }
- // Remove the lib path for the child packages
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- ps = (PackageSetting) pkg.childPackages.get(i).mExtras;
- if (ps != null) {
- NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
+ // Remove the lib path for the child packages
+ final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageSetting childPs = null;
+ synchronized (mPackages) {
+ childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
+ }
+ if (childPs != null) {
+ NativeLibraryHelper.removeNativeBinariesLI(childPs
+ .legacyNativeLibraryPathString);
+ }
}
}
}
@@ -13222,22 +13420,23 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
- int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res, UserHandle user) {
+ int[] allUsers, PackageInstalledInfo res, UserHandle user) {
// Update the parent package setting
- updateSettingsInternalLI(newPackage, installerPackageName, allUsers, perUserInstalled,
+ updateSettingsInternalLI(newPackage, installerPackageName, allUsers, res.origUsers,
res, user);
// Update the child packages setting
final int childCount = (newPackage.childPackages != null)
? newPackage.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = newPackage.childPackages.get(i);
- updateSettingsInternalLI(childPackage, installerPackageName, allUsers, perUserInstalled,
- res, user);
+ PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
+ updateSettingsInternalLI(childPackage, installerPackageName, allUsers,
+ childRes.origUsers, childRes, user);
}
}
private void updateSettingsInternalLI(PackageParser.Package newPackage,
- String installerPackageName, int[] allUsers, boolean[] perUserInstalled,
+ String installerPackageName, int[] allUsers, int[] installedForUsers,
PackageInstalledInfo res, UserHandle user) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
@@ -13261,26 +13460,30 @@ public class PackageManagerService extends IPackageManager.Stub {
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final int userId = user.getIdentifier();
if (ps != null) {
if (isSystemApp(newPackage)) {
- // NB: implicit assumption that system package upgrades apply to all users
if (DEBUG_INSTALL) {
Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
}
+ // Enable system package for requested users
if (res.origUsers != null) {
- for (int userHandle : res.origUsers) {
- ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
- userHandle, installerPackageName);
+ for (int origUserId : res.origUsers) {
+ if (userId == UserHandle.USER_ALL || userId == origUserId) {
+ ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
+ origUserId, installerPackageName);
+ }
}
}
// Also convey the prior install/uninstall state
- if (allUsers != null && perUserInstalled != null) {
- for (int i = 0; i < allUsers.length; i++) {
+ if (allUsers != null && installedForUsers != null) {
+ for (int currentUserId : allUsers) {
+ final boolean installed = ArrayUtils.contains(
+ installedForUsers, currentUserId);
if (DEBUG_INSTALL) {
- Slog.d(TAG, " user " + allUsers[i]
- + " => " + perUserInstalled[i]);
+ Slog.d(TAG, " user " + currentUserId + " => " + installed);
}
- ps.setInstalled(perUserInstalled[i], allUsers[i]);
+ ps.setInstalled(installed, currentUserId);
}
// these install state changes will be persisted in the
// upcoming call to mSettings.writeLPr().
@@ -13288,7 +13491,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// It's implied that when a user requests installation, they want the app to be
// installed and enabled.
- int userId = user.getIdentifier();
if (userId != UserHandle.USER_ALL) {
ps.setInstalled(true, userId);
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
@@ -13299,7 +13501,7 @@ public class PackageManagerService extends IPackageManager.Stub {
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
mSettings.writeLPr();
@@ -13330,11 +13532,12 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean replace = false;
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
- // moving a complete application; perfom an initial scan on the new install location
+ // moving a complete application; perform an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
}
+
// Result object to be returned
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
@@ -13342,7 +13545,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ephemeral && (forwardLocked || onExternal)) {
Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
+ " external=" + onExternal);
- res.returnCode = PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
+ res.setReturnCode(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID);
return;
}
@@ -13367,6 +13570,33 @@ public class PackageManagerService extends IPackageManager.Stub {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ // If we are installing a clustered package add results for the children
+ if (pkg.childPackages != null) {
+ synchronized (mPackages) {
+ final int childCount = pkg.childPackages.size();
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ PackageInstalledInfo childRes = new PackageInstalledInfo();
+ childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ childRes.pkg = childPkg;
+ childRes.name = childPkg.packageName;
+ PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRes.origUsers = childPs.queryInstalledUsers(
+ sUserManager.getUserIds(), true);
+ }
+ if ((mPackages.containsKey(childPkg.packageName))) {
+ childRes.removedInfo = new PackageRemovedInfo();
+ childRes.removedInfo.removedPackage = childPkg.packageName;
+ }
+ if (res.addedChildPackages == null) {
+ res.addedChildPackages = new ArrayMap<>();
+ }
+ res.addedChildPackages.put(childPkg.packageName, childRes);
+ }
+ }
+ }
+
// If package doesn't declare API override, mark that we have an install
// time CPU ABI override.
if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
@@ -13598,7 +13828,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
- installerPackageName, volumeUuid, res);
+ installerPackageName, res);
} else {
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
@@ -13608,6 +13838,17 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
+
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
+ PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRes.newUsers = childPs.queryInstalledUsers(
+ sUserManager.getUserIds(), true);
+ }
+ }
}
}
@@ -13624,10 +13865,17 @@ public class PackageManagerService extends IPackageManager.Stub {
MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
- mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS);
- final Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
+ Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid);
mHandler.sendMessage(msg);
+
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
+ msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid);
+ mHandler.sendMessage(msg);
+ }
}
private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing,
@@ -13882,6 +14130,11 @@ public class PackageManagerService extends IPackageManager.Stub {
});
}
+ @Override
+ public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+ return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
+ }
+
private boolean isPackageDeviceAdmin(String packageName, int userId) {
IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
@@ -13946,60 +14199,36 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
- boolean removedForAllUsers = false;
- boolean systemUpdate = false;
-
- PackageParser.Package uninstalledPkg;
+ PackageSetting uninstalledPs = null;
// for the uninstall-updates case and restricted profiles, remember the per-
- // userhandle installed state
+ // user handle installed state
int[] allUsers;
- boolean[] perUserInstalled;
synchronized (mPackages) {
- uninstalledPkg = mPackages.get(packageName);
- PackageSetting ps = mSettings.mPackages.get(packageName);
- allUsers = sUserManager.getUserIds();
- perUserInstalled = new boolean[allUsers.length];
- for (int i = 0; i < allUsers.length; i++) {
- perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
+ uninstalledPs = mSettings.mPackages.get(packageName);
+ if (uninstalledPs == null) {
+ Slog.w(TAG, "Not removing non-existent package " + packageName);
+ return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
+ allUsers = sUserManager.getUserIds();
+ info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
}
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
- res = deletePackageLI(packageName, removeForUser, true, allUsers, perUserInstalled,
+ res = deletePackageLI(packageName, removeForUser, true, allUsers,
flags | REMOVE_CHATTY, info, true, null);
- systemUpdate = info.isRemovedPackageSystemUpdate;
synchronized (mPackages) {
if (res) {
- if (!systemUpdate && mPackages.get(packageName) == null) {
- removedForAllUsers = true;
- }
- mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPkg);
+ mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPs.pkg);
}
}
- if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
- + " removedForAllUsers=" + removedForAllUsers);
}
if (res) {
- info.sendBroadcast(true, systemUpdate, removedForAllUsers);
-
- // If the removed package was a system update, the old system package
- // was re-enabled; we need to broadcast this information
- if (systemUpdate) {
- Bundle extras = new Bundle(1);
- extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
- ? info.removedAppId : info.uid);
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
-
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0, null, null, null);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0, null, null, null);
- sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
- null, 0, packageName, null, null);
- }
+ info.sendPackageRemovedBroadcasts();
+ info.sendSystemPackageUpdatedBroadcasts();
+ info.sendSystemPackageAppearedBroadcasts();
}
// Force a gc here.
Runtime.getRuntime().gc();
@@ -14018,25 +14247,78 @@ public class PackageManagerService extends IPackageManager.Stub {
String removedPackage;
int uid = -1;
int removedAppId = -1;
+ int[] origUsers;
int[] removedUsers = null;
boolean isRemovedPackageSystemUpdate = false;
+ boolean isUpdate;
+ boolean dataRemoved;
+ boolean removedForAllUsers;
// Clean up resources deleted packages.
InstallArgs args = null;
+ ArrayMap<String, PackageRemovedInfo> removedChildPackages;
+ ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
- void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) {
- Bundle extras = new Bundle(1);
+ void sendPackageRemovedBroadcasts() {
+ sendPackageRemovedBroadcastInternal();
+ final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
+ childInfo.sendPackageRemovedBroadcastInternal();
+ }
+ }
+
+ void sendSystemPackageUpdatedBroadcasts() {
+ if (isRemovedPackageSystemUpdate) {
+ sendSystemPackageUpdatedBroadcastsInternal();
+ final int childCount = (removedChildPackages != null)
+ ? removedChildPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
+ if (childInfo.isRemovedPackageSystemUpdate) {
+ childInfo.sendSystemPackageUpdatedBroadcastsInternal();
+ }
+ }
+ }
+ }
+
+ void sendSystemPackageAppearedBroadcasts() {
+ final int packageCount = (appearedChildPackages != null)
+ ? appearedChildPackages.size() : 0;
+ for (int i = 0; i < packageCount; i++) {
+ PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
+ for (int userId : installedInfo.newUsers) {
+ sendPackageAddedForUser(installedInfo.name, true,
+ UserHandle.getAppId(installedInfo.uid), userId);
+ }
+ }
+ }
+
+ private void sendSystemPackageUpdatedBroadcastsInternal() {
+ Bundle extras = new Bundle(2);
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
- extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
- if (replacing) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage,
+ extras, 0, null, null, null);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
+ extras, 0, null, null, null);
+ sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
+ null, 0, removedPackage, null, null);
+ }
+
+ private void sendPackageRemovedBroadcastInternal() {
+ Bundle extras = new Bundle(2);
+ extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
+ extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
+ if (isUpdate || isRemovedPackageSystemUpdate) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
extras, 0, null, null, removedUsers);
- if (fullRemove && !replacing) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
- extras, 0, null, null, removedUsers);
+ if (dataRemoved && !isRemovedPackageSystemUpdate) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
+ removedPackage, extras, 0, null, null, removedUsers);
}
}
if (removedAppId >= 0) {
@@ -14052,12 +14334,11 @@ public class PackageManagerService extends IPackageManager.Stub {
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLI(PackageSetting ps,
- int[] allUserHandles, boolean[] perUserInstalled,
+ private void removePackageDataLI(PackageSetting ps, int[] allUserHandles,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = ps.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
- removePackageSettingLI(ps, (flags&REMOVE_CHATTY) != 0);
+ removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
// reader
@@ -14072,6 +14353,9 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
removeDataDirsLI(ps.volumeUuid, packageName);
+ if (outInfo != null) {
+ outInfo.dataRemoved = true;
+ }
schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
// writer
@@ -14113,16 +14397,16 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// make sure to preserve per-user disabled state if this removal was just
// a downgrade of a system app to the factory package
- if (allUserHandles != null && perUserInstalled != null) {
+ if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
- for (int i = 0; i < allUserHandles.length; i++) {
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + allUserHandles[i]
- + " => " + perUserInstalled[i]);
+ Slog.d(TAG, " user " + userId + " => " + installed);
}
- ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
+ ps.setInstalled(installed, userId);
}
}
}
@@ -14154,23 +14438,22 @@ public class PackageManagerService extends IPackageManager.Stub {
* Tries to delete system package.
*/
private boolean deleteSystemPackageLI(PackageParser.Package deletedPkg,
- PackageSetting deletedPs, int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo, boolean writeSettings,
- PackageParser.Package replacingPackage) {
- if (deletedPkg.parentPackage != null) {
+ PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
+ boolean writeSettings) {
+ if (deletedPs.parentPackageName != null) {
Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
return false;
}
final boolean applyUserRestrictions
- = (allUserHandles != null) && (perUserInstalled != null);
+ = (allUserHandles != null) && (outInfo.origUsers != null);
final PackageSetting disabledPs;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
synchronized (mPackages) {
- disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPkg.packageName);
+ disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPs.name);
}
if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
@@ -14186,14 +14469,31 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_REMOVE) {
if (applyUserRestrictions) {
Slog.d(TAG, "Remembering install states:");
- for (int i = 0; i < allUserHandles.length; i++) {
- Slog.d(TAG, " u=" + allUserHandles[i] + " inst=" + perUserInstalled[i]);
+ for (int userId : allUserHandles) {
+ final boolean finstalled = ArrayUtils.contains(outInfo.origUsers, userId);
+ Slog.d(TAG, " u=" + userId + " inst=" + finstalled);
}
}
}
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
+ if (outInfo.removedChildPackages != null) {
+ final int childCount = (deletedPs.childPackageNames != null)
+ ? deletedPs.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = deletedPs.childPackageNames.get(i);
+ if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
+ .contains(childPackageName)) {
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
+ childPackageName);
+ if (childInfo != null) {
+ childInfo.isRemovedPackageSystemUpdate = true;
+ }
+ }
+ }
+ }
+
if (disabledPs.versionCode < deletedPs.versionCode) {
// Delete data for downgrades
flags &= ~PackageManager.DELETE_KEEP_DATA;
@@ -14201,8 +14501,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// Preserve data by setting flag
flags |= PackageManager.DELETE_KEEP_DATA;
}
- boolean ret = deleteInstalledPackageLI(deletedPkg, true, flags, allUserHandles,
- perUserInstalled, outInfo, writeSettings, replacingPackage);
+
+ boolean ret = deleteInstalledPackageLI(deletedPs, true, flags, allUserHandles,
+ outInfo, writeSettings, disabledPs.pkg);
if (!ret) {
return false;
}
@@ -14212,7 +14513,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Reinstate the old system package
enableSystemPackageLPw(disabledPs.pkg);
// Remove any native libraries from the upgraded package.
- removeNativeBinariesLI(deletedPkg);
+ removeNativeBinariesLI(deletedPs);
}
// Install the system package
@@ -14248,14 +14549,14 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across reinstall");
}
- for (int i = 0; i < allUserHandles.length; i++) {
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + allUserHandles[i]
- + " => " + perUserInstalled[i]);
+ Slog.d(TAG, " user " + userId + " => " + installed);
}
- ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
+ ps.setInstalled(installed, userId);
- mSettings.writeRuntimePermissionsForUserLPr(allUserHandles[i], false);
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
// Regardless of writeSettings we need to ensure that this restriction
// state propagation is persisted
@@ -14269,52 +14570,59 @@ public class PackageManagerService extends IPackageManager.Stub {
return true;
}
- private boolean deleteInstalledPackageLI(PackageParser.Package pkg,
+ private boolean deleteInstalledPackageLI(PackageSetting ps,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
- boolean[] perUserInstalled, PackageRemovedInfo outInfo, boolean writeSettings,
+ PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
- PackageSetting ps = null;
-
synchronized (mPackages) {
- pkg = mPackages.get(pkg.packageName);
- if (pkg == null) {
- return false;
- }
-
- ps = mSettings.mPackages.get(pkg.packageName);
- if (ps == null) {
- return false;
- }
-
if (outInfo != null) {
outInfo.uid = ps.appId;
}
+
+ if (outInfo != null && outInfo.removedChildPackages != null) {
+ final int childCount = (ps.childPackageNames != null)
+ ? ps.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = ps.childPackageNames.get(i);
+ PackageSetting childPs = mSettings.mPackages.get(childPackageName);
+ if (childPs == null) {
+ return false;
+ }
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
+ childPackageName);
+ if (childInfo != null) {
+ childInfo.uid = childPs.appId;
+ }
+ }
+ }
}
// Delete package data from internal structures and also remove data if flag is set
- removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags,
- writeSettings);
+ removePackageDataLI(ps, allUserHandles, outInfo, flags, writeSettings);
// Delete the child packages data
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageSetting childPs;
synchronized (mPackages) {
- childPs = mSettings.peekPackageLPr(pkg.childPackages.get(i).packageName);
+ childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
}
if (childPs != null) {
+ PackageRemovedInfo childOutInfo = (outInfo != null
+ && outInfo.removedChildPackages != null)
+ ? outInfo.removedChildPackages.get(childPs.name) : null;
final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0
&& (replacingPackage != null
&& !replacingPackage.hasChildPackage(childPs.name))
? flags & ~DELETE_KEEP_DATA : flags;
- removePackageDataLI(childPs, allUserHandles, perUserInstalled, outInfo,
+ removePackageDataLI(childPs, allUserHandles, childOutInfo,
deleteFlags, writeSettings);
}
}
// Delete application code and resources only for parent packages
- if (ps.pkg.parentPackage == null) {
- if (deleteCodeAndResources && (outInfo != null)) {
+ if (ps.parentPackageName == null) {
+ if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
@@ -14385,8 +14693,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* This method handles package deletion in general
*/
private boolean deletePackageLI(String packageName, UserHandle user,
- boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo, boolean writeSettings,
+ boolean deleteCodeAndResources, int[] allUserHandles, int flags,
+ PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
if (packageName == null) {
Slog.w(TAG, "Attempt to delete null packageName.");
@@ -14396,7 +14704,6 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
PackageSetting ps;
- int removeUser = -1;
synchronized (mPackages) {
ps = mSettings.mPackages.get(packageName);
@@ -14405,13 +14712,15 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
- if (ps.pkg.parentPackage != null && (!isSystemApp(ps)
+ if (ps.parentPackageName != null && (!isSystemApp(ps)
|| (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
+ ((user == null) ? UserHandle.USER_ALL : user));
}
- if (!clearPackageStateForUser(ps, removeUser, outInfo)) {
+ final int removedUserId = (user != null) ? user.getIdentifier()
+ : UserHandle.USER_ALL;
+ if (!clearPackageStateForUser(ps, removedUserId, outInfo)) {
return false;
}
markPackageUninstalledForUserLPw(ps, user);
@@ -14435,9 +14744,9 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
// Other user still have this package installed, so all
// we need to do is clear this user's data and save that
- // it is uninstalled.
- if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
- if (!clearPackageStateForUser(ps, removeUser, outInfo)) {
+ // it is uninstalled.
+ if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
+ if (!clearPackageStateForUser(ps, user.getIdentifier(), outInfo)) {
return false;
}
scheduleWritePackageRestrictionsLocked(user);
@@ -14454,7 +14763,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// we need to do is clear this user's data and save that
// it is uninstalled.
if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
- if (!clearPackageStateForUser(ps, removeUser, outInfo)) {
+ if (!clearPackageStateForUser(ps, user.getIdentifier(), outInfo)) {
return false;
}
scheduleWritePackageRestrictionsLocked(user);
@@ -14462,19 +14771,83 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ // If we are deleting a composite package for all users, keep track
+ // of result for each child.
+ if (ps.childPackageNames != null && outInfo != null) {
+ synchronized (mPackages) {
+ final int childCount = ps.childPackageNames.size();
+ outInfo.removedChildPackages = new ArrayMap<>(childCount);
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = ps.childPackageNames.get(i);
+ PackageRemovedInfo childInfo = new PackageRemovedInfo();
+ childInfo.removedPackage = childPackageName;
+ outInfo.removedChildPackages.put(childPackageName, childInfo);
+ PackageSetting childPs = mSettings.peekPackageLPr(childPackageName);
+ if (childPs != null) {
+ childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);
+ }
+ }
+ }
+ }
+
boolean ret = false;
if (isSystemApp(ps)) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
- // When an updated system application is deleted we delete the existing resources as well and
- // fall back to existing code in system partition
- ret = deleteSystemPackageLI(ps.pkg, ps, allUserHandles, perUserInstalled,
- flags, outInfo, writeSettings, replacingPackage);
+ // When an updated system application is deleted we delete the existing resources
+ // as well and fall back to existing code in system partition
+ ret = deleteSystemPackageLI(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
// Kill application pre-emptively especially for apps on sd.
killApplication(packageName, ps.appId, "uninstall pkg");
- ret = deleteInstalledPackageLI(ps.pkg, deleteCodeAndResources, flags, allUserHandles,
- perUserInstalled, outInfo, writeSettings, replacingPackage);
+ ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles,
+ outInfo, writeSettings, replacingPackage);
+ }
+
+ // Take a note whether we deleted the package for all users
+ if (outInfo != null) {
+ outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
+ if (outInfo.removedChildPackages != null) {
+ synchronized (mPackages) {
+ final int childCount = outInfo.removedChildPackages.size();
+ for (int i = 0; i < childCount; i++) {
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i);
+ if (childInfo != null) {
+ childInfo.removedForAllUsers = mPackages.get(
+ childInfo.removedPackage) == null;
+ }
+ }
+ }
+ }
+ // If we uninstalled an update to a system app there may be some
+ // child packages that appeared as they are declared in the system
+ // app but were not declared in the update.
+ if (isSystemApp(ps)) {
+ synchronized (mPackages) {
+ PackageSetting updatedPs = mSettings.peekPackageLPr(ps.name);
+ final int childCount = (updatedPs.childPackageNames != null)
+ ? updatedPs.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = updatedPs.childPackageNames.get(i);
+ if (outInfo.removedChildPackages == null
+ || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) {
+ PackageSetting childPs = mSettings.peekPackageLPr(childPackageName);
+ if (childPs == null) {
+ continue;
+ }
+ PackageInstalledInfo installRes = new PackageInstalledInfo();
+ installRes.name = childPackageName;
+ installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true);
+ installRes.pkg = mPackages.get(childPackageName);
+ installRes.uid = childPs.pkg.applicationInfo.uid;
+ if (outInfo.appearedChildPackages == null) {
+ outInfo.appearedChildPackages = new ArrayMap<>();
+ }
+ outInfo.appearedChildPackages.put(childPackageName, installRes);
+ }
+ }
+ }
+ }
}
return ret;
@@ -16617,15 +16990,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
if (!checkin) {
pw.println("Features:");
}
- Iterator<String> it = mAvailableFeatures.keySet().iterator();
- while (it.hasNext()) {
- String name = it.next();
- if (!checkin) {
- pw.print(" ");
- } else {
+
+ 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(name);
}
}
@@ -17241,7 +17621,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
// Delete package internally
PackageRemovedInfo outInfo = new PackageRemovedInfo();
synchronized (mInstallLock) {
- boolean res = deletePackageLI(pkgName, null, false, null, null,
+ boolean res = deletePackageLI(pkgName, null, false, null,
PackageManager.DELETE_KEEP_DATA, outInfo, false, null);
if (res) {
pkgList.add(pkgName);
@@ -17387,7 +17767,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
final ApplicationInfo info = ps.pkg.applicationInfo;
final PackageRemovedInfo outInfo = new PackageRemovedInfo();
- if (deletePackageLI(ps.name, null, false, null, null,
+ if (deletePackageLI(ps.name, null, false, null,
PackageManager.DELETE_KEEP_DATA, outInfo, false, null)) {
unloaded.add(info);
} else {
@@ -17409,8 +17789,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
* recycled.
*/
private void reconcileUsers(String volumeUuid) {
+ // TODO: also reconcile DE directories
final File[] files = FileUtils
- .listFilesOrEmpty(Environment.getDataUserDirectory(volumeUuid));
+ .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid));
for (File file : files) {
if (!file.isDirectory()) continue;
@@ -17539,8 +17920,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags));
- final File ceDir = Environment.getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
- final File deDir = Environment.getDataUserDeviceEncryptedDirectory(volumeUuid, userId);
+ final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
+ final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
boolean restoreconNeeded = false;
@@ -17605,6 +17986,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
if (ps.getInstalled(userId)) {
prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+
+ if (maybeMigrateAppData(volumeUuid, userId, ps.pkg)) {
+ // We may have just shuffled around app data directories, so
+ // prepare them one more time
+ prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+ }
+
preparedCount++;
}
}
@@ -17631,6 +18019,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
* correct for all installed apps. If there is an ownership mismatch, it
* will try recovering system apps by wiping data; third-party app data is
* left intact.
+ * <p>
+ * <em>Note: To avoid a deadlock, do not call this method with {@code mPackages} lock held</em>
*/
private void prepareAppDataAfterInstall(PackageParser.Package pkg) {
prepareAppDataAfterInstallInternal(pkg);
@@ -17645,6 +18035,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
final PackageSetting ps;
synchronized (mPackages) {
ps = mSettings.mPackages.get(pkg.packageName);
+ mSettings.writeKernelMappingLPr(ps);
}
final UserManager um = mContext.getSystemService(UserManager.class);
@@ -17729,6 +18120,30 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
+ /**
+ * For system apps on non-FBE devices, this method migrates any existing
+ * CE/DE data to match the {@code forceDeviceEncrypted} flag requested by
+ * the app.
+ */
+ private boolean maybeMigrateAppData(String volumeUuid, int userId, PackageParser.Package pkg) {
+ if (pkg.isSystemApp() && !StorageManager.isFileBasedEncryptionEnabled()
+ && PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
+ final int storageTarget = pkg.applicationInfo.isForceDeviceEncrypted()
+ ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
+ synchronized (mInstallLock) {
+ try {
+ mInstaller.migrateAppData(volumeUuid, pkg.packageName, userId, storageTarget);
+ } catch (InstallerException e) {
+ logCriticalInfo(Log.WARN,
+ "Failed to migrate " + pkg.packageName + ": " + e.getMessage());
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
private void unfreezePackage(String packageName) {
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -17809,6 +18224,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Package already moved to " + volumeUuid);
}
+ if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+ throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
+ "Device admin cannot be moved");
+ }
if (ps.frozen) {
throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
@@ -18511,13 +18930,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
@Override
- public void setImePackagesProvider(PackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setImePackagesProviderLPr(provider);
- }
- }
-
- @Override
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
synchronized (mPackages) {
mDefaultPermissionPolicy.setVoiceInteractionPackagesProviderLPw(provider);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
new file mode 100644
index 000000000000..a3ac514ccd22
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.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 com.android.server.pm;
+
+import android.app.AppGlobals;
+import android.content.Intent;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Package;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+/**
+ * Class containing helper methods for the PackageManagerService.
+ *
+ * {@hide}
+ */
+public class PackageManagerServiceUtils {
+ private final static long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000;
+
+ private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
+ List<ResolveInfo> ris = null;
+ try {
+ ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId);
+ } catch (RemoteException e) {
+ }
+ ArraySet<String> pkgNames = new ArraySet<String>();
+ if (ris != null) {
+ for (ResolveInfo ri : ris) {
+ pkgNames.add(ri.activityInfo.packageName);
+ }
+ }
+ return pkgNames;
+ }
+
+ private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
+ long dexOptLRUThresholdInMills) {
+ // Filter out packages that aren't recently used.
+ int total = pkgs.size();
+ int skipped = 0;
+ long now = System.currentTimeMillis();
+ for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
+ PackageParser.Package pkg = i.next();
+ long then = pkg.mLastPackageUsageTimeInMills;
+ if (then + dexOptLRUThresholdInMills < now) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
+ ((then == 0) ? "never" : new Date(then)));
+ }
+ i.remove();
+ skipped++;
+ }
+ }
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipped dexopt " + skipped + " of " + total);
+ }
+ }
+
+ // Sort apps by importance for dexopt ordering. Important apps are given
+ // more priority in case the device runs out of space.
+ public static List<PackageParser.Package> getPackagesForDexopt(
+ Collection<PackageParser.Package> packages,
+ PackageManagerService packageManagerService) {
+ ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
+ LinkedList<PackageParser.Package> result = new LinkedList<>();
+
+ // Give priority to core apps.
+ for (PackageParser.Package pkg : remainingPkgs) {
+ if (pkg.coreApp) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName);
+ }
+ result.add(pkg);
+ }
+ }
+ remainingPkgs.removeAll(result);
+
+ // Give priority to system apps that listen for pre boot complete.
+ Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+ ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
+ for (PackageParser.Package pkg : remainingPkgs) {
+ if (pkgNames.contains(pkg.packageName)) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Adding pre boot system app " + result.size() + ": " +
+ pkg.packageName);
+ }
+ result.add(pkg);
+ }
+ }
+ remainingPkgs.removeAll(result);
+
+ // Filter out packages that aren't recently used, add all remaining apps.
+ // TODO: add a property to control this?
+ if (packageManagerService.isHistoricalPackageUsageAvailable()) {
+ filterRecentlyUsedApps(remainingPkgs, SEVEN_DAYS_IN_MILLISECONDS);
+ }
+ result.addAll(remainingPkgs);
+
+ // Now go ahead and also add the libraries required for these packages.
+ // TODO: Think about interleaving things.
+ Set<PackageParser.Package> dependencies = new HashSet<>();
+ for (PackageParser.Package p : result) {
+ dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p));
+ }
+ if (!dependencies.isEmpty()) {
+ // We might have packages already in `result` that are dependencies
+ // of other packages. Make sure we don't add those to the list twice.
+ dependencies.removeAll(result);
+ }
+ result.addAll(dependencies);
+
+ if (DEBUG_DEXOPT) {
+ StringBuilder sb = new StringBuilder();
+ for (PackageParser.Package pkg : result) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(pkg.packageName);
+ }
+ Log.i(TAG, "Packages to be dexopted: " + sb.toString());
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d8845d816450..abee007f1c8a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -178,12 +178,10 @@ class PackageManagerShellCommand extends ShellCommand {
}
try {
- mInterface.setPackageSuspendedAsUser(packageName, suspendedState, userId);
- ApplicationInfo appInfo = mInterface.getApplicationInfo(
- packageName, 0, userId);
-
+ mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
+ userId);
pw.println("Package " + packageName + " new suspended state: "
- + ((appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0));
+ + mInterface.isPackageSuspendedForUser(packageName, userId));
return 0;
} catch (RemoteException e) {
pw.println(e.toString());
@@ -339,9 +337,17 @@ class PackageManagerShellCommand extends ShellCommand {
for (int p = 0; p < count; p++) {
FeatureInfo fi = list.get(p);
pw.print("feature:");
- if (fi.name != null) pw.println(fi.name);
- else pw.println("reqGlEsVersion=0x"
+ if (fi.name != null) {
+ pw.print(fi.name);
+ if (fi.version > 0) {
+ pw.print("=");
+ pw.print(fi.version);
+ }
+ pw.println();
+ } else {
+ pw.println("reqGlEsVersion=0x"
+ Integer.toHexString(fi.reqGlEsVersion));
+ }
}
return 0;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c1a5c5a24978..16521855507e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -19,22 +19,16 @@ package com.android.server.pm;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
-import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
+
import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
import android.annotation.NonNull;
@@ -88,7 +82,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.PackageManagerService.DumpState;
@@ -170,6 +163,7 @@ final class Settings {
private static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_MU = false;
+ private static final boolean DEBUG_KERNEL = false;
private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
@@ -246,9 +240,13 @@ final class Settings {
private final File mPackageListFilename;
private final File mStoppedPackagesFilename;
private final File mBackupStoppedPackagesFilename;
+ private final File mKernelMappingFilename;
- final ArrayMap<String, PackageSetting> mPackages =
- new ArrayMap<String, PackageSetting>();
+ /** Map from package name to settings */
+ final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
+
+ /** Map from package name to appId */
+ private final ArrayMap<String, Integer> mKernelMapping = new ArrayMap<>();
// List of replaced system applications
private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
@@ -408,6 +406,9 @@ final class Settings {
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+ final File kernelDir = new File("/config/sdcardfs");
+ mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
+
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
@@ -540,8 +541,6 @@ final class Settings {
// is okay to muck with.
PackageSetting newp = new PackageSetting(p);
replacePackageLPw(name, newp);
- } else {
- mPackages.remove(name);
}
return true;
}
@@ -576,9 +575,10 @@ final class Settings {
}
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags,
- String parentPackageName, List<String> childPackageNames) {
+ String legacyNativeLibraryPathString, String primaryCpuAbiString,
+ String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
+ pkgFlags, int pkgPrivateFlags, String parentPackageName,
+ List<String> childPackageNames) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -679,6 +679,9 @@ final class Settings {
if (p != null) {
p.primaryCpuAbiString = primaryCpuAbiString;
p.secondaryCpuAbiString = secondaryCpuAbiString;
+ if (childPackageNames != null) {
+ p.childPackageNames = new ArrayList<>(childPackageNames);
+ }
if (!p.codePath.equals(codePath)) {
// Check to see if its a disabled system app
@@ -2340,6 +2343,7 @@ final class Settings {
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
+ writeKernelMappingLPr();
writePackageListLPr();
writeAllUsersPackageRestrictionsLPr();
writeAllRuntimePermissionsLPr();
@@ -2362,6 +2366,53 @@ final class Settings {
//Debug.stopMethodTracing();
}
+ void writeKernelMappingLPr() {
+ if (mKernelMappingFilename == null) return;
+
+ final String[] known = mKernelMappingFilename.list();
+ final ArraySet<String> knownSet = new ArraySet<>(known.length);
+ for (String name : known) {
+ knownSet.add(name);
+ }
+
+ for (final PackageSetting ps : mPackages.values()) {
+ // Package is actively claimed
+ knownSet.remove(ps.name);
+ writeKernelMappingLPr(ps);
+ }
+
+ // Remove any unclaimed mappings
+ for (int i = 0; i < knownSet.size(); i++) {
+ final String name = knownSet.valueAt(i);
+ if (DEBUG_KERNEL) Slog.d(TAG, "Dropping mapping " + name);
+
+ mKernelMapping.remove(name);
+ new File(mKernelMappingFilename, name).delete();
+ }
+ }
+
+ void writeKernelMappingLPr(PackageSetting ps) {
+ if (mKernelMappingFilename == null) return;
+
+ final Integer cur = mKernelMapping.get(ps.name);
+ if (cur != null && cur.intValue() == ps.appId) {
+ // Ignore when mapping already matches
+ return;
+ }
+
+ if (DEBUG_KERNEL) Slog.d(TAG, "Mapping " + ps.name + " to " + ps.appId);
+
+ final File dir = new File(mKernelMappingFilename, ps.name);
+ dir.mkdir();
+
+ final File file = new File(dir, "appid");
+ try {
+ FileUtils.stringToFile(file, Integer.toString(ps.appId));
+ mKernelMapping.put(ps.name, ps.appId);
+ } catch (IOException ignored) {
+ }
+ }
+
void writePackageListLPr() {
writePackageListLPr(-1);
}
@@ -2393,7 +2444,9 @@ final class Settings {
for (final PackageSetting pkg : mPackages.values()) {
if (pkg.pkg == null || pkg.pkg.applicationInfo == null
|| pkg.pkg.applicationInfo.dataDir == null) {
- Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+ if (!"android".equals(pkg.name)) {
+ Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+ }
continue;
}
@@ -2906,6 +2959,8 @@ final class Settings {
mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ mSharedUsers.size() + " shared uids\n");
+ writeKernelMappingLPr();
+
return true;
}
@@ -4376,7 +4431,7 @@ final class Settings {
if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
pw.print(", COSTS_MONEY");
}
- if ((perm.info.flags&PermissionInfo.FLAG_HIDDEN) != 0) {
+ if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) {
pw.print(", HIDDEN");
}
if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
@@ -4553,7 +4608,7 @@ final class Settings {
if (p.perm != null) {
pw.print(" perm="); pw.println(p.perm);
if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
- || (p.perm.info.flags & PermissionInfo.FLAG_HIDDEN) != 0) {
+ || (p.perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
pw.print(" flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3cc7b10c6f24..549026090a49 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -41,6 +41,7 @@ import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.IUserManager;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -188,6 +189,8 @@ public class UserManagerService extends IUserManager.Stub {
private final File mUsersDir;
private final File mUserListFile;
+ private static final IBinder mUserRestriconToken = new Binder();
+
/**
* User-related information that is used for persisting to flash. Only UserInfo is
* directly exposed to other system apps.
@@ -840,7 +843,7 @@ public class UserManagerService extends IUserManager.Stub {
/**
* See {@link UserManagerInternal#setDevicePolicyUserRestrictions(int, Bundle, Bundle)}
*/
- void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle local,
+ void setDevicePolicyUserRestrictionsInner(int userId, @NonNull Bundle local,
@Nullable Bundle global) {
Preconditions.checkNotNull(local);
boolean globalChanged = false;
@@ -1016,7 +1019,7 @@ public class UserManagerService extends IUserManager.Stub {
if (mAppOpsService != null) { // We skip it until system-ready.
final long token = Binder.clearCallingIdentity();
try {
- mAppOpsService.setUserRestrictions(effective, userId);
+ mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
} finally {
@@ -1749,16 +1752,6 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private boolean isPackageInstalled(String pkg, int userId) {
- final ApplicationInfo info = mPm.getApplicationInfo(pkg,
- PackageManager.GET_UNINSTALLED_PACKAGES,
- userId);
- if (info == null || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
- return false;
- }
- return true;
- }
-
/**
* Removes the app restrictions file for a specific package and user id, if it exists.
*/
@@ -1789,6 +1782,10 @@ public class UserManagerService extends IUserManager.Stub {
Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
return null;
}
+ return createUserInternalUnchecked(name, flags, parentId);
+ }
+
+ private UserInfo createUserInternalUnchecked(String name, int flags, int parentId) {
if (ActivityManager.isLowRamDeviceStatic()) {
return null;
}
@@ -1839,6 +1836,11 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
}
+ if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0) {
+ Log.e(LOG_TAG,
+ "Ephemeral users are supported on split-system-user systems only.");
+ return null;
+ }
// In split system user mode, we assign the first human user the primary flag.
// And if there is no device owner, we also assign the admin flag to primary user.
if (UserManager.isSplitSystemUser()
@@ -1930,13 +1932,18 @@ public class UserManagerService extends IUserManager.Stub {
if (user == null) {
return null;
}
- setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
- // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
- // the putIntForUser() will fail.
- android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
- android.provider.Settings.Secure.LOCATION_MODE,
- android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
- setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
+ // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
+ // the putIntForUser() will fail.
+ android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ android.provider.Settings.Secure.LOCATION_MODE,
+ android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
+ setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
return user;
}
@@ -2201,20 +2208,18 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- if (isPackageInstalled(packageName, userId)) {
- // Notify package of changes via an intent - only sent to explicitly registered receivers.
- Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
- changeIntent.setPackage(packageName);
- changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(changeIntent, new UserHandle(userId));
- }
+ // Notify package of changes via an intent - only sent to explicitly registered receivers.
+ Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+ changeIntent.setPackage(packageName);
+ changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(userId));
}
private int getUidForPackage(String packageName) {
long ident = Binder.clearCallingIdentity();
try {
return mContext.getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES).uid;
+ PackageManager.MATCH_UNINSTALLED_PACKAGES).uid;
} catch (NameNotFoundException nnfe) {
return -1;
} finally {
@@ -2857,7 +2862,7 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle localRestrictions,
@Nullable Bundle globalRestrictions) {
- UserManagerService.this.setDevicePolicyUserRestrictions(userId, localRestrictions,
+ UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, localRestrictions,
globalRestrictions);
}
@@ -2975,6 +2980,33 @@ public class UserManagerService extends IUserManager.Stub {
am.switchUser(UserHandle.USER_SYSTEM);
}
}
+
+ @Override
+ public void onEphemeralUserStop(int userId) {
+ synchronized (mUsersLock) {
+ UserInfo userInfo = getUserInfoLU(userId);
+ if (userInfo != null && userInfo.isEphemeral()) {
+ // Do not allow switching back to the ephemeral user again as the user is going
+ // to be deleted.
+ userInfo.flags |= UserInfo.FLAG_DISABLED;
+ if (userInfo.isGuest()) {
+ // Indicate that the guest will be deleted after it stops.
+ userInfo.guestToRemove = true;
+ }
+ }
+ }
+ }
+
+ @Override
+ public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
+ UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
+ // Keep this in sync with UserManager.createUser
+ if (user != null && !user.isAdmin()) {
+ setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
+ setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, true, user.id);
+ }
+ return user;
+ }
}
/* Remove all the users except of the system one. */
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f57f75f04ba6..4b355de62e87 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -155,7 +155,7 @@ public class UserRestrictionsUtils {
*/
public static boolean isValidRestriction(@NonNull String restriction) {
if (!USER_RESTRICTIONS.contains(restriction)) {
- Slog.wtf(TAG, "Unknown restriction: " + restriction);
+ Slog.e(TAG, "Unknown restriction: " + restriction);
return false;
}
return true;
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index a0f20aa0f5b1..5ef518e21c58 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -18,6 +18,8 @@ package com.android.server.policy;
import com.android.internal.app.AlertController;
import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.R;
@@ -388,6 +390,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
public void run() {
try {
// Take an "interactive" bugreport.
+ MetricsLogger.action(mContext,
+ MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
ActivityManagerNative.getDefault().requestBugReport(
ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
} catch (RemoteException e) {
@@ -405,6 +409,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
try {
// Take a "full" bugreport.
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
ActivityManagerNative.getDefault().requestBugReport(
ActivityManager.BUGREPORT_OPTION_FULL);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c046ba610b3a..6320413a452a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,11 +18,16 @@ package com.android.server.policy;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.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.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.view.WindowManager.DOCKED_TOP;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
@@ -31,7 +36,9 @@ import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import android.Manifest;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityManagerNative;
@@ -100,6 +107,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.LongSparseArray;
import android.view.Display;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -128,6 +136,7 @@ import android.view.animation.AnimationUtils;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.policy.PhoneWindow;
+import com.android.internal.policy.IShortcutService;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.widget.PointerLocationView;
@@ -135,6 +144,7 @@ import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
+import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.File;
import java.io.FileReader;
@@ -186,8 +196,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final int LONG_PRESS_HOME_NOTHING = 0;
static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 1;
static final int LONG_PRESS_HOME_ASSIST = 2;
- static final int LONG_PRESS_HOME_PICTURE_IN_PICTURE = 3;
- static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_PICTURE_IN_PICTURE;
+ static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_ASSIST;
static final int DOUBLE_TAP_HOME_NOTHING = 0;
static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
@@ -280,6 +289,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
DreamManagerInternal mDreamManagerInternal;
PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
+ StatusBarManagerInternal mStatusBarManagerInternal;
boolean mPreloadedRecentApps;
final Object mServiceAquireLock = new Object();
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -328,6 +338,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int[] mNavigationBarHeightForRotationInCarMode = new int[4];
int[] mNavigationBarWidthForRotationInCarMode = new int[4];
+ private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
+
// Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
// This is for car dock and this is updated from resource.
private boolean mEnableCarDockHomeCapture = true;
@@ -488,6 +500,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mResettingSystemUiFlags = 0;
// Bits that we are currently always keeping cleared.
int mForceClearedSystemUiFlags = 0;
+ int mLastFullscreenStackSysUiFlags;
+ int mLastDockedStackSysUiFlags;
+ final Rect mNonDockedStackBounds = new Rect();
+ final Rect mDockedStackBounds = new Rect();
+ final Rect mLastNonDockedStackBounds = new Rect();
+ final Rect mLastDockedStackBounds = new Rect();
+
// What we last reported to system UI about whether the compatibility
// menu needs to be displayed.
boolean mLastFocusNeedsMenu = false;
@@ -508,6 +527,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mTopFullscreenOpaqueWindowState;
WindowState mTopFullscreenOpaqueOrDimmingWindowState;
+ WindowState mTopDockedOpaqueWindowState;
+ WindowState mTopDockedOpaqueOrDimmingWindowState;
HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
boolean mTopIsFullscreen;
@@ -559,6 +580,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mConsumeSearchKeyUp;
boolean mAssistKeyLongPressed;
boolean mPendingMetaAction;
+ boolean mForceShowSystemBars;
// support for activating the lock screen while the screen is on
boolean mAllowLockscreenWhenOn;
@@ -844,6 +866,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ StatusBarManagerInternal getStatusBarManagerInternal() {
+ synchronized (mServiceAquireLock) {
+ if (mStatusBarManagerInternal == null) {
+ mStatusBarManagerInternal =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ }
+ return mStatusBarManagerInternal;
+ }
+ }
+
/*
* We always let the sensor be switched on by default except when
* the user has explicitly disabled sensor based rotation or when the
@@ -1326,7 +1358,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void handleLongPressOnHome(int deviceId, KeyEvent event) {
+ private void handleLongPressOnHome(int deviceId) {
if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
return;
}
@@ -1340,11 +1372,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case LONG_PRESS_HOME_ASSIST:
launchAssistAction(null, deviceId);
break;
- case LONG_PRESS_HOME_PICTURE_IN_PICTURE:
- requestTvPictureInPicture(event);
- break;
default:
- Log.w(TAG, "Not defined home long press behavior: " + mLongPressOnHomeBehavior);
+ Log.w(TAG, "Undefined home long press behavior: " + mLongPressOnHomeBehavior);
break;
}
}
@@ -2015,7 +2044,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
}
if (permission != null) {
- if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) {
+ 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) {
@@ -2389,7 +2418,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TYPE_WALLPAPER:
case TYPE_DREAM:
case TYPE_KEYGUARD_SCRIM:
- case TYPE_DOCK_DIVIDER:
return false;
default:
// Hide only windows below the keyguard host window.
@@ -2916,7 +2944,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
if (!keyguardOn) {
- handleLongPressOnHome(event.getDeviceId(), event);
+ handleLongPressOnHome(event.getDeviceId());
}
}
return -1;
@@ -3076,7 +3104,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
dispatchDirectAudioEvent(event);
return -1;
}
- } else if (KeyEvent.isMetaKey(keyCode)) {
+ }
+
+ if (KeyEvent.isMetaKey(keyCode)) {
if (down) {
mPendingMetaAction = true;
} else if (mPendingMetaAction) {
@@ -3191,6 +3221,35 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return -1;
}
+ if (down) {
+ long shortcutCode = (long) keyCode;
+ if (event.isCtrlPressed()) {
+ shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
+ }
+
+ if (event.isAltPressed()) {
+ shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
+ }
+
+ if (event.isShiftPressed()) {
+ shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
+ }
+
+ if (event.isMetaPressed()) {
+ shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE;
+ }
+
+ IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
+ if (shortcutService != null) {
+ try {
+ shortcutService.notifyShortcutKeyPressed(shortcutCode);
+ } catch (RemoteException e) {
+ mShortcutKeyServices.delete(shortcutCode);
+ }
+ return -1;
+ }
+ }
+
// Reserve all the META modifier combos for system behavior
if ((metaState & KeyEvent.META_META_ON) != 0) {
return -1;
@@ -3280,6 +3339,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return false;
}
+ public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
+ throws RemoteException {
+ synchronized (mLock) {
+ IShortcutService service = mShortcutKeyServices.get(shortcutCode);
+ if (service != null && service.asBinder().isBinderAlive()) {
+ throw new RemoteException("Key already exists.");
+ }
+
+ mShortcutKeyServices.put(shortcutCode, shortcutService);
+ }
+ }
+
private void launchAssistLongPressAction() {
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
@@ -3585,7 +3656,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public void getInsetHintLw(WindowManager.LayoutParams attrs, int displayRotation,
+ public boolean getInsetHintLw(WindowManager.LayoutParams attrs, int displayRotation,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
@@ -3640,10 +3711,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
outStableInsets.set(mStableLeft, mStableTop,
availRight - mStableRight, availBottom - mStableBottom);
- return;
+ return mForceShowSystemBars;
}
outContentInsets.setEmpty();
outStableInsets.setEmpty();
+ return mForceShowSystemBars;
}
private boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
@@ -4373,6 +4445,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ mUnrestrictedScreenWidth;
pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
+ mUnrestrictedScreenHeight;
+ } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
+ pf.left = df.left = of.left = mRestrictedScreenLeft;
+ pf.top = df.top = of.top = mRestrictedScreenTop;
+ pf.right = df.right = of.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
+ pf.bottom = df.bottom = of.bottom = mRestrictedScreenTop
+ + mRestrictedScreenHeight;
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ cf.left = mDockLeft;
+ cf.top = mDockTop;
+ cf.right = mDockRight;
+ cf.bottom = mDockBottom;
+ } else {
+ cf.left = mContentLeft;
+ cf.top = mContentTop;
+ cf.right = mContentRight;
+ cf.bottom = mContentBottom;
+ }
} else {
pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
@@ -4552,6 +4641,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mTopFullscreenOpaqueOrDimmingWindowState = null;
+ mTopDockedOpaqueWindowState = null;
+ mTopDockedOpaqueOrDimmingWindowState = null;
mAppsToBeHidden.clear();
mAppsThatDismissKeyguard.clear();
mForceStatusBar = false;
@@ -4597,7 +4688,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& attrs.type < FIRST_SYSTEM_WINDOW;
final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
-
+ final int stackId = win.getStackId();
if (mTopFullscreenOpaqueWindowState == null &&
win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
@@ -4646,9 +4737,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
mAppsToBeHidden.add(appToken);
}
- if (attrs.x == 0 && attrs.y == 0
- && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
- && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
+ if (isFullscreen(attrs) && StackId.normallyFullscreenWindows(stackId)) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
@@ -4692,11 +4781,37 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWinShowWhenLocked = win;
}
}
- if (mTopFullscreenOpaqueOrDimmingWindowState == null
- && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()
- && win.isDimming()) {
+
+ // Keep track of the window if it's dimming but not necessarily fullscreen.
+ final boolean reallyVisible = win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw();
+ if (mTopFullscreenOpaqueOrDimmingWindowState == null && reallyVisible
+ && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) {
mTopFullscreenOpaqueOrDimmingWindowState = win;
}
+
+ // We need to keep track of the top "fullscreen" opaque window for the docked stack
+ // separately, because both the "real fullscreen" opaque window and the one for the docked
+ // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ if (mTopDockedOpaqueWindowState == null && reallyVisible && appWindow && attached == null
+ && isFullscreen(attrs) && stackId == DOCKED_STACK_ID) {
+ mTopDockedOpaqueWindowState = win;
+ if (mTopDockedOpaqueOrDimmingWindowState == null) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+ }
+
+ // Also keep track of any windows that are dimming but not necessarily fullscreen in the
+ // docked stack.
+ if (mTopDockedOpaqueOrDimmingWindowState == null && reallyVisible && win.isDimming()
+ && stackId == DOCKED_STACK_ID) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+ }
+
+ private boolean isFullscreen(WindowManager.LayoutParams attrs) {
+ return attrs.x == 0 && attrs.y == 0
+ && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+ && attrs.height == WindowManager.LayoutParams.MATCH_PARENT;
}
/** {@inheritDoc} */
@@ -6013,9 +6128,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
Rect outInsets) {
outInsets.setEmpty();
+
+ // Navigation bar and status bar.
+ getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, outInsets);
if (mStatusBar != null) {
outInsets.top = mStatusBarHeight;
}
+ }
+
+ @Override
+ public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+ Rect outInsets) {
+ outInsets.setEmpty();
+
+ // Only navigation bar
if (mNavigationBar != null) {
if (isNavigationBarOnBottom(displayWidth, displayHeight)) {
outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode);
@@ -6025,6 +6151,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ @Override
+ public boolean isNavBarForcedShownLw(WindowState windowState) {
+ return mForceShowSystemBars
+ && !windowState.getFrameLw().equals(windowState.getDisplayFrameLw());
+ }
+
+ @Override
+ public boolean isDockSideAllowed(int dockSide) {
+
+ // We do not allow all dock sides at which the navigation bar touches the docked stack.
+ if (!mNavigationBarCanMove) {
+ return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT;
+ } else {
+ return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT;
+ }
+ }
+
void sendCloseSystemWindows() {
PhoneWindow.sendCloseSystemWindows(mContext, null);
}
@@ -6838,42 +6981,52 @@ public class PhoneWindowManager implements WindowManagerPolicy {
tmpVisibility |= StatusBarManager.DISABLE_RECENT;
}
- tmpVisibility = updateLightStatusBarLw(tmpVisibility);
+ final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
+ final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
+ mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
+ mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds);
+ mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds);
final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
final int diff = visibility ^ mLastSystemUiFlags;
+ final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
+ final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
- if (diff == 0 && mLastFocusNeedsMenu == needsMenu
- && mFocusedApp == win.getAppToken()) {
+ if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
+ && mFocusedApp == win.getAppToken()
+ && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
+ && mLastDockedStackBounds.equals(mDockedStackBounds)) {
return 0;
}
mLastSystemUiFlags = visibility;
+ mLastFullscreenStackSysUiFlags = fullscreenVisibility;
+ mLastDockedStackSysUiFlags = dockedVisibility;
mLastFocusNeedsMenu = needsMenu;
mFocusedApp = win.getAppToken();
+ final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
+ final Rect dockedStackBounds = new Rect(mDockedStackBounds);
mHandler.post(new Runnable() {
@Override
public void run() {
- try {
- IStatusBarService statusbar = getStatusBarService();
- if (statusbar != null) {
- statusbar.setSystemUiVisibility(visibility, 0xffffffff, win.toString());
- statusbar.topAppWindowChanged(needsMenu);
- }
- } catch (RemoteException e) {
- // re-acquire status bar service next time it is needed.
- mStatusBarService = null;
+ StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+ if (statusbar != null) {
+ statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
+ dockedVisibility, 0xffffffff, fullscreenStackBounds,
+ dockedStackBounds, win.toString());
+ statusbar.topAppWindowChanged(needsMenu);
}
}
});
return diff;
}
- private int updateLightStatusBarLw(int vis) {
+ private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
? mStatusBar
- : mTopFullscreenOpaqueOrDimmingWindowState;
+ : opaqueOrDimming;
if (statusColorWin != null) {
- if (statusColorWin == mTopFullscreenOpaqueWindowState) {
+ if (statusColorWin == opaque) {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect
// its light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
@@ -6896,8 +7049,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// We need to force system bars when the docked stack is visible, when the freeform stack
// is visible but also when we are resizing for the transitions when docked stack
// visibility changes.
- final boolean forceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
- final boolean forceOpaqueSystemBars = forceShowSystemBars && !mForceStatusBarFromKeyguard;
+ mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
+ final boolean forceOpaqueSystemBars = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
// apply translucent bar vis flags
WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
@@ -6945,11 +7098,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
(vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
final boolean transientStatusBarAllowed = mStatusBar != null
- && (statusBarHasFocus || (!forceShowSystemBars
+ && (statusBarHasFocus || (!mForceShowSystemBars
&& (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
final boolean transientNavBarAllowed = mNavigationBar != null
- && !forceShowSystemBars && hideNavBarSysui && immersiveSticky;
+ && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
final long now = SystemClock.uptimeMillis();
final boolean pendingPanic = mPendingPanicGestureUptime != 0
@@ -6966,7 +7119,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& !transientStatusBarAllowed && hideStatusBarSysui;
final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
&& !transientNavBarAllowed;
- if (denyTransientStatus || denyTransientNav || forceShowSystemBars) {
+ if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
// clear the clearable flags instead
clearClearableFlagsLw();
vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 549d2dc39468..8d296d505c4c 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -22,6 +22,7 @@ import android.view.WindowManagerPolicy.OnKeyguardExitResult;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
+import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -116,8 +117,8 @@ public class KeyguardServiceDelegate {
public KeyguardServiceDelegate(Context context) {
mContext = context;
- mScrim = createScrim(context);
- mScrimHandler = new Handler();
+ mScrimHandler = UiThread.getHandler();
+ mScrim = createScrim(context, mScrimHandler);
}
public void bindService(Context context) {
@@ -130,7 +131,7 @@ public class KeyguardServiceDelegate {
intent.setComponent(keyguardComponent);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
- Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
+ Context.BIND_AUTO_CREATE, mScrimHandler, UserHandle.SYSTEM)) {
Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
@@ -334,8 +335,8 @@ public class KeyguardServiceDelegate {
}
}
- private static final View createScrim(Context context) {
- View view = new View(context);
+ private static View createScrim(Context context, Handler handler) {
+ final View view = new View(context);
int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
@@ -345,14 +346,13 @@ public class KeyguardServiceDelegate {
final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
lp.setTitle("KeyguardScrim");
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- wm.addView(view, lp);
+ final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
// Disable pretty much everything in statusbar until keyguard comes back and we know
// the state of the world.
view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
@@ -360,6 +360,12 @@ public class KeyguardServiceDelegate {
| View.STATUS_BAR_DISABLE_RECENT
| View.STATUS_BAR_DISABLE_EXPAND
| View.STATUS_BAR_DISABLE_SEARCH);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ wm.addView(view, lp);
+ }
+ });
return view;
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a1f24f772c3c..f901f9565fcc 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -49,6 +49,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.service.dreams.DreamManagerInternal;
import android.util.EventLog;
import android.util.Slog;
@@ -468,6 +469,9 @@ 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;
+
private native void nativeInit();
private static native void nativeAcquireSuspendBlocker(String name);
@@ -620,6 +624,9 @@ 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);
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -726,6 +733,9 @@ 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,
@@ -1997,6 +2007,7 @@ public final class PowerManagerService extends SystemService
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress;
+ mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
@@ -2692,12 +2703,9 @@ public final class PowerManagerService extends SystemService
if (reason == null) {
reason = "";
}
- if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
- // If we are rebooting to go into recovery, instead of
- // setting sys.powerctl directly we'll start the
- // pre-recovery service which will do some preparation for
- // recovery and then reboot for us.
- SystemProperties.set("ctl.start", "pre-recovery");
+ if (reason.equals(PowerManager.REBOOT_RECOVERY)
+ || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+ SystemProperties.set("sys.powerctl", "reboot,recovery");
} else {
SystemProperties.set("sys.powerctl", "reboot," + reason);
}
@@ -3410,7 +3418,8 @@ public final class PowerManagerService extends SystemService
@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
- if (PowerManager.REBOOT_RECOVERY.equals(reason)) {
+ if (PowerManager.REBOOT_RECOVERY.equals(reason)
+ || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index ac6a28e91ca8..bcafddc3e999 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -32,8 +32,10 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.PowerManager;
+import android.os.RecoverySystem;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -81,13 +83,9 @@ public final class ShutdownThread extends Thread {
private static Object sIsStartedGuard = new Object();
private static boolean sIsStarted = false;
- // uncrypt status files
- private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
- private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
-
private static boolean mReboot;
private static boolean mRebootSafeMode;
- private static boolean mRebootUpdate;
+ private static boolean mRebootHasProgressBar;
private static String mReason;
// Provides shutdown assurance in case the system_server is killed
@@ -96,6 +94,9 @@ public final class ShutdownThread extends Thread {
// Indicates whether we are rebooting into safe mode
public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
+ // Indicates whether we should stay in safe mode until ro.build.date.utc is newer than this
+ public static final String AUDIT_SAFEMODE_PROPERTY = "persist.sys.audit_safemode";
+
// static instance of this thread
private static final ShutdownThread sInstance = new ShutdownThread();
@@ -213,7 +214,7 @@ public final class ShutdownThread extends Thread {
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
- mRebootUpdate = false;
+ mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
@@ -233,7 +234,7 @@ public final class ShutdownThread extends Thread {
mReboot = true;
mRebootSafeMode = true;
- mRebootUpdate = false;
+ mRebootHasProgressBar = false;
mReason = null;
shutdownInner(context, confirm);
}
@@ -250,10 +251,19 @@ public final class ShutdownThread extends Thread {
// Throw up a system dialog to indicate the device is rebooting / shutting down.
ProgressDialog pd = new ProgressDialog(context);
- // Path 1: Reboot to recovery and install the update
- // Condition: mReason == REBOOT_RECOVERY and mRebootUpdate == True
- // (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.)
- // UI: progress bar
+ // Path 1: Reboot to recovery for update
+ // Condition: mReason == REBOOT_RECOVERY_UPDATE
+ //
+ // Path 1a: uncrypt needed
+ // Condition: if /cache/recovery/uncrypt_file exists but
+ // /cache/recovery/block.map doesn't.
+ // UI: determinate progress bar (mRebootHasProgressBar == True)
+ //
+ // * Path 1a is expected to be removed once the GmsCore shipped on
+ // device always calls uncrypt prior to reboot.
+ //
+ // Path 1b: uncrypt already done
+ // UI: spinning circle only (no progress bar)
//
// Path 2: Reboot to recovery for factory reset
// Condition: mReason == REBOOT_RECOVERY
@@ -262,24 +272,31 @@ public final class ShutdownThread extends Thread {
// Path 3: Regular reboot / shutdown
// Condition: Otherwise
// UI: spinning circle only (no progress bar)
- if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
- mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
- if (mRebootUpdate) {
- pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
- pd.setMessage(context.getText(
- com.android.internal.R.string.reboot_to_update_prepare));
+ if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
+ // We need the progress bar if uncrypt will be invoked during the
+ // reboot, which might be time-consuming.
+ mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
+ && !(RecoverySystem.BLOCK_MAP_FILE.exists());
+ pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
+ if (mRebootHasProgressBar) {
pd.setMax(100);
- pd.setProgressNumberFormat(null);
- pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setProgress(0);
pd.setIndeterminate(false);
- } else {
- // Factory reset path. Set the dialog message accordingly.
- pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
+ pd.setProgressNumberFormat(null);
+ pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage(context.getText(
- com.android.internal.R.string.reboot_to_reset_message));
+ com.android.internal.R.string.reboot_to_update_prepare));
+ } else {
pd.setIndeterminate(true);
+ pd.setMessage(context.getText(
+ com.android.internal.R.string.reboot_to_update_reboot));
}
+ } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
+ // Factory reset path. Set the dialog message accordingly.
+ pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
+ pd.setMessage(context.getText(
+ com.android.internal.R.string.reboot_to_reset_message));
+ pd.setIndeterminate(true);
} else {
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
@@ -379,7 +396,7 @@ public final class ShutdownThread extends Thread {
if (delay <= 0) {
Log.w(TAG, "Shutdown broadcast timed out");
break;
- } else if (mRebootUpdate) {
+ } else if (mRebootHasProgressBar) {
int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
sInstance.setRebootProgress(status, null);
@@ -390,7 +407,7 @@ public final class ShutdownThread extends Thread {
}
}
}
- if (mRebootUpdate) {
+ if (mRebootHasProgressBar) {
sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
}
@@ -404,7 +421,7 @@ public final class ShutdownThread extends Thread {
} catch (RemoteException e) {
}
}
- if (mRebootUpdate) {
+ if (mRebootHasProgressBar) {
sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
}
@@ -415,13 +432,13 @@ public final class ShutdownThread extends Thread {
if (pm != null) {
pm.shutdown();
}
- if (mRebootUpdate) {
+ if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
- if (mRebootUpdate) {
+ if (mRebootHasProgressBar) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
@@ -455,7 +472,7 @@ public final class ShutdownThread extends Thread {
if (delay <= 0) {
Log.w(TAG, "Shutdown wait timed out");
break;
- } else if (mRebootUpdate) {
+ } else if (mRebootHasProgressBar) {
int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
(MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
MAX_SHUTDOWN_WAIT_TIME);
@@ -468,10 +485,11 @@ public final class ShutdownThread extends Thread {
}
}
}
- if (mRebootUpdate) {
+ if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
- // If it's to reboot to install update, invoke uncrypt via init service.
+ // If it's to reboot to install an update and uncrypt hasn't been
+ // done yet, trigger it now.
uncrypt();
}
@@ -549,7 +567,7 @@ public final class ShutdownThread extends Thread {
long delay = endTime - SystemClock.elapsedRealtime();
while (delay > 0) {
- if (mRebootUpdate) {
+ if (mRebootHasProgressBar) {
int status = (int)((timeout - delay) * 1.0 *
(RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
status += PACKAGE_MANAGER_STOP_PERCENT;
@@ -651,66 +669,40 @@ public final class ShutdownThread extends Thread {
private void uncrypt() {
Log.i(TAG, "Calling uncrypt and monitoring the progress...");
+ final RecoverySystem.ProgressListener progressListener =
+ new RecoverySystem.ProgressListener() {
+ @Override
+ public void onProgress(int status) {
+ if (status >= 0 && status < 100) {
+ // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
+ status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
+ status += MOUNT_SERVICE_STOP_PERCENT;
+ CharSequence msg = mContext.getText(
+ com.android.internal.R.string.reboot_to_update_package);
+ sInstance.setRebootProgress(status, msg);
+ } else if (status == 100) {
+ CharSequence msg = mContext.getText(
+ com.android.internal.R.string.reboot_to_update_reboot);
+ sInstance.setRebootProgress(status, msg);
+ } else {
+ // Ignored
+ }
+ }
+ };
+
final boolean[] done = new boolean[1];
done[0] = false;
Thread t = new Thread() {
@Override
public void run() {
- // Create the status pipe file to communicate with /system/bin/uncrypt.
- new File(UNCRYPT_STATUS_FILE).delete();
+ RecoverySystem rs = (RecoverySystem) mContext.getSystemService(
+ Context.RECOVERY_SERVICE);
+ String filename = null;
try {
- Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
- } catch (ErrnoException e) {
- Log.w(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
- "\": " + e.getMessage());
- }
-
- SystemProperties.set("ctl.start", "uncrypt");
-
- // Read the status from the pipe.
- try (BufferedReader reader = new BufferedReader(
- new FileReader(UNCRYPT_STATUS_FILE))) {
-
- int lastStatus = Integer.MIN_VALUE;
- while (true) {
- String str = reader.readLine();
- try {
- int status = Integer.parseInt(str);
-
- // Avoid flooding the log with the same message.
- if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
- continue;
- }
- lastStatus = status;
-
- if (status >= 0 && status < 100) {
- // Update status
- Log.d(TAG, "uncrypt read status: " + status);
- // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
- status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
- status += MOUNT_SERVICE_STOP_PERCENT;
- CharSequence msg = mContext.getText(
- com.android.internal.R.string.reboot_to_update_package);
- sInstance.setRebootProgress(status, msg);
- } else if (status == 100) {
- Log.d(TAG, "uncrypt successfully finished.");
- CharSequence msg = mContext.getText(
- com.android.internal.R.string.reboot_to_update_reboot);
- sInstance.setRebootProgress(status, msg);
- break;
- } else {
- // Error in /system/bin/uncrypt. Or it's rebooting to recovery
- // to perform other operations (e.g. factory reset).
- Log.d(TAG, "uncrypt failed with status: " + status);
- break;
- }
- } catch (NumberFormatException unused) {
- Log.d(TAG, "uncrypt invalid status received: " + str);
- break;
- }
- }
- } catch (IOException unused) {
- Log.w(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+ filename = FileUtils.readTextFile(RecoverySystem.UNCRYPT_PACKAGE_FILE, 0, null);
+ rs.processPackage(mContext, new File(filename), progressListener);
+ } catch (IOException e) {
+ Log.e(TAG, "Error uncrypting file", e);
}
done[0] = true;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 25d646d2bb3b..6bda4edf273b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -16,6 +16,7 @@
package com.android.server.statusbar;
+import android.graphics.Rect;
import android.os.Bundle;
import com.android.server.notification.NotificationDelegate;
@@ -29,4 +30,8 @@ public interface StatusBarManagerInternal {
void showAssistDisclosure();
void startAssist(Bundle args);
void onCameraLaunchGestureDetected(int source);
+ void topAppWindowChanged(boolean menuVisible);
+ void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+ Rect fullscreenBounds, Rect dockedBounds, String cause);
+ void toggleSplitScreen();
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 90340d5589a5..d24e1af3f382 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -20,6 +20,7 @@ import android.app.StatusBarManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -70,6 +71,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
private Object mLock = new Object();
// encompasses lights-out mode and other flags defined on View
private int mSystemUiVisibility = 0;
+ private int mFullscreenStackSysUiVisibility;
+ private int mDockedStackSysUiVisibility;
+ private final Rect mFullscreenStackBounds = new Rect();
+ private final Rect mDockedStackBounds = new Rect();
private boolean mMenuVisible = false;
private int mImeWindowVis = 0;
private int mImeBackDisposition;
@@ -186,6 +191,29 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
}
+
+ @Override
+ public void topAppWindowChanged(boolean menuVisible) {
+ StatusBarManagerService.this.topAppWindowChanged(menuVisible);
+ }
+
+ @Override
+ public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask,
+ Rect fullscreenBounds, Rect dockedBounds, String cause) {
+ StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
+ dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
+ }
+
+ @Override
+ public void toggleSplitScreen() {
+ enforceStatusBarService();
+ if (mBar != null) {
+ try {
+ mBar.toggleSplitScreen();
+ } catch (RemoteException ex) {}
+ }
+ }
};
// ================================================================================
@@ -390,8 +418,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
* response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
* to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
*/
- @Override
- public void topAppWindowChanged(final boolean menuVisible) {
+ private void topAppWindowChanged(final boolean menuVisible) {
enforceStatusBar();
if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key");
@@ -399,15 +426,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
synchronized(mLock) {
mMenuVisible = menuVisible;
mHandler.post(new Runnable() {
- public void run() {
- if (mBar != null) {
- try {
- mBar.topAppWindowChanged(menuVisible);
- } catch (RemoteException ex) {
- }
+ public void run() {
+ if (mBar != null) {
+ try {
+ mBar.topAppWindowChanged(menuVisible);
+ } catch (RemoteException ex) {
}
}
- });
+ }
+ });
}
}
@@ -443,13 +470,19 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void setSystemUiVisibility(int vis, int mask, String cause) {
+ setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause);
+ }
+
+ private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
+ Rect fullscreenBounds, Rect dockedBounds, String cause) {
// also allows calls from window manager which is in this process.
enforceStatusBarService();
if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
synchronized (mLock) {
- updateUiVisibilityLocked(vis, mask);
+ updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
+ fullscreenBounds, dockedBounds);
disableLocked(
mCurrentUserId,
vis & StatusBarManager.DISABLE_MASK,
@@ -458,14 +491,25 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
- private void updateUiVisibilityLocked(final int vis, final int mask) {
- if (mSystemUiVisibility != vis) {
+ private void updateUiVisibilityLocked(final int vis,
+ final int fullscreenStackVis, final int dockedStackVis, final int mask,
+ final Rect fullscreenBounds, final Rect dockedBounds) {
+ if (mSystemUiVisibility != vis
+ || mFullscreenStackSysUiVisibility != fullscreenStackVis
+ || mDockedStackSysUiVisibility != dockedStackVis
+ || !mFullscreenStackBounds.equals(fullscreenBounds)
+ || !mDockedStackBounds.equals(dockedBounds)) {
mSystemUiVisibility = vis;
+ mFullscreenStackSysUiVisibility = fullscreenStackVis;
+ mDockedStackSysUiVisibility = dockedStackVis;
+ mFullscreenStackBounds.set(fullscreenBounds);
+ mDockedStackBounds.set(dockedBounds);
mHandler.post(new Runnable() {
public void run() {
if (mBar != null) {
try {
- mBar.setSystemUiVisibility(vis, mask);
+ mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
+ mask, fullscreenBounds, dockedBounds);
} catch (RemoteException ex) {
}
}
@@ -617,7 +661,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
// ================================================================================
@Override
public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
- List<StatusBarIcon> iconList, int switches[], List<IBinder> binders) {
+ List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
+ Rect fullscreenStackBounds, Rect dockedStackBounds) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
@@ -636,7 +681,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
switches[4] = mImeBackDisposition;
switches[5] = mShowImeSwitcher ? 1 : 0;
switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
+ switches[7] = mFullscreenStackSysUiVisibility;
+ switches[8] = mDockedStackSysUiVisibility;
binders.add(mImeToken);
+ fullscreenStackBounds.set(mFullscreenStackBounds);
+ dockedStackBounds.set(mDockedStackBounds);
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 4e96d71d7e18..bf281d6fb471 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -24,6 +24,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
@@ -45,6 +46,7 @@ import android.media.tv.ITvInputHardwareCallback;
import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvStreamConfig;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -57,9 +59,13 @@ import android.util.SparseBooleanArray;
import android.view.KeyEvent;
import android.view.Surface;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
@@ -549,6 +555,70 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return (float) mCurrentIndex / (float) mCurrentMaxIndex;
}
+ public void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump TvInputHardwareManager from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mLock) {
+ pw.println("TvInputHardwareManager Info:");
+ pw.increaseIndent();
+ pw.println("mConnections: deviceId -> Connection");
+ pw.increaseIndent();
+ for (int i = 0; i < mConnections.size(); i++) {
+ int deviceId = mConnections.keyAt(i);
+ Connection mConnection = mConnections.valueAt(i);
+ pw.println(deviceId + ": " + mConnection);
+
+ }
+ pw.decreaseIndent();
+
+ pw.println("mHardwareList:");
+ pw.increaseIndent();
+ for (TvInputHardwareInfo tvInputHardwareInfo : mHardwareList) {
+ pw.println(tvInputHardwareInfo);
+ }
+ pw.decreaseIndent();
+
+ pw.println("mHdmiDeviceList:");
+ pw.increaseIndent();
+ for (HdmiDeviceInfo hdmiDeviceInfo : mHdmiDeviceList) {
+ pw.println(hdmiDeviceInfo);
+ }
+ pw.decreaseIndent();
+
+ pw.println("mHardwareInputIdMap: deviceId -> inputId");
+ pw.increaseIndent();
+ for (int i = 0 ; i < mHardwareInputIdMap.size(); i++) {
+ int deviceId = mHardwareInputIdMap.keyAt(i);
+ String inputId = mHardwareInputIdMap.valueAt(i);
+ pw.println(deviceId + ": " + inputId);
+ }
+ pw.decreaseIndent();
+
+ pw.println("mHdmiInputIdMap: id -> inputId");
+ pw.increaseIndent();
+ for (int i = 0; i < mHdmiInputIdMap.size(); i++) {
+ int id = mHdmiInputIdMap.keyAt(i);
+ String inputId = mHdmiInputIdMap.valueAt(i);
+ pw.println(id + ": " + inputId);
+ }
+ pw.decreaseIndent();
+
+ pw.println("mInputMap: inputId -> inputInfo");
+ pw.increaseIndent();
+ for(Map.Entry<String, TvInputInfo> entry : mInputMap.entrySet()) {
+ pw.println(entry.getKey() + ": " + entry.getValue());
+ }
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ }
+ }
+
private class Connection implements IBinder.DeathRecipient {
private final TvInputHardwareInfo mHardwareInfo;
private TvInputInfo mInfo;
@@ -641,6 +711,17 @@ class TvInputHardwareManager implements TvInputHal.Callback {
resetLocked(null, null, null, null, null);
}
}
+
+ public String toString() {
+ return "Connection{"
+ + " mHardwareInfo: " + mHardwareInfo
+ + ", mInfo: " + mInfo
+ + ", mCallback: " + mCallback
+ + ", mConfigs: " + Arrays.toString(mConfigs)
+ + ", mCallingUid: " + mCallingUid
+ + ", mResolvedUserId: " + mResolvedUserId
+ + " }";
+ }
}
private class TvInputHardwareImpl extends ITvInputHardware.Stub {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 3e99a4cfe01e..8a2729eec805 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.tv;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -304,9 +305,8 @@ public final class TvInputManagerService extends SystemService {
if (hasHardwarePermission(pm, component)) {
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
- // We see this hardware TV input service for the first time; we need to
- // prepare the ServiceState object so that we can connect to the service and
- // let it add TvInputInfo objects to mInputList if there's any.
+ // New hardware input found. Create a new ServiceState and connect to the
+ // service to populate the hardware list.
serviceState = new ServiceState(component, userId);
userState.serviceStateMap.put(component, serviceState);
updateServiceConnectionLocked(component, userId);
@@ -437,11 +437,7 @@ public final class TvInputManagerService extends SystemService {
for (SessionState state : userState.sessionStateMap.values()) {
if (state.session != null) {
try {
- if (state.isRecordingSession) {
- state.session.disconnect();
- } else {
- state.session.release();
- }
+ state.session.release();
} catch (RemoteException e) {
Slog.e(TAG, "error in release", e);
}
@@ -642,11 +638,7 @@ public final class TvInputManagerService extends SystemService {
if (sessionToken == userState.mainSessionToken) {
setMainLocked(sessionToken, false, callingUid, userId);
}
- if (sessionState.isRecordingSession) {
- sessionState.session.disconnect();
- } else {
- sessionState.session.release();
- }
+ sessionState.session.release();
}
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in releaseSession", e);
@@ -777,9 +769,9 @@ public final class TvInputManagerService extends SystemService {
}
}
- private void setTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
+ private void updateTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
if (DEBUG) {
- Slog.d(TAG, "setTvInputInfoLocked(inputInfo=" + inputInfo + ")");
+ Slog.d(TAG, "updateTvInputInfoLocked(inputInfo=" + inputInfo + ")");
}
String inputId = inputInfo.getId();
TvInputState inputState = userState.inputMap.get(inputId);
@@ -787,16 +779,13 @@ public final class TvInputManagerService extends SystemService {
Slog.e(TAG, "failed to set input info - unknown input id " + inputId);
return;
}
- if (inputState.info.equals(inputInfo)) {
- return;
- }
inputState.info = inputInfo;
for (ITvInputManagerCallback callback : userState.callbackSet) {
try {
- callback.onTvInputInfoChanged(inputInfo);
+ callback.onTvInputInfoUpdated(inputInfo);
} catch (RemoteException e) {
- Slog.e(TAG, "failed to report changed input info to callback", e);
+ Slog.e(TAG, "failed to report updated input info to callback", e);
}
}
}
@@ -853,7 +842,7 @@ public final class TvInputManagerService extends SystemService {
}
}
- public void setTvInputInfo(TvInputInfo inputInfo, int userId) {
+ public void updateTvInputInfo(TvInputInfo inputInfo, int userId) {
String inputInfoPackageName = inputInfo.getServiceInfo().packageName;
String callingPackageName = getCallingPackageName();
if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) {
@@ -862,12 +851,12 @@ public final class TvInputManagerService extends SystemService {
}
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, "setTvInputInfo");
+ Binder.getCallingUid(), userId, "updateTvInputInfo");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- setTvInputInfoLocked(userState, inputInfo);
+ updateTvInputInfoLocked(userState, inputInfo);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1278,6 +1267,9 @@ public final class TvInputManagerService extends SystemService {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
+ if (sessionState.isRecordingSession) {
+ return;
+ }
// Log the start of watch.
SomeArgs args = SomeArgs.obtain();
@@ -1562,27 +1554,7 @@ public final class TvInputManagerService extends SystemService {
}
@Override
- public void connect(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "connect");
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- try {
- getSessionLocked(sessionToken, callingUid, resolvedUserId).connect(
- channelUri, params);
- } catch (RemoteException | SessionNotFoundException e) {
- Slog.e(TAG, "error in connect", e);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
- public void startRecording(IBinder sessionToken, int userId) {
+ public void startRecording(IBinder sessionToken, @Nullable Uri programHint, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "startRecording");
@@ -1590,7 +1562,8 @@ public final class TvInputManagerService extends SystemService {
try {
synchronized (mLock) {
try {
- getSessionLocked(sessionToken, callingUid, resolvedUserId).startRecording();
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).startRecording(
+ programHint);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in startRecording", e);
}
@@ -1950,6 +1923,7 @@ public final class TvInputManagerService extends SystemService {
pw.decreaseIndent();
}
}
+ mTvInputHardwareManager.dump(fd, writer, args);
}
}
@@ -2157,21 +2131,17 @@ public final class TvInputManagerService extends SystemService {
}
if (serviceState.isHardware) {
- List<TvInputHardwareInfo> hardwareInfoList =
- mTvInputHardwareManager.getHardwareList();
- for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
+ serviceState.hardwareInputList.clear();
+ for (TvInputHardwareInfo hardware : mTvInputHardwareManager.getHardwareList()) {
try {
- serviceState.service.notifyHardwareAdded(hardwareInfo);
+ serviceState.service.notifyHardwareAdded(hardware);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareAdded", e);
}
}
-
- List<HdmiDeviceInfo> deviceInfoList =
- mTvInputHardwareManager.getHdmiDeviceList();
- for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
+ for (HdmiDeviceInfo device : mTvInputHardwareManager.getHdmiDeviceList()) {
try {
- serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
+ serviceState.service.notifyHdmiDeviceAdded(device);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
}
@@ -2474,7 +2444,8 @@ public final class TvInputManagerService extends SystemService {
public void onSessionEvent(String eventType, Bundle eventArgs) {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
+ Slog.d(TAG, "onEvent(eventType=" + eventType + ", eventArgs=" + eventArgs
+ + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
@@ -2491,7 +2462,7 @@ public final class TvInputManagerService extends SystemService {
public void onTimeShiftStatusChanged(int status) {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onTimeShiftStatusChanged()");
+ Slog.d(TAG, "onTimeShiftStatusChanged(status=" + status + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
@@ -2508,7 +2479,7 @@ public final class TvInputManagerService extends SystemService {
public void onTimeShiftStartPositionChanged(long timeMs) {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onTimeShiftStartPositionChanged()");
+ Slog.d(TAG, "onTimeShiftStartPositionChanged(timeMs=" + timeMs + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
@@ -2525,7 +2496,7 @@ public final class TvInputManagerService extends SystemService {
public void onTimeShiftCurrentPositionChanged(long timeMs) {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onTimeShiftCurrentPositionChanged()");
+ Slog.d(TAG, "onTimeShiftCurrentPositionChanged(timeMs=" + timeMs + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
@@ -2541,36 +2512,18 @@ public final class TvInputManagerService extends SystemService {
// For the recording session only
@Override
- public void onConnected() {
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "onConnected()");
- }
- if (mSessionState.session == null || mSessionState.client == null) {
- return;
- }
- try {
- mSessionState.client.onConnected(mSessionState.seq);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in onConnected", e);
- }
- }
- }
-
- // For the recording session only
- @Override
- public void onRecordingStarted() {
+ public void onTuned() {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onRecordingStarted()");
+ Slog.d(TAG, "onTuned()");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
}
try {
- mSessionState.client.onRecordingStarted(mSessionState.seq);
+ mSessionState.client.onTuned(mSessionState.seq);
} catch (RemoteException e) {
- Slog.e(TAG, "error in onRecordingStarted", e);
+ Slog.e(TAG, "error in onTuned", e);
}
}
}
@@ -2580,7 +2533,8 @@ public final class TvInputManagerService extends SystemService {
public void onRecordingStopped(Uri recordedProgramUri) {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onRecordingStopped()");
+ Slog.d(TAG, "onRecordingStopped(recordedProgramUri=" + recordedProgramUri
+ + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
@@ -2598,7 +2552,7 @@ public final class TvInputManagerService extends SystemService {
public void onError(int error) {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "onError()");
+ Slog.d(TAG, "onError(error=" + error + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
diff --git a/services/core/java/com/android/server/twilight/TwilightManager.java b/services/core/java/com/android/server/twilight/TwilightManager.java
index b3de58b279af..56137a406757 100644
--- a/services/core/java/com/android/server/twilight/TwilightManager.java
+++ b/services/core/java/com/android/server/twilight/TwilightManager.java
@@ -20,5 +20,6 @@ import android.os.Handler;
public interface TwilightManager {
void registerListener(TwilightListener listener, Handler handler);
+ void unregisterListener(TwilightListener listener);
TwilightState getCurrentState();
}
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index a71961c8fe9b..6158c929a296 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -19,12 +19,15 @@ package com.android.server.twilight;
import com.android.server.SystemService;
import com.android.server.TwilightCalculator;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
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.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
@@ -33,6 +36,9 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Slog;
@@ -54,6 +60,26 @@ public final class TwilightService extends SystemService {
static final String ACTION_UPDATE_TWILIGHT_STATE =
"com.android.server.action.UPDATE_TWILIGHT_STATE";
+ // The amount of time after or before sunrise over which to start adjusting
+ // twilight affected things. We want the change to happen gradually so that
+ // it is below the threshold of perceptibility and so that the adjustment has
+ // maximum effect well after dusk.
+ private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+
+ // Broadcast when twilight changes.
+ public static final String ACTION_TWILIGHT_CHANGED = "android.intent.action.TWILIGHT_CHANGED";
+
+ public static final String EXTRA_IS_NIGHT = "isNight";
+ public static final String EXTRA_AMOUNT = "amount";
+
+ // Amount of time the TwilightService will stay locked in an override state before switching
+ // back to auto.
+ private static final long RESET_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+ private static final String EXTRA_RESET_USER = "user";
+
+ private static final String ACTION_RESET_TWILIGHT_AUTO =
+ "com.android.server.action.RESET_TWILIGHT_AUTO";
+
final Object mLock = new Object();
AlarmManager mAlarmManager;
@@ -65,6 +91,10 @@ public final class TwilightService extends SystemService {
TwilightState mTwilightState;
+ private int mCurrentUser;
+ private boolean mLocked;
+ private boolean mBootCompleted;
+
public TwilightService(Context context) {
super(context);
}
@@ -75,16 +105,95 @@ public final class TwilightService extends SystemService {
mLocationManager = (LocationManager) getContext().getSystemService(
Context.LOCATION_SERVICE);
mLocationHandler = new LocationHandler();
+ mCurrentUser = ActivityManager.getCurrentUser();
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
- getContext().registerReceiver(mUpdateLocationReceiver, filter);
+ getContext().registerReceiver(mReceiver, filter);
publishLocalService(TwilightManager.class, mService);
}
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ getContext().getContentResolver().registerContentObserver(
+ Secure.getUriFor(Secure.TWILIGHT_MODE), false, mContentObserver, mCurrentUser);
+ mContentObserver.onChange(true);
+ mBootCompleted = true;
+ sendBroadcast();
+ }
+ }
+
+ private void reregisterSettingObserver() {
+ final ContentResolver contentResolver = getContext().getContentResolver();
+ contentResolver.unregisterContentObserver(mContentObserver);
+ contentResolver.registerContentObserver(Secure.getUriFor(Secure.TWILIGHT_MODE), false,
+ mContentObserver, mCurrentUser);
+ mContentObserver.onChange(true);
+ }
+
+ private void setLockedState(TwilightState state) {
+ synchronized (mLock) {
+ // Make sure we aren't locked so we can set the state.
+ mLocked = false;
+ setTwilightState(state);
+ // Make sure we leave the state locked, so it cant be changed.
+ mLocked = true;
+ // TODO: Don't bother updating state when locked.
+ }
+ }
+
+ private void setTwilightState(TwilightState state) {
+ synchronized (mLock) {
+ if (mLocked) {
+ // State has been locked by secure setting, shouldn't be changed.
+ return;
+ }
+ if (!Objects.equal(mTwilightState, state)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Twilight state changed: " + state);
+ }
+
+ mTwilightState = state;
+
+ final int listenerLen = mListeners.size();
+ for (int i = 0; i < listenerLen; i++) {
+ mListeners.get(i).postUpdate();
+ }
+ }
+ }
+ sendBroadcast();
+ }
+
+ private void sendBroadcast() {
+ synchronized (mLock) {
+ if (mTwilightState == null) {
+ return;
+ }
+ if (mBootCompleted) {
+ Intent intent = new Intent(ACTION_TWILIGHT_CHANGED);
+ intent.putExtra(EXTRA_IS_NIGHT, mTwilightState.isNight());
+ intent.putExtra(EXTRA_AMOUNT, mTwilightState.getAmount());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+ }
+ }
+
+ private void scheduleReset() {
+ long resetTime = System.currentTimeMillis() + RESET_TIME;
+ Intent resetIntent = new Intent(ACTION_RESET_TWILIGHT_AUTO);
+ resetIntent.putExtra(EXTRA_RESET_USER, mCurrentUser);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ getContext(), 0, resetIntent, 0);
+ mAlarmManager.cancel(pendingIntent);
+ mAlarmManager.setExact(AlarmManager.RTC, resetTime, pendingIntent);
+ }
+
private static class TwilightListenerRecord implements Runnable {
private final TwilightListener mListener;
private final Handler mHandler;
@@ -133,24 +242,22 @@ public final class TwilightService extends SystemService {
}
}
}
- };
- private void setTwilightState(TwilightState state) {
- synchronized (mLock) {
- if (!Objects.equal(mTwilightState, state)) {
- if (DEBUG) {
- Slog.d(TAG, "Twilight state changed: " + state);
+ @Override
+ public void unregisterListener(TwilightListener listener) {
+ synchronized (mLock) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ if (mListeners.get(i).mListener == listener) {
+ mListeners.remove(i);
+ }
}
- mTwilightState = state;
-
- final int listenerLen = mListeners.size();
- for (int i = 0; i < listenerLen; i++) {
- mListeners.get(i).postUpdate();
+ if (mListeners.size() == 0) {
+ mLocationHandler.disableLocationUpdates();
}
}
}
- }
+ };
// The user has moved if the accuracy circles of the two locations don't overlap.
private static boolean hasMoved(Location from, Location to) {
@@ -183,6 +290,7 @@ public final class TwilightService extends SystemService {
private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
private static final int MSG_PROCESS_NEW_LOCATION = 3;
private static final int MSG_DO_TWILIGHT_UPDATE = 4;
+ private static final int MSG_DISABLE_LOCATION_UPDATES = 5;
private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
@@ -210,6 +318,10 @@ public final class TwilightService extends SystemService {
sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
}
+ public void disableLocationUpdates() {
+ sendEmptyMessage(MSG_DISABLE_LOCATION_UPDATES);
+ }
+
public void requestLocationUpdate() {
sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
}
@@ -311,6 +423,11 @@ public final class TwilightService extends SystemService {
}
break;
+ case MSG_DISABLE_LOCATION_UPDATES:
+ mLocationManager.removeUpdates(mLocationListener);
+ removeMessages(MSG_ENABLE_LOCATION_UPDATES);
+ break;
+
case MSG_DO_TWILIGHT_UPDATE:
updateTwilightState();
break;
@@ -368,11 +485,6 @@ public final class TwilightService extends SystemService {
final long now = System.currentTimeMillis();
- // calculate yesterday's twilight
- mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS,
- mLocation.getLatitude(), mLocation.getLongitude());
- final long yesterdaySunset = mTwilightCalculator.mSunset;
-
// calculate today's twilight
mTwilightCalculator.calculateTwilight(now,
mLocation.getLatitude(), mLocation.getLongitude());
@@ -385,9 +497,19 @@ public final class TwilightService extends SystemService {
mLocation.getLatitude(), mLocation.getLongitude());
final long tomorrowSunrise = mTwilightCalculator.mSunrise;
+ float amount = 0;
+ if (isNight) {
+ if (todaySunrise == -1 || todaySunset == -1) {
+ amount = 1;
+ } else if (now > todaySunset) {
+ amount = Math.min(1, (now - todaySunset) / (float) TWILIGHT_ADJUSTMENT_TIME);
+ } else {
+ amount = Math.max(0, 1
+ - (todaySunrise - now) / (float) TWILIGHT_ADJUSTMENT_TIME);
+ }
+ }
// set twilight state
- TwilightState state = new TwilightState(isNight, yesterdaySunset,
- todaySunrise, todaySunset, tomorrowSunrise);
+ TwilightState state = new TwilightState(isNight, amount);
if (DEBUG) {
Slog.d(TAG, "Updating twilight state: " + state);
}
@@ -402,12 +524,18 @@ public final class TwilightService extends SystemService {
// add some extra time to be on the safe side.
nextUpdate += DateUtils.MINUTE_IN_MILLIS;
- if (now > todaySunset) {
- nextUpdate += tomorrowSunrise;
- } else if (now > todaySunrise) {
- nextUpdate += todaySunset;
+ if (amount == 1 || amount == 0) {
+ if (now > todaySunset) {
+ nextUpdate += tomorrowSunrise;
+ } else if (now > todaySunrise) {
+ nextUpdate += todaySunset;
+ } else {
+ nextUpdate += todaySunrise;
+ }
} else {
- nextUpdate += todaySunrise;
+ // This is the update rate while transitioning.
+ // Leave at 10 min for now (one from above).
+ nextUpdate += 9 * DateUtils.MINUTE_IN_MILLIS;
}
}
@@ -423,9 +551,37 @@ public final class TwilightService extends SystemService {
}
}
- private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+ private final ContentObserver mContentObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ int value = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_LOCKED_OFF, mCurrentUser);
+ if (value == Secure.TWILIGHT_MODE_LOCKED_OFF) {
+ setLockedState(new TwilightState(false, 0));
+ } else if (value == Secure.TWILIGHT_MODE_LOCKED_ON) {
+ setLockedState(new TwilightState(true, 1));
+ } else if (value == Secure.TWILIGHT_MODE_AUTO_OVERRIDE_OFF) {
+ setLockedState(new TwilightState(false, 0));
+ scheduleReset();
+ } else if (value == Secure.TWILIGHT_MODE_AUTO_OVERRIDE_ON) {
+ setLockedState(new TwilightState(true, 1));
+ scheduleReset();
+ } else {
+ mLocked = false;
+ mLocationHandler.requestTwilightUpdate();
+ }
+ }
+ };
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+ mCurrentUser = ActivityManager.getCurrentUser();
+ reregisterSettingObserver();
+ return;
+ }
if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())
&& !intent.getBooleanExtra("state", false)) {
// Airplane mode is now off!
@@ -433,6 +589,12 @@ public final class TwilightService extends SystemService {
return;
}
+ if (ACTION_RESET_TWILIGHT_AUTO.equals(intent.getAction())) {
+ int user = intent.getIntExtra(EXTRA_RESET_USER, 0);
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_AUTO, user);
+ return;
+ }
// Time zone has changed or alarm expired.
mLocationHandler.requestTwilightUpdate();
}
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index 91e24d7d55bf..81abc132011a 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -25,20 +25,11 @@ import java.util.Date;
*/
public class TwilightState {
private final boolean mIsNight;
- private final long mYesterdaySunset;
- private final long mTodaySunrise;
- private final long mTodaySunset;
- private final long mTomorrowSunrise;
+ private final float mAmount;
- TwilightState(boolean isNight,
- long yesterdaySunset,
- long todaySunrise, long todaySunset,
- long tomorrowSunrise) {
+ TwilightState(boolean isNight, float amount) {
mIsNight = isNight;
- mYesterdaySunset = yesterdaySunset;
- mTodaySunrise = todaySunrise;
- mTodaySunset = todaySunset;
- mTomorrowSunrise = tomorrowSunrise;
+ mAmount = amount;
}
/**
@@ -49,35 +40,11 @@ public class TwilightState {
}
/**
- * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
+ * For twilight affects that change gradually over time, this is the amount they
+ * should currently be in effect.
*/
- public long getYesterdaySunset() {
- return mYesterdaySunset;
- }
-
- /**
- * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTodaySunrise() {
- return mTodaySunrise;
- }
-
- /**
- * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
- */
- public long getTodaySunset() {
- return mTodaySunset;
- }
-
- /**
- * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTomorrowSunrise() {
- return mTomorrowSunrise;
+ public float getAmount() {
+ return mAmount;
}
@Override
@@ -88,10 +55,7 @@ public class TwilightState {
public boolean equals(TwilightState other) {
return other != null
&& mIsNight == other.mIsNight
- && mYesterdaySunset == other.mYesterdaySunset
- && mTodaySunrise == other.mTodaySunrise
- && mTodaySunset == other.mTodaySunset
- && mTomorrowSunrise == other.mTomorrowSunrise;
+ && mAmount == other.mAmount;
}
@Override
@@ -103,10 +67,7 @@ public class TwilightState {
public String toString() {
DateFormat f = DateFormat.getDateTimeInstance();
return "{TwilightState: isNight=" + mIsNight
- + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
- + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
- + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
- + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+ + ", mAmount=" + mAmount
+ "}";
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 09c53aeff81e..ba0d34061e9e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.wallpaper;
+import static android.app.WallpaperManager.FLAG_SET_SYSTEM;
+import static android.app.WallpaperManager.FLAG_SET_LOCK;
import static android.os.ParcelFileDescriptor.*;
import android.app.ActivityManagerNative;
@@ -102,9 +104,9 @@ import libcore.io.IoUtils;
public class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperManagerService";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
- final Object mLock = new Object[0];
+ final Object mLock = new Object();
/**
* Minimum time between crashes of a wallpaper service for us to consider
@@ -114,8 +116,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
static final String WALLPAPER = "wallpaper_orig";
static final String WALLPAPER_CROP = "wallpaper";
+ static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
+ static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ // All the various per-user state files we need to be aware of
+ static final String[] sPerUserFiles = new String[] {
+ WALLPAPER, WALLPAPER_CROP,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
+ WALLPAPER_INFO
+ };
+
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
* that the wallpaper has changed. The CREATE is triggered when there is no
@@ -124,22 +135,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
*/
private class WallpaperObserver extends FileObserver {
+ final int mUserId;
final WallpaperData mWallpaper;
final File mWallpaperDir;
final File mWallpaperFile;
- final File mWallpaperCropFile;
+ final File mWallpaperLockFile;
final File mWallpaperInfoFile;
public WallpaperObserver(WallpaperData wallpaper) {
super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
+ mUserId = wallpaper.userId;
mWallpaperDir = getWallpaperDir(wallpaper.userId);
mWallpaper = wallpaper;
mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
- mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP);
+ mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
}
+ private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
+ WallpaperData wallpaper = null;
+ synchronized (mLock) {
+ if (lockChanged) {
+ wallpaper = mLockWallpaperMap.get(mUserId);
+ }
+ if (wallpaper == null) {
+ // no lock-specific wallpaper exists, or sys case, handled together
+ wallpaper = mWallpaperMap.get(mUserId);
+ }
+ }
+ return (wallpaper != null) ? wallpaper : mWallpaper;
+ }
+
@Override
public void onEvent(int event, String path) {
if (path == null) {
@@ -148,38 +175,82 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
final File changedFile = new File(mWallpaperDir, path);
+ // System and system+lock changes happen on the system wallpaper input file;
+ // lock-only changes happen on the dedicated lock wallpaper input file
+ final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
+ final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
+ WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
+
+ if (DEBUG) {
+ Slog.v(TAG, "Wallpaper file change: evt=" + event
+ + " path=" + path
+ + " sys=" + sysWallpaperChanged
+ + " lock=" + lockWallpaperChanged
+ + " imagePending=" + wallpaper.imageWallpaperPending
+ + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
+ + " written=" + written);
+ }
synchronized (mLock) {
- if (mWallpaperFile.equals(changedFile)
- || mWallpaperInfoFile.equals(changedFile)) {
+ if (sysWallpaperChanged || mWallpaperInfoFile.equals(changedFile)) {
// changing the wallpaper means we'll need to back up the new one
long origId = Binder.clearCallingIdentity();
BackupManager bm = new BackupManager(mContext);
bm.dataChanged();
Binder.restoreCallingIdentity(origId);
}
- if (mWallpaperFile.equals(changedFile)) {
- notifyCallbacksLocked(mWallpaper);
- if (mWallpaper.wallpaperComponent == null
+ if (sysWallpaperChanged || lockWallpaperChanged) {
+ notifyCallbacksLocked(wallpaper);
+ if (wallpaper.wallpaperComponent == null
|| event != CLOSE_WRITE // includes the MOVED_TO case
- || mWallpaper.imageWallpaperPending) {
+ || wallpaper.imageWallpaperPending) {
if (written) {
// The image source has finished writing the source image,
// so we now produce the crop rect (in the background), and
// only publish the new displayable (sub)image as a result
// of that work.
- generateCrop(mWallpaper);
- mWallpaper.imageWallpaperPending = false;
- if (mWallpaper.setComplete != null) {
+ if (DEBUG) {
+ Slog.v(TAG, "Wallpaper written; generating crop");
+ }
+ generateCrop(wallpaper);
+ if (DEBUG) {
+ Slog.v(TAG, "Crop done; invoking completion callback");
+ }
+ wallpaper.imageWallpaperPending = false;
+ if (wallpaper.setComplete != null) {
try {
- mWallpaper.setComplete.onWallpaperChanged();
+ wallpaper.setComplete.onWallpaperChanged();
} catch (RemoteException e) {
// if this fails we don't really care; the setting app may just
// have crashed and that sort of thing is a fact of life.
}
}
- bindWallpaperComponentLocked(mImageWallpaper, true,
- false, mWallpaper, null);
- saveSettingsLocked(mWallpaper);
+ if (sysWallpaperChanged) {
+ // If this was the system wallpaper, rebind...
+ bindWallpaperComponentLocked(mImageWallpaper, true,
+ false, wallpaper, null);
+ }
+ if (lockWallpaperChanged
+ || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) {
+ if (DEBUG) {
+ Slog.i(TAG, "Lock-relevant wallpaper changed");
+ }
+ // either a lock-only wallpaper commit or a system+lock event.
+ // if it's system-plus-lock we need to wipe the lock bookkeeping;
+ // we're falling back to displaying the system wallpaper there.
+ if (!lockWallpaperChanged) {
+ mLockWallpaperMap.remove(wallpaper.userId);
+ }
+ // and in any case, tell keyguard about it
+ final IWallpaperManagerCallback cb = mKeyguardListener;
+ if (cb != null) {
+ try {
+ cb.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // Oh well it went away; no big deal
+ }
+ }
+ }
+ saveSettingsLocked(wallpaper.userId);
}
}
}
@@ -194,12 +265,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
private void generateCrop(WallpaperData wallpaper) {
boolean success = false;
boolean needCrop = false;
+ boolean needScale = false;
+
+ if (DEBUG) {
+ Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
+ + Integer.toHexString(wallpaper.whichPending)
+ + " to " + wallpaper.cropFile.getName());
+ }
// Analyse the source; needed in multiple cases
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+ // We'll need to scale if the crop is sufficiently bigger than the display
+
// Legacy case uses an empty crop rect here, so we just preserve the
// source image verbatim
if (!wallpaper.cropHint.isEmpty()) {
@@ -211,7 +291,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
&& options.outWidth >= wallpaper.cropHint.width());
}
- if (!needCrop) {
+ if (!needCrop && !needScale) {
// Simple case: the nominal crop is at least as big as the source image,
// so we take the whole thing and just copy the image file directly.
if (DEBUG) {
@@ -223,7 +303,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
// TODO: fall back to default wallpaper in this case
}
} else {
- // Fancy case: the crop is a subrect of the source
+ // Fancy case: crop and/or scale
FileOutputStream f = null;
BufferedOutputStream bos = null;
try {
@@ -270,6 +350,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
final MyPackageMonitor mMonitor;
final AppOpsManager mAppOpsManager;
WallpaperData mLastWallpaper;
+ IWallpaperManagerCallback mKeyguardListener;
/**
* ID of the current wallpaper, changed every time anything sets a wallpaper.
@@ -283,7 +364,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
*/
final ComponentName mImageWallpaper;
- SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
+ final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
+ final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
int mCurrentUserId;
@@ -291,15 +373,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
int userId;
- final File wallpaperFile;
- final File cropFile;
+ final File wallpaperFile; // source image
+ final File cropFile; // eventual destination
/**
- * Client is currently writing a new image wallpaper.
+ * True while the client is writing a new wallpaper
*/
boolean imageWallpaperPending;
/**
+ * Which new wallpapers are being written; mirrors the 'which'
+ * selector bit field to setWallpaper().
+ */
+ int whichPending;
+
+ /**
* Callback once the set + crop is finished
*/
IWallpaperManagerCallback setComplete;
@@ -345,13 +433,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
final Rect padding = new Rect(0, 0, 0, 0);
- WallpaperData(int userId) {
+ WallpaperData(int userId, String inputFileName, String cropFileName) {
this.userId = userId;
- wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
- cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+ final File wallpaperDir = getWallpaperDir(userId);
+ wallpaperFile = new File(wallpaperDir, inputFileName);
+ cropFile = new File(wallpaperDir, cropFileName);
}
- // Only called in single-threaded boot sequence mode
+ // Called during initialization of a given user's wallpaper bookkeeping
boolean ensureCropExists() {
// if the crop file is not present, copy over the source image to use verbatim
if (!cropFile.exists()) {
@@ -395,7 +484,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
// when we have an engine, but I'm not sure about
// locking there and anyway we always need to be able to
// recover if there is something wrong.
- saveSettingsLocked(mWallpaper);
+ saveSettingsLocked(mWallpaper.userId);
}
}
}
@@ -419,7 +508,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
&& mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
> SystemClock.uptimeMillis()) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true, mWallpaper.userId, null);
+ clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null);
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
}
@@ -498,7 +587,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (!bindWallpaperComponentLocked(comp, false, false,
wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -578,7 +667,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -598,7 +687,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
}
}
if (wallpaper.nextWallpaperComponent != null
@@ -646,7 +735,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
if (!wallpaper.ensureCropExists()) {
- clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null);
}
switchWallpaper(wallpaper, null);
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -706,37 +795,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- void onStoppingUser(int userId) {
- if (userId < 1) return;
- synchronized (mLock) {
- WallpaperData wallpaper = mWallpaperMap.get(userId);
- if (wallpaper != null) {
- if (wallpaper.wallpaperObserver != null) {
- wallpaper.wallpaperObserver.stopWatching();
- wallpaper.wallpaperObserver = null;
- }
- mWallpaperMap.remove(userId);
+ void stopObserver(WallpaperData wallpaper) {
+ if (wallpaper != null) {
+ if (wallpaper.wallpaperObserver != null) {
+ wallpaper.wallpaperObserver.stopWatching();
+ wallpaper.wallpaperObserver = null;
}
}
}
+ void stopObserversLocked(int userId) {
+ stopObserver(mWallpaperMap.get(userId));
+ stopObserver(mLockWallpaperMap.get(userId));
+ mWallpaperMap.remove(userId);
+ mLockWallpaperMap.remove(userId);
+ }
+
void onRemoveUser(int userId) {
if (userId < 1) return;
+
+ final File wallpaperDir = getWallpaperDir(userId);
synchronized (mLock) {
- onStoppingUser(userId);
- File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
- wallpaperFile.delete();
- File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
- cropFile.delete();
- File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
- wallpaperInfoFile.delete();
+ stopObserversLocked(userId);
+ for (String filename : sPerUserFiles) {
+ new File(wallpaperDir, filename).delete();
+ }
}
}
void switchUser(int userId, IRemoteCallback reply) {
synchronized (mLock) {
mCurrentUserId = userId;
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
// Not started watching yet, in case wallpaper data was loaded for other reasons.
if (wallpaper.wallpaperObserver == null) {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -759,32 +849,71 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false, wallpaper.userId, reply);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply);
}
}
- public void clearWallpaper(String callingPackage) {
+ @Override
+ public void clearWallpaper(String callingPackage, int which, int userId) {
if (DEBUG) Slog.v(TAG, "clearWallpaper");
checkPermission(android.Manifest.permission.SET_WALLPAPER);
if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
return;
}
+ if (userId != UserHandle.getCallingUserId()) {
+ // cross-user call
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "WallpaperManagerService");
+ }
+
synchronized (mLock) {
- clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
+ clearWallpaperLocked(false, which, userId, null);
}
}
- void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
- WallpaperData wallpaper = mWallpaperMap.get(userId);
+ void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
+ if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
+ }
+
+ WallpaperData wallpaper = null;
+ if (which == FLAG_SET_LOCK) {
+ wallpaper = mLockWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ // It's already gone; we're done.
+ return;
+ }
+ } else {
+ wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ // Might need to bring it in the first time to establish our rewrite
+ loadSettingsLocked(userId);
+ wallpaper = mWallpaperMap.get(userId);
+ }
+ }
if (wallpaper == null) {
return;
}
- if (wallpaper.wallpaperFile.exists()) {
- wallpaper.wallpaperFile.delete();
- wallpaper.cropFile.delete();
- }
+
final long ident = Binder.clearCallingIdentity();
try {
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
+ wallpaper.cropFile.delete();
+ if (which == FLAG_SET_LOCK) {
+ final IWallpaperManagerCallback cb = mKeyguardListener;
+ if (cb != null) {
+ try {
+ cb.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // Oh well it went away; no big deal
+ }
+ }
+ return;
+ }
+ }
+
RuntimeException e = null;
try {
wallpaper.imageWallpaperPending = false;
@@ -859,7 +988,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
@@ -871,7 +1000,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (width != wallpaper.width || height != wallpaper.height) {
wallpaper.width = width;
wallpaper.height = height;
- saveSettingsLocked(wallpaper);
+ saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
if (wallpaper.connection.mEngine != null) {
@@ -921,14 +1050,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
throw new IllegalArgumentException("padding must be positive: " + padding);
}
if (!padding.equals(wallpaper.padding)) {
wallpaper.padding.set(padding);
- saveSettingsLocked(wallpaper);
+ saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
if (wallpaper.connection.mEngine != null) {
@@ -948,28 +1077,41 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
- Bundle outParams) {
+ @Override
+ public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which,
+ Bundle outParams, int wallpaperUserId) {
+ if (wallpaperUserId != UserHandle.getCallingUserId()) {
+ // cross-user call
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "WallpaperManagerService");
+ }
+
+ if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
+ }
+
synchronized (mLock) {
- // This returns the current user's wallpaper, if called by a system service. Else it
- // returns the wallpaper for the calling user.
- int callingUid = Binder.getCallingUid();
- int wallpaperUserId = 0;
- if (callingUid == android.os.Process.SYSTEM_UID) {
- wallpaperUserId = mCurrentUserId;
- } else {
- wallpaperUserId = UserHandle.getUserId(callingUid);
- }
- WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
+ final SparseArray<WallpaperData> whichSet =
+ (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ WallpaperData wallpaper = whichSet.get(wallpaperUserId);
if (wallpaper == null) {
- return null;
+ // common case, this is the first lookup post-boot of the system or
+ // unified lock, so we bring up the saved state lazily now and recheck.
+ loadSettingsLocked(wallpaperUserId);
+ wallpaper = whichSet.get(wallpaperUserId);
+ if (wallpaper == null) {
+ return null;
+ }
}
try {
if (outParams != null) {
outParams.putInt("width", wallpaper.width);
outParams.putInt("height", wallpaper.height);
}
- wallpaper.callbacks.register(cb);
+ if (cb != null) {
+ wallpaper.callbacks.register(cb);
+ }
if (!wallpaper.cropFile.exists()) {
return null;
}
@@ -994,11 +1136,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
@Override
+ public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
+ checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
+ synchronized (mLock) {
+ mKeyguardListener = cb;
+ }
+ return true;
+ }
+
+ @Override
public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
- if (which == 0) {
+ if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) {
+ Slog.e(TAG, "Must specify a valid wallpaper category to set");
return null;
}
@@ -1017,15 +1169,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ final int userId = UserHandle.getCallingUserId();
+
synchronized (mLock) {
- if (DEBUG) Slog.v(TAG, "setWallpaper");
- int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
+ WallpaperData wallpaper;
+
+ wallpaper = getWallpaperSafeLocked(userId, which);
final long ident = Binder.clearCallingIdentity();
try {
ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
if (pfd != null) {
wallpaper.imageWallpaperPending = true;
+ wallpaper.whichPending = which;
wallpaper.setComplete = completion;
wallpaper.cropHint.set(cropHint);
}
@@ -1048,10 +1204,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- File file = new File(dir, WALLPAPER);
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
- if (!SELinux.restorecon(file)) {
+ if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
return null;
}
wallpaper.name = name;
@@ -1061,7 +1216,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
if (DEBUG) {
Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
- + " name=" + name);
+ + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
}
return fd;
} catch (FileNotFoundException e) {
@@ -1338,50 +1493,33 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
- private void saveSettingsLocked(WallpaperData wallpaper) {
- JournaledFile journal = makeJournaledFile(wallpaper.userId);
- FileOutputStream stream = null;
+ private void saveSettingsLocked(int userId) {
+ JournaledFile journal = makeJournaledFile(userId);
+ FileOutputStream fstream = null;
+ BufferedOutputStream stream = null;
try {
- stream = new FileOutputStream(journal.chooseForWrite(), false);
XmlSerializer out = new FastXmlSerializer();
+ fstream = new FileOutputStream(journal.chooseForWrite(), false);
+ stream = new BufferedOutputStream(fstream);
out.setOutput(stream, StandardCharsets.UTF_8.name());
out.startDocument(null, true);
- out.startTag(null, "wp");
- out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
- out.attribute(null, "width", Integer.toString(wallpaper.width));
- out.attribute(null, "height", Integer.toString(wallpaper.height));
-
- out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
- out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
- out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
- out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+ WallpaperData wallpaper;
- if (wallpaper.padding.left != 0) {
- out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
- }
- if (wallpaper.padding.top != 0) {
- out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
- }
- if (wallpaper.padding.right != 0) {
- out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
- }
- if (wallpaper.padding.bottom != 0) {
- out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
+ wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper != null) {
+ writeWallpaperAttributes(out, "wp", wallpaper);
}
-
- out.attribute(null, "name", wallpaper.name);
- if (wallpaper.wallpaperComponent != null
- && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
- out.attribute(null, "component",
- wallpaper.wallpaperComponent.flattenToShortString());
+ wallpaper = mLockWallpaperMap.get(userId);
+ if (wallpaper != null) {
+ writeWallpaperAttributes(out, "kwp", wallpaper);
}
- out.endTag(null, "wp");
out.endDocument();
- stream.flush();
- FileUtils.sync(stream);
- stream.close();
+
+ stream.flush(); // also flushes fstream
+ FileUtils.sync(fstream);
+ stream.close(); // also closes fstream
journal.commit();
} catch (IOException e) {
IoUtils.closeQuietly(stream);
@@ -1389,6 +1527,40 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ out.startTag(null, tag);
+ out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
+ out.attribute(null, "width", Integer.toString(wallpaper.width));
+ out.attribute(null, "height", Integer.toString(wallpaper.height));
+
+ out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
+ out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
+ out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
+ out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+
+ if (wallpaper.padding.left != 0) {
+ out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
+ }
+ if (wallpaper.padding.top != 0) {
+ out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
+ }
+ if (wallpaper.padding.right != 0) {
+ out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
+ }
+ if (wallpaper.padding.bottom != 0) {
+ out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
+ }
+
+ out.attribute(null, "name", wallpaper.name);
+ if (wallpaper.wallpaperComponent != null
+ && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
+ out.attribute(null, "component",
+ wallpaper.wallpaperComponent.flattenToShortString());
+ }
+ out.endTag(null, tag);
+ }
+
private void migrateFromOld() {
File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
@@ -1417,11 +1589,36 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
* want to update the data. The data is going to be applied when the user switch observer
* is eventually executed.
*/
- private WallpaperData getWallpaperSafeLocked(int userId) {
- WallpaperData wallpaper = mWallpaperMap.get(userId);
+ private WallpaperData getWallpaperSafeLocked(int userId, int which) {
+ // We're setting either just system (work with the system wallpaper),
+ // both (also work with the system wallpaper), or just the lock
+ // wallpaper (update against the existing lock wallpaper if any).
+ // Combined or just-system operations use the 'system' WallpaperData
+ // for this use; lock-only operations use the dedicated one.
+ final SparseArray<WallpaperData> whichSet =
+ (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ WallpaperData wallpaper = whichSet.get(userId);
if (wallpaper == null) {
+ // common case, this is the first lookup post-boot of the system or
+ // unified lock, so we bring up the saved state lazily now and recheck.
loadSettingsLocked(userId);
- wallpaper = mWallpaperMap.get(userId);
+ wallpaper = whichSet.get(userId);
+ // if it's still null here, this is a lock-only operation and there is not
+ // yet a lock-only wallpaper set for this user, so we need to establish
+ // it now.
+ if (wallpaper == null) {
+ if (which == FLAG_SET_LOCK) {
+ wallpaper = new WallpaperData(userId,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ mLockWallpaperMap.put(userId, wallpaper);
+ } else {
+ // sanity fallback: we're in bad shape, but establishing a known
+ // valid system+lock WallpaperData will keep us from dying.
+ Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
+ wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
+ mWallpaperMap.put(userId, wallpaper);
+ }
+ }
}
return wallpaper;
}
@@ -1438,8 +1635,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
WallpaperData wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
- wallpaper = new WallpaperData(userId);
+ wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
mWallpaperMap.put(userId, wallpaper);
+ wallpaper.ensureCropExists();
}
boolean success = false;
try {
@@ -1453,28 +1651,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
if ("wp".equals(tag)) {
- final String idString = parser.getAttributeValue(null, "id");
- if (idString != null) {
- final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
- if (id > mWallpaperId) {
- mWallpaperId = id;
- }
- } else {
- wallpaper.wallpaperId = makeWallpaperIdLocked();
- }
+ // Common to system + lock wallpapers
+ parseWallpaperAttributes(parser, wallpaper);
- wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
- wallpaper.height = Integer.parseInt(parser
- .getAttributeValue(null, "height"));
- wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
- wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
- wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
- wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
- wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
- wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
- wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
- wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
- wallpaper.name = parser.getAttributeValue(null, "name");
+ // A system wallpaper might also be a live wallpaper
String comp = parser.getAttributeValue(null, "component");
wallpaper.nextWallpaperComponent = comp != null
? ComponentName.unflattenFromString(comp)
@@ -1493,6 +1673,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
Slog.v(TAG, "mNextWallpaperComponent:"
+ wallpaper.nextWallpaperComponent);
}
+ } else if ("kwp".equals(tag)) {
+ // keyguard-specific wallpaper for this user
+ WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
+ if (lockWallpaper == null) {
+ lockWallpaper = new WallpaperData(userId,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ mLockWallpaperMap.put(userId, lockWallpaper);
+ }
+ parseWallpaperAttributes(parser, lockWallpaper);
}
}
} while (type != XmlPullParser.END_DOCUMENT);
@@ -1543,6 +1732,31 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) {
+ final String idString = parser.getAttributeValue(null, "id");
+ if (idString != null) {
+ final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
+ if (id > mWallpaperId) {
+ mWallpaperId = id;
+ }
+ } else {
+ wallpaper.wallpaperId = makeWallpaperIdLocked();
+ }
+
+ wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+ wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
+ wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
+ wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
+ wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
+ wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
+ wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
+ wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
+ wallpaper.name = parser.getAttributeValue(null, "name");
+ }
+
private int getMaximumSizeDimension() {
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
@@ -1561,8 +1775,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
WallpaperData wallpaper = null;
boolean success = false;
synchronized (mLock) {
- loadSettingsLocked(0);
- wallpaper = mWallpaperMap.get(0);
+ loadSettingsLocked(UserHandle.USER_SYSTEM);
+ wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
if (wallpaper.nextWallpaperComponent != null
&& !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
@@ -1596,11 +1810,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
if (!success) {
Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
wallpaper.name = "";
- getWallpaperDir(0).delete();
+ getWallpaperDir(UserHandle.USER_SYSTEM).delete();
}
synchronized (mLock) {
- saveSettingsLocked(wallpaper);
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index c3a6f5d2f637..9c770e1fdd27 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -23,14 +23,20 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.os.Binder;
+import android.os.PatternMatcher;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
-import android.provider.Settings.Secure;
+import android.provider.Settings.Global;
import android.util.AndroidRuntimeException;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
@@ -40,6 +46,7 @@ import android.webkit.WebViewFactory;
import com.android.server.SystemService;
+import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -90,7 +97,7 @@ public class WebViewUpdateService extends SystemService {
// change provider when the new version of the package is being installed).
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
&& intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
- synchronized(this) {
+ synchronized(WebViewUpdateService.this) {
if (mCurrentWebViewPackage == null) return;
String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
@@ -101,12 +108,29 @@ public class WebViewUpdateService extends SystemService {
return;
}
+ // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
+ // package, not just a component
+ if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
+ if (!WebViewFactory.entirePackageChanged(intent)) {
+ return;
+ }
+ }
+
+ if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
+ int userId =
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ handleNewUser(userId);
+ return;
+ }
+
+ updateFallbackState(context, intent);
+
for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
boolean updateWebView = false;
- boolean removedOldPackage = false;
+ boolean removedOrChangedOldPackage = false;
String oldProviderName = null;
PackageInfo newPackage = null;
synchronized(WebViewUpdateService.this) {
@@ -124,7 +148,7 @@ public class WebViewUpdateService extends SystemService {
|| mCurrentWebViewPackage == null;
// We removed the old package if we received an intent to remove
// or replace the old package.
- removedOldPackage =
+ removedOrChangedOldPackage =
provider.packageName.equals(oldProviderName);
if (updateWebView) {
onWebViewProviderChanged(newPackage);
@@ -134,14 +158,15 @@ public class WebViewUpdateService extends SystemService {
"relro with " + e);
}
}
- if(updateWebView && !removedOldPackage && oldProviderName != null) {
+ if(updateWebView && !removedOrChangedOldPackage
+ && oldProviderName != null) {
// If the provider change is the result of adding or replacing a
// package that was not the previous provider then we must kill
// packages dependent on the old package ourselves. The framework
// only kills dependents of packages that are being removed.
try {
ActivityManagerNative.getDefault().killPackageDependents(
- oldProviderName, getContext().getUserId());
+ oldProviderName, UserHandle.USER_ALL);
} catch (RemoteException e) {
}
}
@@ -153,12 +178,167 @@ public class WebViewUpdateService extends SystemService {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
+ // Make sure we only receive intents for WebView packages from our config file.
+ for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+ filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
+ }
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
+ IntentFilter userAddedFilter = new IntentFilter();
+ userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
+ getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
+
publishBinderService("webviewupdate", new BinderService());
}
+ private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
+ for (WebViewProviderInfo provider : providers) {
+ if (provider.isAvailableByDefault() && provider.isEnabled()
+ && provider.isValidProvider() && !provider.isFallbackPackage()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static void enablePackageForUser(String packageName, boolean enable, int userId) {
+ try {
+ AppGlobals.getPackageManager().setApplicationEnabledSetting(
+ packageName,
+ enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
+ userId, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
+ }
+ }
+
+ /**
+ * Called when a new user has been added to update the state of its fallback package.
+ */
+ void handleNewUser(int userId) {
+ if (!isFallbackLogicEnabled()) return;
+
+ WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
+ if (fallbackProvider == null) return;
+ boolean existsValidNonFallbackProvider =
+ existsValidNonFallbackProvider(webviewProviders);
+
+ enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
+ userId);
+ }
+
+ /**
+ * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
+ * package that is valid (and available by default) then disable the fallback package,
+ * otherwise, enable the fallback package.
+ */
+ void updateFallbackState(final Context context, final Intent intent) {
+ if (!isFallbackLogicEnabled()) return;
+
+ WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
+
+ if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
+ || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
+ // A package was changed / updated / downgraded, early out if it is not one of the
+ // webview packages that are available by default.
+ String changedPackage = null;
+ for (WebViewProviderInfo provider : webviewProviders) {
+ String webviewPackage = "package:" + provider.packageName;
+ if (webviewPackage.equals(intent.getDataString())) {
+ if (provider.isAvailableByDefault()) {
+ changedPackage = provider.packageName;
+ }
+ break;
+ }
+ }
+ if (changedPackage == null) return;
+ }
+
+ // If there exists a valid and enabled non-fallback package - disable the fallback
+ // package, otherwise, enable it.
+ WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
+ if (fallbackProvider == null) return;
+ boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
+
+ if (existsValidNonFallbackProvider
+ // During an OTA the primary user's WebView state might differ from other users', so
+ // ignore the state of that user during boot.
+ && (fallbackProvider.isEnabled() || intent == null)) {
+ // Uninstall and disable fallback package for all users.
+ context.getPackageManager().deletePackage(fallbackProvider.packageName,
+ new IPackageDeleteObserver.Stub() {
+ public void packageDeleted(String packageName, int returnCode) {
+ // Ignore returnCode since the deletion could fail, e.g. we might be trying
+ // to delete a non-updated system-package (and we should still disable the
+ // package)
+ UserManager userManager =
+ (UserManager)context.getSystemService(Context.USER_SERVICE);
+ // Disable the fallback package for all users.
+ for(UserInfo userInfo : userManager.getUsers()) {
+ enablePackageForUser(packageName, false, userInfo.id);
+ }
+ }
+ }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+ } else if (!existsValidNonFallbackProvider
+ // During an OTA the primary user's WebView state might differ from other users', so
+ // ignore the state of that user during boot.
+ && (!fallbackProvider.isEnabled() || intent==null)) {
+ // Enable the fallback package for all users.
+ UserManager userManager =
+ (UserManager)context.getSystemService(Context.USER_SERVICE);
+ for(UserInfo userInfo : userManager.getUsers()) {
+ enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
+ }
+ }
+ }
+
+ private static boolean isFallbackLogicEnabled() {
+ // Note that this is enabled by default (i.e. if the setting hasn't been set).
+ return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
+ }
+
+ private static void enableFallbackLogic(boolean enable) {
+ Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
+ }
+
+ /**
+ * Returns the only fallback provider, or null if there is none.
+ */
+ private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
+ for (WebViewProviderInfo provider : webviewPackages) {
+ if (provider.isFallbackPackage()) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ private static boolean containsAvailableNonFallbackProvider(
+ WebViewProviderInfo[] webviewPackages) {
+ for (WebViewProviderInfo provider : webviewPackages) {
+ if (provider.isAvailableByDefault() && provider.isEnabled()
+ && provider.isValidProvider() && !provider.isFallbackPackage()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isFallbackPackage(String packageName) {
+ if (packageName == null || !isFallbackLogicEnabled()) return false;
+
+ WebViewProviderInfo[] webviewPackages = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
+ return (fallbackProvider != null
+ && packageName.equals(fallbackProvider.packageName));
+ }
+
/**
* Perform any WebView loading preparations that must happen at boot from the system server,
* after the package manager has started or after an update to the webview is installed.
@@ -166,6 +346,7 @@ public class WebViewUpdateService extends SystemService {
* Currently, this means spawning the child processes which will create the relro files.
*/
public void prepareWebViewInSystemServer() {
+ updateFallbackState(getContext(), null);
try {
synchronized(this) {
updateValidWebViewPackages();
@@ -181,8 +362,10 @@ public class WebViewUpdateService extends SystemService {
/**
* Change WebView provider and provider setting and kill packages using the old provider.
+ * Return the new provider (in case we are in the middle of creating relro files this new
+ * provider will not be in use directly, but will when the relros are done).
*/
- private void changeProviderAndSetting(String newProviderName) {
+ private String changeProviderAndSetting(String newProviderName) {
PackageInfo oldPackage = null;
PackageInfo newPackage = null;
synchronized(this) {
@@ -194,14 +377,14 @@ public class WebViewUpdateService extends SystemService {
if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
// If we don't perform the user change, revert the settings change.
updateUserSetting(newPackage.packageName);
- return;
+ return newPackage.packageName;
}
} catch (WebViewFactory.MissingWebViewPackageException e) {
Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
+ e);
// If we don't perform the user change but don't have an installed WebView package,
// we will have changed the setting and it will be used when a package is available.
- return;
+ return newProviderName;
}
onWebViewProviderChanged(newPackage);
}
@@ -209,11 +392,11 @@ public class WebViewUpdateService extends SystemService {
try {
if (oldPackage != null) {
ActivityManagerNative.getDefault().killPackageDependents(
- oldPackage.packageName, getContext().getUserId());
+ oldPackage.packageName, UserHandle.USER_ALL);
}
} catch (RemoteException e) {
}
- return;
+ return newPackage.packageName;
}
/**
@@ -267,13 +450,13 @@ public class WebViewUpdateService extends SystemService {
}
private static String getUserChosenWebViewProvider() {
- return Settings.Secure.getString(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Secure.WEBVIEW_PROVIDER);
+ return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER);
}
private void updateUserSetting(String newProviderName) {
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.WEBVIEW_PROVIDER,
+ Settings.Global.putString(getContext().getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER,
newProviderName == null ? "" : newProviderName);
}
@@ -348,6 +531,14 @@ public class WebViewUpdateService extends SystemService {
private class BinderService extends IWebViewUpdateService.Stub {
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+ (new WebViewUpdateServiceShellCommand(this)).exec(
+ this, in, out, err, args, resultReceiver);
+ }
+
+
/**
* The shared relro process calls this to notify us that it's done trying to create a relro
* file. This method gets called even if the relro creation has failed or the process
@@ -363,9 +554,14 @@ public class WebViewUpdateService extends SystemService {
return;
}
- synchronized (WebViewUpdateService.this) {
- mNumRelroCreationsFinished++;
- checkIfRelrosDoneLocked();
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (WebViewUpdateService.this) {
+ mNumRelroCreationsFinished++;
+ checkIfRelrosDoneLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@@ -422,7 +618,7 @@ public class WebViewUpdateService extends SystemService {
* This is called from DeveloperSettings when the user changes WebView provider.
*/
@Override // Binder call
- public void changeProviderAndSetting(String newProvider) {
+ public String changeProviderAndSetting(String newProvider) {
if (getContext().checkCallingPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -434,7 +630,7 @@ public class WebViewUpdateService extends SystemService {
throw new SecurityException(msg);
}
- WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+ return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
}
@Override // Binder call
@@ -452,5 +648,26 @@ public class WebViewUpdateService extends SystemService {
return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
}
}
+
+ @Override // Binder call
+ public boolean isFallbackPackage(String packageName) {
+ return WebViewUpdateService.isFallbackPackage(packageName);
+ }
+
+ @Override // Binder call
+ public void enableFallbackLogic(boolean enable) {
+ if (getContext().checkCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: enableFallbackLogic() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ WebViewUpdateService.enableFallbackLogic(enable);
+ }
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
new file mode 100644
index 000000000000..a9461e82a596
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
@@ -0,0 +1,77 @@
+/*
+ * 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.webkit;
+
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.webkit.IWebViewUpdateService;
+
+import java.io.PrintWriter;
+
+class WebViewUpdateServiceShellCommand extends ShellCommand {
+ final IWebViewUpdateService mInterface;
+
+ WebViewUpdateServiceShellCommand(IWebViewUpdateService service) {
+ mInterface = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ // TODO(gsennton) add command for changing WebView provider
+ switch(cmd) {
+ case "enable-redundant-packages":
+ return enableFallbackLogic(false);
+ case "disable-redundant-packages":
+ return enableFallbackLogic(true);
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException e) {
+ pw.println("Remote exception: " + e);
+ }
+ return -1;
+ }
+
+ private int enableFallbackLogic(boolean enable) throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ mInterface.enableFallbackLogic(enable);
+ pw.println("Success");
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("WebView updater commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println("");
+ pw.println(" enable-redundant-packages");
+ pw.println(" Allow a fallback package to be installed and enabled even when a");
+ pw.println(" more-preferred package is available. This command is useful when testing");
+ pw.println(" fallback packages.");
+ pw.println(" disable-redundant-packages");
+ pw.println(" Disallow installing and enabling fallback packages when a more-preferred");
+ pw.println(" package is available.");
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index e6b649e70bdf..2c158188edbc 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -60,6 +60,7 @@ import com.android.internal.R;
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -1019,9 +1020,17 @@ final class AccessibilityController {
boolean focusedWindowAdded = false;
final int visibleWindowCount = visibleWindows.size();
+ int skipRemainingWindowsForTaskId = -1;
+ HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
for (int i = visibleWindowCount - 1; i >= 0; i--) {
final WindowState windowState = visibleWindows.valueAt(i);
final int flags = windowState.mAttrs.flags;
+ final Task task = windowState.getTask();
+
+ // If the window is part of a task that we're finished with - ignore.
+ if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
+ continue;
+ }
// If the window is not touchable - ignore.
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
@@ -1062,10 +1071,19 @@ final class AccessibilityController {
break;
}
- // If a window is modal, no other below can be touched - done.
+ // If a window is modal it prevents other windows from being touched
if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
- break;
+ if (task != null) {
+ // If the window is associated with a particular task, we can skip the
+ // rest of the windows for that task.
+ skipRemainingWindowsForTasks.add(task.mTaskId);
+ continue;
+ } else {
+ // If the window is not associated with a particular task, then it is
+ // globally modal. In this case we can skip all remaining windows.
+ break;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 182148758738..5cb709936bd1 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -46,13 +46,13 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.view.AppTransitionAnimationSpec;
@@ -63,8 +63,6 @@ import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ClipRectAnimation;
-import android.view.animation.ClipRectLRAnimation;
-import android.view.animation.ClipRectTBAnimation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
@@ -73,10 +71,11 @@ import android.view.animation.TranslateAnimation;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
+import com.android.server.wm.animation.ClipRectLRAnimation;
+import com.android.server.wm.animation.ClipRectTBAnimation;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -135,6 +134,16 @@ public class AppTransition implements Dump {
private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
+ /** Interpolator to be used for animations that respond directly to a touch */
+ static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+ /**
+ * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
+ * involved, to make it more understandable.
+ */
+ private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
@@ -199,17 +208,17 @@ public class AppTransition implements Dump {
private final Interpolator mFastOutLinearInInterpolator;
private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
- /** Interpolator to be used for animations that respond directly to a touch */
- private final Interpolator mTouchResponseInterpolator =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
private final int mClipRevealTranslationY;
private int mCurrentUserId = 0;
+ private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
+ private int mLastClipRevealMaxTranslation;
+ private boolean mLastHadClipReveal;
+
AppTransition(Context context, WindowManagerService service) {
mContext = context;
mService = service;
@@ -331,19 +340,25 @@ public class AppTransition implements Dump {
if (!isRunning()) {
mAppTransitionState = APP_STATE_IDLE;
notifyAppTransitionPendingLocked();
+ mLastHadClipReveal = false;
+ mLastClipRevealMaxTranslation = 0;
+ mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
return true;
}
return false;
}
- void goodToGo(AppWindowAnimator openingAppAnimator, AppWindowAnimator closingAppAnimator) {
+ void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
+ ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
mNextAppTransition = TRANSIT_UNSET;
mAppTransitionState = APP_STATE_RUNNING;
notifyAppTransitionStartingLocked(
- openingAppAnimator != null ? openingAppAnimator.mAppToken.token : null,
- closingAppAnimator != null ? closingAppAnimator.mAppToken.token : null,
- openingAppAnimator != null ? openingAppAnimator.animation : null,
- closingAppAnimator != null ? closingAppAnimator.animation : null);
+ topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null,
+ topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null,
+ topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
+ topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
+ mService.getDefaultDisplayContentLocked().getDockedDividerController()
+ .notifyAppTransitionStarting(openingApps, closingApps);
}
void clear() {
@@ -632,50 +647,118 @@ public class AppTransition implements Dump {
bitmap, new Rect(left, top, left + width, top + height));
}
- private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) {
+ /**
+ * @return the duration of the last clip reveal animation
+ */
+ long getLastClipRevealTransitionDuration() {
+ return mLastClipRevealTransitionDuration;
+ }
+
+ /**
+ * @return the maximum distance the app surface is traveling of the last clip reveal animation
+ */
+ int getLastClipRevealMaxTranslation() {
+ return mLastClipRevealMaxTranslation;
+ }
+
+ /**
+ * @return true if in the last app transition had a clip reveal animation, false otherwise
+ */
+ boolean hadClipRevealAnimation() {
+ return mLastHadClipReveal;
+ }
+
+ /**
+ * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
+ * the start rect is outside of the target rect, and there is a lot of movement going on.
+ *
+ * @param cutOff whether the start rect was not fully contained by the end rect
+ * @param translationX the total translation the surface moves in x direction
+ * @param translationY the total translation the surfaces moves in y direction
+ * @param displayFrame our display frame
+ *
+ * @return the duration of the clip reveal animation, in milliseconds
+ */
+ private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
+ float translationY, Rect displayFrame) {
+ if (!cutOff) {
+ return DEFAULT_APP_TRANSITION_DURATION;
+ }
+ final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
+ Math.abs(translationY) / displayFrame.height());
+ return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
+ (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
+ }
+
+ private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
+ Rect displayFrame) {
final Animation anim;
if (enter) {
- // Reveal will expand and move faster in horizontal direction
-
final int appWidth = appFrame.width();
final int appHeight = appFrame.height();
+
// mTmpRect will contain an area around the launcher icon that was pressed. We will
// clip reveal from that area in the final area of the app.
getDefaultNextAppTransitionStartRect(mTmpRect);
float t = 0f;
if (appHeight > 0) {
- t = (float) mTmpRect.left / appHeight;
+ t = (float) mTmpRect.top / displayFrame.height();
}
- int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t);
-
+ int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
+ int translationX = 0;
+ int translationYCorrection = translationY;
int centerX = mTmpRect.centerX();
int centerY = mTmpRect.centerY();
int halfWidth = mTmpRect.width() / 2;
int halfHeight = mTmpRect.height() / 2;
+ int clipStartX = centerX - halfWidth - appFrame.left;
+ int clipStartY = centerY - halfHeight - appFrame.top;
+ boolean cutOff = false;
+
+ // If the starting rectangle is fully or partially outside of the target rectangle, we
+ // need to start the clipping at the edge and then achieve the rest with translation
+ // and extending the clip rect from that edge.
+ if (appFrame.top > centerY - halfHeight) {
+ translationY = (centerY - halfHeight) - appFrame.top;
+ translationYCorrection = 0;
+ clipStartY = 0;
+ cutOff = true;
+ }
+ if (appFrame.left > centerX - halfWidth) {
+ translationX = (centerX - halfWidth) - appFrame.left;
+ clipStartX = 0;
+ cutOff = true;
+ }
+ if (appFrame.right < centerX + halfWidth) {
+ translationX = (centerX + halfWidth) - appFrame.right;
+ clipStartX = appWidth - mTmpRect.width();
+ cutOff = true;
+ }
+ final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
+ translationY, displayFrame);
// Clip third of the from size of launch icon, expand to full width/height
Animation clipAnimLR = new ClipRectLRAnimation(
- centerX - halfWidth, centerX + halfWidth, 0, appWidth);
+ clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
- clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f));
-
- Animation clipAnimTB = new ClipRectTBAnimation(centerY - halfHeight - translationY,
- centerY + halfHeight/ 2 - translationY, 0, appHeight);
- clipAnimTB.setInterpolator(mTouchResponseInterpolator);
- clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION);
-
- // We might be animating entrance of a docked task, so we need the translate to account
- // for the app frame in which the window will reside. Every other calculation here
- // is performed as if the window started at 0,0.
- translationY -= appFrame.top;
- TranslateAnimation translate = new TranslateAnimation(-appFrame.left, 0, translationY,
- 0);
- translate.setInterpolator(mLinearOutSlowInInterpolator);
- translate.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ clipAnimLR.setDuration((long) (duration / 2.5f));
+
+ TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
+ translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
+ : mLinearOutSlowInInterpolator);
+ translate.setDuration(duration);
+
+ Animation clipAnimTB = new ClipRectTBAnimation(
+ clipStartY, clipStartY + mTmpRect.height(),
+ 0, appHeight,
+ translationYCorrection, 0,
+ mLinearOutSlowInInterpolator);
+ clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+ clipAnimTB.setDuration(duration);
// Quick fade-in from icon to app window
- final int alphaDuration = DEFAULT_APP_TRANSITION_DURATION / 4;
+ final long alphaDuration = duration / 4;
AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
alpha.setDuration(alphaDuration);
alpha.setInterpolator(mLinearOutSlowInInterpolator);
@@ -688,6 +771,13 @@ public class AppTransition implements Dump {
set.setZAdjustment(Animation.ZORDER_TOP);
set.initialize(appWidth, appHeight, appWidth, appHeight);
anim = set;
+ mLastHadClipReveal = true;
+ mLastClipRevealTransitionDuration = duration;
+
+ // If the start rect was full inside the target rect (cutOff == false), we don't need
+ // to store the translation, because it's only used if cutOff == true.
+ mLastClipRevealMaxTranslation = cutOff
+ ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
} else {
final long duration;
switch (transit) {
@@ -794,7 +884,7 @@ public class AppTransition implements Dump {
// Animation up from the thumbnail to the full screen
Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
- scale.setInterpolator(mTouchResponseInterpolator);
+ scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(1f, 0f);
alpha.setInterpolator(mThumbnailFadeOutInterpolator);
@@ -802,7 +892,7 @@ public class AppTransition implements Dump {
final float toX = appRect.left + appRect.width() / 2 -
(mTmpRect.left + thumbWidth / 2);
Animation translate = new TranslateAnimation(0, toX, 0, toY);
- translate.setInterpolator(mTouchResponseInterpolator);
+ translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
// This AnimationSet uses the Interpolators assigned above.
@@ -815,7 +905,7 @@ public class AppTransition implements Dump {
// Animation down from the full screen to the thumbnail
Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
- scale.setInterpolator(mTouchResponseInterpolator);
+ scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(0f, 1f);
alpha.setInterpolator(mThumbnailFadeInInterpolator);
@@ -823,7 +913,7 @@ public class AppTransition implements Dump {
final float toX = appRect.left + appRect.width() / 2 -
(mTmpRect.left + thumbWidth / 2);
Animation translate = new TranslateAnimation(toX, 0, toY, 0);
- translate.setInterpolator(mTouchResponseInterpolator);
+ translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
// This AnimationSet uses the Interpolators assigned above.
@@ -835,7 +925,7 @@ public class AppTransition implements Dump {
}
return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
- mTouchResponseInterpolator);
+ TOUCH_RESPONSE_INTERPOLATOR);
}
/**
@@ -967,7 +1057,7 @@ public class AppTransition implements Dump {
int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
THUMBNAIL_APP_TRANSITION_DURATION);
return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
- mTouchResponseInterpolator);
+ TOUCH_RESPONSE_INTERPOLATOR);
}
private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
@@ -1219,8 +1309,9 @@ public class AppTransition implements Dump {
* bigger.
*/
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- int orientation, Rect frame, Rect insets, @Nullable Rect surfaceInsets,
- boolean isVoiceInteraction, boolean freeform, int taskId) {
+ int orientation, Rect frame, Rect displayFrame, Rect insets,
+ @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform,
+ int taskId) {
Animation a;
if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
@@ -1265,7 +1356,7 @@ public class AppTransition implements Dump {
+ " transit=" + appTransitionToString(transit)
+ " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
- a = createClipRevealAnimationLocked(transit, enter, frame);
+ a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation:"
+ " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index fa5ee72f6a8e..a81fba00f7a0 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -153,6 +153,13 @@ public class AppWindowAnimator {
} else {
mClearProlongedAnimation = true;
}
+
+ // Since we are finally starting our animation, we don't need the logic anymore to prevent
+ // the app from showing again if we just moved between stacks. See
+ // {@link WindowState#notifyMovedInStack}.
+ for (int i = mAppToken.allAppWindows.size() - 1; i >= 0; i--) {
+ mAppToken.allAppWindows.get(i).resetJustMovedInStack();
+ }
}
public void setDummyAnimation() {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 93b1d6297a0c..f9e258d35d8e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -159,6 +160,25 @@ class AppWindowToken extends WindowToken {
}
}
+ void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
+ firstWindowDrawn = true;
+
+ // We now have a good window to show, remove dead placeholders
+ removeAllDeadWindows();
+
+ if (startingData != null) {
+ if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
+ + win.mToken + ": first real window is shown, no animation");
+ // If this initial window is animating, stop it -- we will do an animation to reveal
+ // it from behind the starting window, so there is no need for it to also be doing its
+ // own stuff.
+ winAnimator.clearAnimation();
+ winAnimator.mService.mFinishedStarting.add(this);
+ winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
+ }
+ updateReportedVisibilityLocked();
+ }
+
void updateReportedVisibilityLocked() {
if (appToken == null) {
return;
@@ -254,7 +274,7 @@ class AppWindowToken extends WindowToken {
// In cases where there are multiple windows, we prefer the non-exiting window. This
// happens for example when replacing windows during an activity relaunch. When
// constructing the animation, we want the new window, not the exiting one.
- if (win.mExiting) {
+ if (win.mAnimatingExit) {
candidate = win;
} else {
return win;
@@ -307,8 +327,13 @@ class AppWindowToken extends WindowToken {
// If the app already requested to remove its window, we don't modify
// its exiting state. Otherwise the stale window won't get removed on
// exit and could cause focus to be given to the wrong window.
- if (!(win.mRemoveOnExit && win.mExiting)) {
- win.mExiting = exiting;
+ if (!(win.mRemoveOnExit && win.mAnimatingExit)) {
+ win.mAnimatingExit = exiting;
+ }
+ // If we're no longer exiting, remove the window from destroying list
+ if (!win.mAnimatingExit && win.mDestroying) {
+ win.mDestroying = false;
+ service.mDestroySurface.remove(win);
}
}
}
@@ -325,13 +350,13 @@ class AppWindowToken extends WindowToken {
continue;
}
- if (!mAppStopped && !win.mClientRemoveRequested) {
- return;
+ if (!(mAppStopped || win.mWindowRemovalAllowed)) {
+ continue;
}
win.destroyOrSaveSurface();
if (win.mRemoveOnExit) {
- win.mExiting = false;
+ win.mAnimatingExit = false;
service.removeWindowInnerLocked(win);
}
final DisplayContent displayContent = win.getDisplayContent();
@@ -352,6 +377,9 @@ class AppWindowToken extends WindowToken {
void notifyAppStopped() {
mAppStopped = true;
destroySurfaces();
+
+ // Remove any starting window that was added for this app if they are still around.
+ mTask.mService.scheduleRemoveStartingWindowLocked(this);
}
/**
@@ -388,7 +416,9 @@ class AppWindowToken extends WindowToken {
int numDrawn = 0;
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
- w.restoreSavedSurface();
+ if (w.hasSavedSurface()) {
+ w.restoreSavedSurface();
+ }
if (w != startingWindow && !w.mAppDied
&& (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
numInteresting++;
@@ -398,7 +428,7 @@ class AppWindowToken extends WindowToken {
}
}
- allDrawn |= (numInteresting == numDrawn);
+ allDrawn |= (numInteresting > 0) && (numInteresting == numDrawn);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
"restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn);
@@ -587,6 +617,9 @@ class AppWindowToken extends WindowToken {
if (paused) {
pw.print(prefix); pw.print("paused="); pw.println(paused);
}
+ if (mAppStopped) {
+ pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
+ }
if (numInterestingWindows != 0 || numDrawnWindows != 0
|| allDrawn || mAppAnimator.allDrawn) {
pw.print(prefix); pw.print("numInterestingWindows=");
@@ -612,7 +645,7 @@ class AppWindowToken extends WindowToken {
pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
pw.print(" startingView="); pw.print(startingView);
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
- pw.print(" startingMoved"); pw.println(startingMoved);
+ pw.print(" startingMoved="); pw.println(startingMoved);
}
if (!mFrozenBounds.isEmpty()) {
pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 0678ca2de365..f0efebed0747 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -24,6 +24,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Rect;
+import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.animation.LinearInterpolator;
@@ -39,7 +40,10 @@ import android.view.animation.LinearInterpolator;
* The object that is resized needs to implement {@link AnimateBoundsUser} interface.
*/
public class BoundsAnimationController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "BoundsAnimationController" : TAG_WM;
+ private static final boolean DEBUG_LOCAL = false;
+ private static final boolean DEBUG = DEBUG_LOCAL || DEBUG_ANIM;
+ private static final String TAG = TAG_WITH_CLASS_NAME || DEBUG_LOCAL
+ ? "BoundsAnimationController" : TAG_WM;
private static final int DEBUG_ANIMATION_SLOW_DOWN_FACTOR = 1;
// Only accessed on UI thread.
@@ -80,9 +84,9 @@ public class BoundsAnimationController {
mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f);
mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value + 0.5f);
mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value + 0.5f);
- if (DEBUG_ANIM) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + ", mBounds="
- + mTmpRect + ", from=" + mFrom + ", mTo=" + mTo + ", value=" + value
- + ", remains=" + remains);
+ if (DEBUG) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + " mBounds="
+ + mTmpRect + " from=" + mFrom + " mTo=" + mTo + " value=" + value
+ + " remains=" + remains);
if (!mTarget.setSize(mTmpRect)) {
// Whoops, the target doesn't feel like animating anymore. Let's immediately finish
// any further animation.
@@ -93,6 +97,8 @@ public class BoundsAnimationController {
@Override
public void onAnimationStart(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
+ + " mReplacement=" + mReplacement);
if (!mReplacement) {
mTarget.onAnimationStart();
}
@@ -100,6 +106,8 @@ public class BoundsAnimationController {
@Override
public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
+ + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
finishAnimation();
if (mMoveToFullScreen && !mWillReplace) {
mTarget.moveToFullscreen();
@@ -114,10 +122,18 @@ public class BoundsAnimationController {
@Override
public void cancel() {
mWillReplace = true;
+ if (DEBUG) Slog.d(TAG, "cancel: willReplace mTarget=" + mTarget);
super.cancel();
}
+ /** Returns true if the animation target is the same as the input bounds. */
+ public boolean isAnimatingTo(Rect bounds) {
+ return mTo.equals(bounds);
+ }
+
private void finishAnimation() {
+ if (DEBUG) Slog.d(TAG, "finishAnimation: mTarget=" + mTarget
+ + " callers" + Debug.getCallers(2));
if (!mWillReplace) {
mTarget.onAnimationEnd();
}
@@ -167,7 +183,18 @@ public class BoundsAnimationController {
final BoundsAnimator existing = mRunningAnimations.get(target);
final boolean replacing = existing != null;
+
+ if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to
+ + " moveToFullscreen=" + moveToFullscreen + " replacing=" + replacing);
+
if (replacing) {
+ if (existing.isAnimatingTo(to)) {
+ // Just les the current animation complete if it has the same destination as the
+ // one we are trying to start.
+ if (DEBUG) Slog.d(TAG, "animateBounds: same destination as existing=" + existing
+ + " ignoring...");
+ return;
+ }
existing.cancel();
}
final BoundsAnimator animator =
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0c429e5a1cd2..73cea52adb0f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -19,6 +19,9 @@ package com.android.server.wm;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
@@ -124,7 +127,7 @@ class DisplayContent {
isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
mService = service;
initializeDisplayBaseInfo();
- mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
+ mDividerControllerLocked = new DockedStackDividerController(service, this);
mDimLayerController = new DimLayerController(this);
}
@@ -603,8 +606,55 @@ class DisplayContent {
return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
}
+ /**
+ * @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);
return (stack != null && stack.isVisibleLocked()) ? stack : null;
}
+
+ /**
+ * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
+ * visible, as long as it's not hidden because the current user doesn't have any tasks there.
+ */
+ TaskStack getDockedStackVisibleForUserLocked() {
+ final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ return (stack != null && stack.isVisibleForUserLocked()) ? stack : null;
+ }
+
+ /**
+ * Find the visible, touch-deliverable window under the given point
+ */
+ WindowState getTouchableWinAtPointLocked(float xf, float yf) {
+ WindowState touchedWin = null;
+ final int x = (int) xf;
+ final int y = (int) yf;
+
+ for (int i = mWindows.size() - 1; i >= 0; i--) {
+ WindowState window = mWindows.get(i);
+ final int flags = window.mAttrs.flags;
+ if (!window.isVisibleLw()) {
+ continue;
+ }
+ if ((flags & FLAG_NOT_TOUCHABLE) != 0) {
+ continue;
+ }
+
+ window.getVisibleBounds(mTmpRect);
+ if (!mTmpRect.contains(x, y)) {
+ continue;
+ }
+
+ window.getTouchableRegion(mTmpRegion);
+
+ final int touchFlags = flags & (FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL);
+ if (mTmpRegion.contains(x, y) || touchFlags == 0) {
+ touchedWin = window;
+ break;
+ }
+ }
+
+ return touchedWin;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 412a45500157..b6aa3f2ed4b0 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -20,19 +20,26 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.IDockedStackListener;
import android.view.SurfaceControl;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.server.wm.DimLayer.DimLayerUser;
+import java.util.ArrayList;
+
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -43,25 +50,65 @@ public class DockedStackDividerController implements DimLayerUser {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
+ /**
+ * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
+ * revealing surface at the earliest.
+ */
+ private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
+
+ /**
+ * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
+ * revealing surface at the latest.
+ */
+ private static final float CLIP_REVEAL_MEET_LAST = 1f;
+
+ /**
+ * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
+ * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
+ */
+ private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
+
+ /**
+ * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
+ * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
+ */
+ private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
+
+ private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
private final int mDividerWindowWidth;
private final int mDividerInsets;
private boolean mResizing;
private WindowState mWindow;
private final Rect mTmpRect = new Rect();
+ private final Rect mTmpRect2 = new Rect();
private final Rect mLastRect = new Rect();
private boolean mLastVisibility = false;
private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
= new RemoteCallbackList<>();
private final DimLayer mDimLayer;
- DockedStackDividerController(Context context, DisplayContent displayContent) {
+ private boolean mMinimizedDock;
+ private boolean mAnimating;
+ private boolean mAnimationStarted;
+ private long mAnimationStartTime;
+ private float mAnimationStart;
+ private float mAnimationTarget;
+ private long mAnimationDuration;
+ private final Interpolator mMinimizedDockInterpolator;
+ private float mMaximizeMeetFraction;
+
+ DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
+ mService = service;
mDisplayContent = displayContent;
+ final Context context = service.mContext;
mDividerWindowWidth = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
mDividerInsets = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_insets);
mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
+ mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
+ context, android.R.interpolator.fast_out_slow_in);
}
boolean isResizing() {
@@ -77,7 +124,17 @@ public class DockedStackDividerController implements DimLayerUser {
}
void setResizing(boolean resizing) {
- mResizing = resizing;
+ if (mResizing != resizing) {
+ mResizing = resizing;
+ resetDragResizingChangeReported();
+ }
+ }
+
+ private void resetDragResizingChangeReported() {
+ final WindowList windowList = mDisplayContent.getWindowList();
+ for (int i = windowList.size() - 1; i >= 0; i--) {
+ windowList.get(i).resetDragResizingChangeReported();
+ }
}
void setWindow(WindowState window) {
@@ -90,7 +147,9 @@ public class DockedStackDividerController implements DimLayerUser {
return;
}
TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID);
- final boolean visible = stack != null && stack.isVisibleLocked();
+
+ // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
+ final boolean visible = stack != null;
if (mLastVisibility == visible && !force) {
return;
}
@@ -166,6 +225,19 @@ public class DockedStackDividerController implements DimLayerUser {
mDockedStackListeners.finishBroadcast();
}
+ void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
+ }
+ }
+ mDockedStackListeners.finishBroadcast();
+ }
+
void registerDockedStackListener(IDockedStackListener listener) {
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
@@ -193,6 +265,183 @@ public class DockedStackDividerController implements DimLayerUser {
SurfaceControl.closeTransaction();
}
+ /**
+ * Notifies the docked stack divider controller of a visibility change that happens without
+ * an animation.
+ */
+ void notifyAppVisibilityChanged(AppWindowToken wtoken, boolean visible) {
+ final Task task = wtoken.mTask;
+ if (!task.isHomeTask() || !task.isVisibleForUser()) {
+ return;
+ }
+
+ // If the stack is completely offscreen, this might just be an intermediate state when
+ // docking a task/launching recents at the same time, but home doesn't actually get
+ // visible after the state settles in.
+ if (isWithinDisplay(task)
+ && mDisplayContent.getDockedStackVisibleForUserLocked() != null) {
+ setMinimizedDockedStack(visible, false /* animate */);
+ }
+ }
+
+ void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps,
+ ArraySet<AppWindowToken> closingApps) {
+ if (containsHomeTaskWithinDisplay(openingApps)) {
+ setMinimizedDockedStack(true /* minimized */, true /* animate */);
+ } else if (containsHomeTaskWithinDisplay(closingApps)) {
+ setMinimizedDockedStack(false /* minimized */, true /* animate */);
+ }
+ }
+
+ private boolean containsHomeTaskWithinDisplay(ArraySet<AppWindowToken> apps) {
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ final Task task = apps.valueAt(i).mTask;
+ if (task != null && task.isHomeTask()) {
+ return isWithinDisplay(task);
+ }
+ }
+ return false;
+ }
+
+ private boolean isWithinDisplay(Task task) {
+ task.mStack.getBounds(mTmpRect);
+ mDisplayContent.getLogicalDisplayRect(mTmpRect2);
+ return mTmpRect.intersect(mTmpRect2);
+ }
+
+ /**
+ * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
+ * docked stack are heavily clipped so you can only see a minimal peek state.
+ *
+ * @param minimizedDock Whether the docked stack is currently minimized.
+ * @param animate Whether to animate the change.
+ */
+ private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
+ if (minimizedDock == mMinimizedDock
+ || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
+ return;
+ }
+
+ mMinimizedDock = minimizedDock;
+ if (minimizedDock) {
+ if (animate) {
+ startAdjustAnimation(0f, 1f);
+ } else {
+ setMinimizedDockedStack(true);
+ }
+ } else {
+ if (animate) {
+ startAdjustAnimation(1f, 0f);
+ } else {
+ setMinimizedDockedStack(false);
+ }
+ }
+ }
+
+ private void startAdjustAnimation(float from, float to) {
+ mAnimating = true;
+ mAnimationStarted = false;
+ mAnimationStart = from;
+ mAnimationTarget = to;
+ }
+
+ private void setMinimizedDockedStack(boolean minimized) {
+ final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+ if (stack == null) {
+ return;
+ }
+ if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ notifyDockedStackMinimizedChanged(minimized, 0);
+ }
+
+ private boolean isAnimationMaximizing() {
+ return mAnimationTarget == 0f;
+ }
+
+ public boolean animate(long now) {
+ if (!mAnimating) {
+ return false;
+ }
+
+ final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+ 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));
+ }
+ float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
+ t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
+ .getInterpolation(t);
+ if (stack != null) {
+ if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+ if (t >= 1.0f) {
+ mAnimating = false;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
+ */
+ private float getMinimizeAmount(TaskStack stack, float t) {
+ final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
+ if (isAnimationMaximizing()) {
+ return adjustMaximizeAmount(stack, t, naturalAmount);
+ } else {
+ return naturalAmount;
+ }
+ }
+
+ /**
+ * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
+ * during the transition such that the edge of the clip reveal rect is met earlier in the
+ * transition so we don't create a visible "hole", but only if both the clip reveal and the
+ * docked stack divider start from about the same portion on the screen.
+ */
+ private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
+ if (mMaximizeMeetFraction == 1f) {
+ return naturalAmount;
+ }
+ final int minimizeDistance = stack.getMinimizeDistance();
+ float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
+ / (float) minimizeDistance;
+ final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
+ final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
+ return amountPrime * t2 + naturalAmount * (1 - t2);
+ }
+
+ /**
+ * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
+ * edge. See {@link #adjustMaximizeAmount}.
+ */
+ private float getClipRevealMeetFraction(TaskStack stack) {
+ if (!isAnimationMaximizing() || stack == null ||
+ !mService.mAppTransition.hadClipRevealAnimation()) {
+ return 1f;
+ }
+ final int minimizeDistance = stack.getMinimizeDistance();
+ final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
+ / (float) minimizeDistance;
+ final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
+ / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
+ return CLIP_REVEAL_MEET_EARLIEST
+ + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
+ }
+
@Override
public boolean isFullscreen() {
return false;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d1c088175a17..cf27b9722de3 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -24,15 +24,18 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
import android.hardware.input.InputManager;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.IUserManager;
import android.util.Slog;
import android.view.Display;
import android.view.DragEvent;
@@ -66,6 +69,13 @@ import java.util.ArrayList;
class DragState {
private static final long ANIMATION_DURATION_MS = 500;
+ private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
+ View.DRAG_FLAG_GLOBAL_URI_WRITE;
+
+ private static final int DRAG_FLAGS_URI_PERMISSIONS = DRAG_FLAGS_URI_ACCESS |
+ View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
+ View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
+
final WindowManagerService mService;
IBinder mToken;
SurfaceControl mSurfaceControl;
@@ -73,6 +83,8 @@ class DragState {
IBinder mLocalWin;
int mPid;
int mUid;
+ int mSourceUserId;
+ boolean mCrossProfileCopyAllowed;
ClipData mData;
ClipDescription mDataDescription;
int mTouchSource;
@@ -88,10 +100,7 @@ class DragState {
WindowState mTargetWindow;
ArrayList<WindowState> mNotifiedWindows;
boolean mDragInProgress;
- Display mDisplay;
-
- private final Region mTmpRegion = new Region();
- private final Rect mTmpRect = new Rect();
+ DisplayContent mDisplayContent;
private Animation mAnimation;
final Transformation mTransformation = new Transformation();
@@ -124,11 +133,12 @@ class DragState {
* @param display The Display that the window being dragged is on.
*/
void register(Display display) {
- mDisplay = display;
if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
if (mClientChannel != null) {
Slog.e(TAG_WM, "Duplicate register of drag input channel");
} else {
+ mDisplayContent = mService.getDisplayContentLocked(display.getDisplayId());
+
InputChannel[] channels = InputChannel.openInputChannelPair("drag");
mServerChannel = channels[0];
mClientChannel = channels[1];
@@ -142,7 +152,7 @@ class DragState {
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
- mDisplay.getDisplayId());
+ display.getDisplayId());
mDragWindowHandle.name = "drag";
mDragWindowHandle.inputChannel = mServerChannel;
mDragWindowHandle.layer = getDragLayerLw();
@@ -167,7 +177,7 @@ class DragState {
mDragWindowHandle.frameLeft = 0;
mDragWindowHandle.frameTop = 0;
Point p = new Point();
- mDisplay.getRealSize(p);
+ display.getRealSize(p);
mDragWindowHandle.frameRight = p.x;
mDragWindowHandle.frameBottom = p.y;
@@ -221,20 +231,30 @@ class DragState {
mNotifiedWindows.clear();
mDragInProgress = true;
+ mSourceUserId = UserHandle.getUserId(mUid);
+
+ final IUserManager userManager =
+ (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
+ try {
+ mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
+ UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
+ mCrossProfileCopyAllowed = false;
+ }
+
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
}
- final WindowList windows = mService.getWindowListLocked(mDisplay);
- if (windows != null) {
- final int N = windows.size();
- for (int i = 0; i < N; i++) {
- sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
- }
+ final WindowList windows = mDisplayContent.getWindowList();
+ final int N = windows.size();
+ for (int i = 0; i < N; i++) {
+ sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
}
}
- /* helper - send a caller-provided event, presumed to be DRAG_STARTED, if the
+ /* helper - send a ACTION_DRAG_STARTED event, if the
* designated window is potentially a drop recipient. There are race situations
* around DRAG_ENDED broadcast, so we make sure that once we've declared that
* the drag has ended, we never send out another DRAG_STARTED for this drag action.
@@ -244,19 +264,7 @@ class DragState {
*/
private void sendDragStartedLw(WindowState newWin, float touchX, float touchY,
ClipDescription desc) {
- // Don't actually send the event if the drag is supposed to be pinned
- // to the originating window but 'newWin' is not that window.
- if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
- final IBinder winBinder = newWin.mClient.asBinder();
- if (winBinder != mLocalWin) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "Not dispatching local DRAG_STARTED to " + newWin);
- }
- return;
- }
- }
-
- if (mDragInProgress && newWin.isPotentialDragTarget()) {
+ if (mDragInProgress && isValidDropTarget(newWin)) {
DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
touchX, touchY, null, desc, null, null, false);
try {
@@ -274,17 +282,33 @@ class DragState {
}
}
- /* helper - construct and send a DRAG_STARTED event only if the window has not
+ private boolean isValidDropTarget(WindowState targetWin) {
+ if (targetWin == null) {
+ return false;
+ }
+ if (!targetWin.isPotentialDragTarget()) {
+ return false;
+ }
+ if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
+ // Drag is limited to the current window.
+ if (mLocalWin != targetWin.mClient.asBinder()) {
+ return false;
+ }
+ }
+
+ return mCrossProfileCopyAllowed ||
+ mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
+ }
+
+ /* helper - send a ACTION_DRAG_STARTED event only if the window has not
* previously been notified, i.e. it became visible after the drag operation
* was begun. This is a rare case.
*/
void sendDragStartedIfNeededLw(WindowState newWin) {
if (mDragInProgress) {
// If we have sent the drag-started, we needn't do so again
- for (WindowState ws : mNotifiedWindows) {
- if (ws == newWin) {
- return;
- }
+ if (isWindowNotified(newWin)) {
+ return;
}
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
@@ -293,6 +317,15 @@ class DragState {
}
}
+ private boolean isWindowNotified(WindowState newWin) {
+ for (WindowState ws : mNotifiedWindows) {
+ if (ws == newWin) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void broadcastDragEndedLw() {
final int myPid = Process.myPid();
@@ -346,7 +379,9 @@ class DragState {
private void cleanUpDragLw() {
broadcastDragEndedLw();
- restorePointerIconLw();
+ if (isFromSource(InputDevice.SOURCE_MOUSE)) {
+ mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
+ }
// stop intercepting input
unregister();
@@ -384,19 +419,18 @@ class DragState {
void notifyLocationLw(float x, float y) {
// Tell the affected window
- WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+ WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
if (touchedWin == null) {
if (DEBUG_DRAG) Slog.d(TAG_WM, "No touched win at x=" + x + " y=" + y);
return;
}
- if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
- final IBinder touchedBinder = touchedWin.mClient.asBinder();
- if (touchedBinder != mLocalWin) {
- // This drag is pinned only to the originating window, but the drag
- // point is outside that window. Pretend it's over empty space.
- touchedWin = null;
- }
+
+ if (!isWindowNotified(touchedWin)) {
+ // The drag point is over a window which was not notified about a drag start.
+ // Pretend it's over empty space.
+ touchedWin = null;
}
+
try {
final int myPid = Process.myPid();
@@ -430,22 +464,19 @@ class DragState {
mTargetWindow = touchedWin;
}
- WindowState getDropTargetWinLw(float x, float y) {
- return getTouchedWinAtPointLw(x, y);
- }
-
- // Tell the drop target about the data. Returns 'true' if we can immediately
+ // Find the drop target and tell it about the data. Returns 'true' if we can immediately
// dispatch the global drag-ended message, 'false' if we need to wait for a
// result from the recipient.
- boolean notifyDropLw(WindowState touchedWin, IDropPermissions dropPermissions,
- float x, float y) {
+ boolean notifyDropLw(float x, float y) {
if (mAnimation != null) {
return false;
}
mCurrentX = x;
mCurrentY = y;
- if (touchedWin == null) {
+ WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
+
+ if (!isWindowNotified(touchedWin)) {
// "drop" outside a valid window -- no recipient to apply a
// timeout to, and we can send the drag-ended message immediately.
mDragResult = false;
@@ -455,6 +486,23 @@ class DragState {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "sending DROP to " + touchedWin);
}
+
+ final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
+
+ DropPermissionsHandler dropPermissions = null;
+ if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
+ (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
+ dropPermissions = new DropPermissionsHandler(
+ mData,
+ mUid,
+ touchedWin.getOwningPackage(),
+ mFlags & DRAG_FLAGS_URI_PERMISSIONS,
+ mSourceUserId,
+ targetUserId);
+ }
+ if (mSourceUserId != targetUserId){
+ mData.fixUris(mSourceUserId);
+ }
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
@@ -478,77 +526,17 @@ class DragState {
return false;
}
- // Find the visible, touch-deliverable window under the given point
- private WindowState getTouchedWinAtPointLw(float xf, float yf) {
- WindowState touchedWin = null;
- final int x = (int) xf;
- final int y = (int) yf;
-
- final WindowList windows = mService.getWindowListLocked(mDisplay);
- if (windows == null) {
- return null;
- }
- final int N = windows.size();
- for (int i = N - 1; i >= 0; i--) {
- WindowState child = windows.get(i);
- final int flags = child.mAttrs.flags;
- if (!child.isVisibleLw()) {
- // not visible == don't tell about drags
- continue;
- }
- if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
- // not touchable == don't tell about drags
- continue;
- }
-
- child.getVisibleBounds(mTmpRect);
- if (!mTmpRect.contains(x, y)) {
- // outside of this window's activity stack == don't tell about drags
- continue;
- }
-
- child.getTouchableRegion(mTmpRegion);
-
- final int touchFlags = flags &
- (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- if (mTmpRegion.contains(x, y) || touchFlags == 0) {
- // Found it
- touchedWin = child;
- break;
- }
- }
-
- return touchedWin;
- }
-
private static DragEvent obtainDragEvent(WindowState win, int action,
float x, float y, Object localState,
ClipDescription description, ClipData data,
IDropPermissions dropPermissions,
boolean result) {
- final float winX = translateToWindowX(win, x);
- final float winY = translateToWindowY(win, y);
+ final float winX = win.translateToWindowX(x);
+ final float winY = win.translateToWindowY(y);
return DragEvent.obtain(action, winX, winY, localState, description, data,
dropPermissions, result);
}
- private static float translateToWindowX(WindowState win, float x) {
- float winX = x - win.mFrame.left;
- if (win.mEnforceSizeCompat) {
- winX *= win.mGlobalScale;
- }
- return winX;
- }
-
- private static float translateToWindowY(WindowState win, float y) {
- float winY = y - win.mFrame.top;
- if (win.mEnforceSizeCompat) {
- winY *= win.mGlobalScale;
- }
- return winY;
- }
-
boolean stepAnimationLocked(long currentTimeMs) {
if (mAnimation == null) {
return false;
@@ -604,21 +592,4 @@ class DragState {
InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
}
}
-
- private void restorePointerIconLw() {
- if (isFromSource(InputDevice.SOURCE_MOUSE)) {
- WindowState touchWin = getTouchedWinAtPointLw(mCurrentX, mCurrentY);
- if (touchWin != null) {
- try {
- touchWin.mClient.updatePointerIcon(
- translateToWindowX(touchWin, mCurrentX),
- translateToWindowY(touchWin, mCurrentY));
- return;
- } catch (RemoteException e) {
- Slog.w(TAG_WM, "unable to restore pointer icon");
- }
- }
- InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_DEFAULT);
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index a8d974f729a6..a589f894e3bc 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -369,7 +369,12 @@ final class Session extends IWindowSession.Stub
if (DEBUG_TASK_POSITIONING) Slog.d(
TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
- return mService.startMovingTask(window, startX, startY);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mService.startMovingTask(window, startX, startY);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
public void reportDropResult(IWindow window, boolean consumed) {
@@ -528,6 +533,16 @@ final class Session extends IWindowSession.Stub
}
}
+ @Override
+ public void updatePointerIcon(IWindow window) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mService.updatePointerIcon(window);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (WindowManagerService.localLOGV) Slog.v(
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4167ac48daa9..c7b559904209 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
@@ -134,12 +135,6 @@ class Task implements DimLayer.DimLayerUser {
mShowNonResizeableDockToast = false;
- if (isResizeable()) {
- Slog.wtf(TAG,
- "Trying to show non-resizeable toast when task is resizeable task=" + this);
- return;
- }
-
if (mResizeMode == RESIZE_MODE_UNRESIZEABLE) {
final String text =
mService.mContext.getString(R.string.dock_non_resizeble_failed_to_dock_text);
@@ -148,7 +143,7 @@ class Task implements DimLayer.DimLayerUser {
}
final int dockSide = mStack.getDockSide();
- if (!inCropWindowsResizeMode() || dockSide == DOCKED_INVALID) {
+ if (mResizeMode != RESIZE_MODE_FORCE_RESIZEABLE || dockSide == DOCKED_INVALID) {
return;
}
@@ -176,7 +171,7 @@ class Task implements DimLayer.DimLayerUser {
yOffset = mTmpRect2.bottom - mTmpRect.bottom;
}
final String text =
- mService.mContext.getString(R.string.dock_cropped_windows_text);
+ mService.mContext.getString(R.string.dock_forced_resizable);
mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST,
xOffset, yOffset, text).sendToTarget();
}
@@ -247,7 +242,15 @@ class Task implements DimLayer.DimLayerUser {
mStack.removeTask(this);
}
stack.positionTask(this, position, showForAllUsers());
- setBounds(bounds, config);
+ resizeLocked(bounds, config, false /* force */);
+
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ win.notifyMovedInStack();
+ }
+ }
}
boolean removeAppToken(AppWindowToken wtoken) {
@@ -272,7 +275,7 @@ class Task implements DimLayer.DimLayerUser {
}
/** Set the task bounds. Passing in null sets the bounds to fullscreen. */
- int setBounds(Rect bounds, Configuration config) {
+ private int setBounds(Rect bounds, Configuration config) {
if (config == null) {
config = Configuration.EMPTY;
}
@@ -357,6 +360,10 @@ class Task implements DimLayer.DimLayerUser {
return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
}
+ boolean isHomeTask() {
+ return mHomeTask;
+ }
+
private boolean inCropWindowsResizeMode() {
return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
}
@@ -536,7 +543,20 @@ class Task implements DimLayer.DimLayerUser {
}
void setDragResizing(boolean dragResizing) {
- mDragResizing = dragResizing;
+ if (mDragResizing != dragResizing) {
+ mDragResizing = dragResizing;
+ resetDragResizingChangeReported();
+ }
+ }
+
+ void resetDragResizingChangeReported() {
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ win.resetDragResizingChangeReported();
+ }
+ }
}
boolean isDragResizing() {
@@ -581,13 +601,21 @@ class Task implements DimLayer.DimLayerUser {
void resizeWindows() {
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
- final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ final AppWindowToken atoken = mAppTokens.get(activityNdx);
+
+ // Some windows won't go through the resizing process, if they don't have a surface, so
+ // destroy all saved surfaces here.
+ atoken.destroySavedSurfaces();
+ final ArrayList<WindowState> windows = atoken.allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (win.mHasSurface && !resizingWindows.contains(win)) {
if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
resizingWindows.add(win);
}
+ if (win.isGoneForLayoutLw()) {
+ win.mResizedWhileGone = true;
+ }
}
}
}
@@ -626,6 +654,19 @@ class Task implements DimLayer.DimLayerUser {
return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
}
+ boolean isVisibleForUser() {
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken appToken = mAppTokens.get(i);
+ for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
+ WindowState window = appToken.allAppWindows.get(j);
+ if (!window.isHiddenFromUserLocked()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
boolean inHomeStack() {
return mStack != null && mStack.mStackId == HOME_STACK_ID;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a8b728923265..07a6514de5f1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -38,6 +38,7 @@ import java.util.ArrayList;
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.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
@@ -74,9 +75,6 @@ public class TaskStack implements DimLayer.DimLayerUser,
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
- /** Screen content area excluding IM windows, etc. */
- private final Rect mContentBounds = new Rect();
-
/** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
private final Rect mAdjustedBounds = new Rect();
@@ -97,14 +95,27 @@ public class TaskStack implements DimLayer.DimLayerUser,
/** Detach this stack from its display when animation completes. */
boolean mDeferDetach;
- private boolean mUpdateBoundsAfterRotation = false;
+
+ // Display rotation as of the last time the display information was updated for this stack.
+ private int mLastUpdateDisplayInfoRotation = -1;
+ // Display rotation as of the last time the configuration was updated for this stack.
+ private int mLastConfigChangedRotation = -1;
// Whether the stack and all its tasks is currently being drag-resized
private boolean mDragResizing;
+ private final Rect mLastContentBounds = new Rect();
+ private final Rect mTmpAdjustedBounds = new Rect();
+ private boolean mAdjustedForIme;
+ private WindowState mImeWin;
+ private float mMinimizeAmount;
+ private final int mDockedStackMinimizeThickness;
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
+ mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_minimize_thickness);
EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
}
@@ -173,7 +184,27 @@ public class TaskStack implements DimLayer.DimLayerUser,
return mTmpRect.equals(bounds);
}
- void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+ /**
+ * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
+ * the normal task bounds.
+ *
+ * @param bounds The adjusted bounds.
+ * @param keepInsets Whether to keep the insets from the original bounds or to calculate new
+ * ones depending on the adjusted bounds.
+ */
+ private void setAdjustedBounds(Rect bounds, boolean keepInsets) {
+ if (mAdjustedBounds.equals(bounds)) {
+ return;
+ }
+
+ mAdjustedBounds.set(bounds);
+ final boolean adjusted = !mAdjustedBounds.isEmpty();
+ alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds,
+ adjusted && keepInsets ? mBounds : null);
+ mDisplayContent.layoutNeeded = true;
+ }
+
+ private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
if (mFullscreen) {
return;
}
@@ -186,72 +217,15 @@ public class TaskStack implements DimLayer.DimLayerUser,
task.resizeLocked(null, null, false /* forced */);
task.getBounds(mTmpRect2);
task.scrollLocked(mTmpRect2);
- } else if (task.isResizeable()) {
+ } else if (task.isResizeable() && task.mOverrideConfig != Configuration.EMPTY) {
task.getBounds(mTmpRect2);
mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+ task.setTempInsetBounds(tempInsetBounds);
task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
}
}
}
- void adjustForIME(final WindowState imeWin) {
- final int dockedSide = getDockSide();
- final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
- final Rect adjustedBounds = mAdjustedBounds;
- if (imeWin == null || !dockedTopOrBottom) {
- // If mContentBounds is already empty, it means we're not applying
- // any adjustments, so nothing to do; otherwise clear any adjustments.
- if (!mContentBounds.isEmpty()) {
- mContentBounds.setEmpty();
- adjustedBounds.set(mBounds);
- alignTasksToAdjustedBounds(adjustedBounds);
- }
- return;
- }
-
- final Rect displayContentRect = mTmpRect;
- final Rect contentBounds = mTmpRect2;
-
- // Calculate the content bounds excluding the area occupied by IME
- mDisplayContent.getContentRect(displayContentRect);
- contentBounds.set(displayContentRect);
- int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
- imeTop += imeWin.getGivenContentInsetsLw().top;
- if (contentBounds.bottom > imeTop) {
- contentBounds.bottom = imeTop;
- }
-
- // If content bounds not changing, nothing to do.
- if (mContentBounds.equals(contentBounds)) {
- return;
- }
-
- // Content bounds changed, need to apply adjustments depending on dock sides.
- mContentBounds.set(contentBounds);
- adjustedBounds.set(mBounds);
- final int yOffset = displayContentRect.bottom - contentBounds.bottom;
-
- if (dockedSide == DOCKED_TOP) {
- // If this stack is docked on top, we make it smaller so the bottom stack is not
- // occluded by IME. We shift its bottom up by the height of the IME (capped by
- // the display content rect). Note that we don't change the task bounds.
- adjustedBounds.bottom = Math.max(
- adjustedBounds.bottom - yOffset, displayContentRect.top);
- } else {
- // If this stack is docked on bottom, we shift it up so that it's not occluded by
- // IME. We try to move it up by the height of the IME window (although the best
- // we could do is to make the top stack fully collapsed).
- final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
- adjustedBounds.top = Math.max(
- adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
- adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
-
- // We also move the member tasks together, taking care not to resize them.
- // Resizing might cause relaunch, and IME window may not come back after that.
- alignTasksToAdjustedBounds(adjustedBounds);
- }
- }
-
private boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
@@ -280,14 +254,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
mBounds.set(bounds);
mRotation = rotation;
- // Clear the adjusted content bounds as they're no longer valid.
- // If IME is still visible, these will be re-applied.
- // Note that we don't clear mContentBounds here, so that we know the last IME
- // adjust we applied.
- // If user starts dragging the dock divider while IME is visible, the new bounds
- // we received are based on the actual screen location of the divider. It already
- // accounted for the IME window, so we don't want to adjust again.
- mAdjustedBounds.set(mBounds);
+ updateAdjustedBounds();
return true;
}
@@ -313,10 +280,11 @@ public class TaskStack implements DimLayer.DimLayerUser,
public void getBounds(Rect out) {
if (useCurrentBounds()) {
- // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
- // no need to adjust the output bounds if fullscreen or the docked stack is visible
- // since it is already what we want to represent to the rest of the system.
- if (!mContentBounds.isEmpty()) {
+ // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
+ // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
+ // stack is visible since it is already what we want to represent to the rest of the
+ // system.
+ if (!mAdjustedBounds.isEmpty()) {
out.set(mAdjustedBounds);
} else {
out.set(mBounds);
@@ -337,49 +305,99 @@ public class TaskStack implements DimLayer.DimLayerUser,
}
void updateDisplayInfo(Rect bounds) {
- mUpdateBoundsAfterRotation = false;
- if (mDisplayContent != null) {
- for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
- }
- if (bounds != null) {
- setBounds(bounds);
- } else if (mFullscreen) {
- setBounds(null);
- } else {
- mUpdateBoundsAfterRotation = true;
- mTmpRect2.set(mBounds);
- final int newRotation = mDisplayContent.getDisplayInfo().rotation;
- if (mRotation == newRotation) {
- setBounds(mTmpRect2);
- }
+ if (mDisplayContent == null) {
+ return;
+ }
- // If the rotation changes, we'll handle it in updateBoundsAfterRotation
- }
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+ }
+ if (bounds != null) {
+ setBounds(bounds);
+ return;
+ } else if (mFullscreen) {
+ setBounds(null);
+ return;
+ }
+
+ mTmpRect2.set(mBounds);
+ final int newRotation = mDisplayContent.getDisplayInfo().rotation;
+ if (mRotation == newRotation) {
+ setBounds(mTmpRect2);
+ } else {
+ mLastUpdateDisplayInfoRotation = newRotation;
+ updateBoundsAfterRotation();
}
}
- /**
- * Updates the bounds after rotating the screen. We can't handle it in
- * {@link #updateDisplayInfo} because at that point the configuration might not be fully updated
- * yet.
- */
+ void onConfigurationChanged() {
+ mLastConfigChangedRotation = getDisplayInfo().rotation;
+ updateBoundsAfterRotation();
+ }
+
void updateBoundsAfterRotation() {
- if (!mUpdateBoundsAfterRotation) {
+ if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
+ // We wait for the rotation values after configuration change and display info. update
+ // to be equal before updating the bounds due to rotation change otherwise things might
+ // get out of alignment...
return;
}
- mUpdateBoundsAfterRotation = false;
+
final int newRotation = getDisplayInfo().rotation;
+
+ if (mRotation == newRotation) {
+ // Nothing to do here if the rotation didn't change
+ return;
+ }
+
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (mStackId == DOCKED_STACK_ID) {
+ repositionDockedStackAfterRotation(mTmpRect2);
snapDockedStackAfterRotation(mTmpRect2);
}
// 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.sendMessage(mService.mH.obtainMessage(
- RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2));
+ mService.mH.obtainMessage(
+ RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+ }
+
+ /**
+ * Some dock sides are not allowed by the policy. This method queries the policy and moves
+ * the docked stack around if needed.
+ *
+ * @param inOutBounds the bounds of the docked stack to adjust
+ */
+ private void repositionDockedStackAfterRotation(Rect inOutBounds) {
+ int dockSide = getDockSide(inOutBounds);
+ if (mService.mPolicy.isDockSideAllowed(dockSide)) {
+ return;
+ }
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ dockSide = DockedDividerUtils.invertDockSide(dockSide);
+ switch (dockSide) {
+ case DOCKED_LEFT:
+ int movement = inOutBounds.left;
+ inOutBounds.left -= movement;
+ inOutBounds.right -= movement;
+ break;
+ case DOCKED_RIGHT:
+ movement = mTmpRect.right - inOutBounds.right;
+ inOutBounds.left += movement;
+ inOutBounds.right += movement;
+ break;
+ case DOCKED_TOP:
+ movement = inOutBounds.top;
+ inOutBounds.top -= movement;
+ inOutBounds.bottom -= movement;
+ break;
+ case DOCKED_BOTTOM:
+ movement = mTmpRect.bottom - inOutBounds.bottom;
+ inOutBounds.top += movement;
+ inOutBounds.bottom += movement;
+ break;
+ }
}
/**
@@ -419,7 +437,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
- if (winAnimator.isAnimating() || winAnimator.mWin.mExiting) {
+ if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) {
return true;
}
}
@@ -690,7 +708,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
outBounds.top = dockedBounds.bottom + dockDividerWidth;
}
}
- DockedDividerUtils.sanitizeStackBounds(outBounds);
+ DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
}
/** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
@@ -801,6 +819,158 @@ public class TaskStack implements DimLayer.DimLayerUser,
mDisplayContent = null;
}
+ /**
+ * Adjusts the stack bounds if the IME is visible.
+ *
+ * @param imeWin The IME window.
+ */
+ void setAdjustedForIme(WindowState imeWin) {
+ mAdjustedForIme = true;
+ mImeWin = imeWin;
+ updateAdjustedBounds();
+ }
+
+ /**
+ * Resets the adjustment after it got adjusted for the IME.
+ */
+ void resetAdjustedForIme() {
+ mAdjustedForIme = false;
+ mImeWin = null;
+ updateAdjustedBounds();
+ }
+
+ /**
+ * Sets the amount how much we currently minimize our stack.
+ *
+ * @param minimizeAmount The amount, between 0 and 1.
+ * @return Whether the amount has changed and a layout is needed.
+ */
+ boolean setAdjustedForMinimizedDock(float minimizeAmount) {
+ if (minimizeAmount != mMinimizeAmount) {
+ mMinimizeAmount = minimizeAmount;
+ updateAdjustedBounds();
+ return isVisibleForUserLocked();
+ } else {
+ return false;
+ }
+ }
+
+ private boolean adjustForIME(final WindowState imeWin) {
+ final int dockedSide = getDockSide();
+ final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+ final Rect adjustedBounds = mTmpAdjustedBounds;
+ if (imeWin == null || !dockedTopOrBottom) {
+ return false;
+ }
+
+ final Rect displayContentRect = mTmpRect;
+ final Rect contentBounds = mTmpRect2;
+
+ // Calculate the content bounds excluding the area occupied by IME
+ getDisplayContent().getContentRect(displayContentRect);
+ contentBounds.set(displayContentRect);
+ int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+ imeTop += imeWin.getGivenContentInsetsLw().top;
+ if (contentBounds.bottom > imeTop) {
+ contentBounds.bottom = imeTop;
+ }
+
+ // If content bounds not changing, nothing to do.
+ if (mLastContentBounds.equals(contentBounds)) {
+ return true;
+ }
+
+ // Content bounds changed, need to apply adjustments depending on dock sides.
+ mLastContentBounds.set(contentBounds);
+ adjustedBounds.set(mBounds);
+ final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+ if (dockedSide == DOCKED_TOP) {
+ // If this stack is docked on top, we make it smaller so the bottom stack is not
+ // occluded by IME. We shift its bottom up by the height of the IME (capped by
+ // the display content rect). Note that we don't change the task bounds.
+ adjustedBounds.bottom = Math.max(
+ adjustedBounds.bottom - yOffset, displayContentRect.top);
+ } else {
+ // If this stack is docked on bottom, we shift it up so that it's not occluded by
+ // IME. We try to move it up by the height of the IME window (although the best
+ // we could do is to make the top stack fully collapsed).
+ final int dividerWidth = getDisplayContent().mDividerControllerLocked
+ .getContentWidth();
+ adjustedBounds.top = Math.max(
+ adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+ adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+ }
+ return true;
+ }
+
+ private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
+ final int dockSide = getDockSide();
+ if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
+ return false;
+ }
+
+ if (dockSide == DOCKED_TOP) {
+ mService.getStableInsetsLocked(mTmpRect);
+ int topInset = mTmpRect.top;
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.bottom =
+ (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
+ } else if (dockSide == DOCKED_LEFT) {
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.right =
+ (int) (minimizeAmount * mDockedStackMinimizeThickness
+ + (1 - minimizeAmount) * mBounds.right);
+ } else if (dockSide == DOCKED_RIGHT) {
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.left =
+ (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
+ + (1 - minimizeAmount) * mBounds.left);
+ }
+ return true;
+ }
+
+ /**
+ * @return the distance in pixels how much the stack gets minimized from it's original size
+ */
+ int getMinimizeDistance() {
+ final int dockSide = getDockSide();
+ if (dockSide == DOCKED_INVALID) {
+ return 0;
+ }
+
+ if (dockSide == DOCKED_TOP) {
+ mService.getStableInsetsLocked(mTmpRect);
+ int topInset = mTmpRect.top;
+ return mBounds.bottom - topInset;
+ } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
+ return mBounds.width() - mDockedStackMinimizeThickness;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Updates the adjustment depending on it's current state.
+ */
+ void updateAdjustedBounds() {
+ boolean adjust = false;
+ if (mMinimizeAmount != 0f) {
+ adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
+ } else if (mAdjustedForIme) {
+ adjust = adjustForIME(mImeWin);
+ }
+ if (!adjust) {
+ mTmpAdjustedBounds.setEmpty();
+ mLastContentBounds.setEmpty();
+ }
+ setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
+ }
+
+ boolean isAdjustedForMinimizedDockedStack() {
+ return mMinimizeAmount != 0f;
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "mStackId=" + mStackId);
pw.println(prefix + "mDeferDetach=" + mDeferDetach);
@@ -897,20 +1067,36 @@ public class TaskStack implements DimLayer.DimLayerUser,
}
boolean isVisibleLocked() {
- final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded();
+ final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
+ && !mService.mAnimator.mKeyguardGoingAway;
if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
// The keyguard is showing and the stack shouldn't show on top of the keyguard.
return false;
}
for (int i = mTasks.size() - 1; i >= 0; i--) {
- Task task = mTasks.get(i);
+ final Task task = mTasks.get(i);
for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
if (!task.mAppTokens.get(j).hidden) {
return true;
}
}
}
+
+ return false;
+ }
+
+ /**
+ * @return true if a the stack is visible for the current in user, ignoring any other visibility
+ * aspects, and false otherwise
+ */
+ boolean isVisibleForUserLocked() {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ final Task task = mTasks.get(i);
+ if (task.isVisibleForUser()) {
+ return true;
+ }
+ }
return false;
}
@@ -918,6 +1104,16 @@ public class TaskStack implements DimLayer.DimLayerUser,
return mDragResizing;
}
+ private void setDragResizingLocked(boolean resizing) {
+ if (mDragResizing == resizing) {
+ return;
+ }
+ mDragResizing = resizing;
+ for (int i = mTasks.size() - 1; i >= 0 ; i--) {
+ mTasks.get(i).resetDragResizingChangeReported();
+ }
+ }
+
@Override // AnimatesBounds
public boolean setSize(Rect bounds) {
synchronized (mService.mWindowMap) {
@@ -935,16 +1131,23 @@ public class TaskStack implements DimLayer.DimLayerUser,
@Override // AnimatesBounds
public void onAnimationStart() {
synchronized (mService.mWindowMap) {
- mDragResizing = true;
+ setDragResizingLocked(true);
}
}
@Override // AnimatesBounds
public void onAnimationEnd() {
synchronized (mService.mWindowMap) {
- mDragResizing = false;
+ setDragResizingLocked(false);
mService.requestTraversal();
}
+ if (mStackId == PINNED_STACK_ID) {
+ try {
+ mService.mActivityManager.notifyPinnedStackAnimationEnded();
+ } catch (RemoteException e) {
+ // I don't believe you...
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 8d2fb9b785de..85bddee5e1dc 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
@@ -231,7 +232,10 @@ public class WindowAnimator {
// Only hide windows if the keyguard is active and not animating away.
boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded()
&& mForceHiding != KEYGUARD_ANIMATING_OUT;
- return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY);
+ boolean hideDockDivider = win.mAttrs.type == TYPE_DOCK_DIVIDER
+ && win.getDisplayContent().getDockedStackLocked() == null;
+ return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY)
+ || hideDockDivider;
}
private void updateWindowsLocked(final int displayId) {
@@ -526,7 +530,7 @@ public class WindowAnimator {
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState win = windows.get(i);
WindowStateAnimator winAnimator = win.mWinAnimator;
- if (winAnimator.mSurfaceController == null) {
+ if (winAnimator.mSurfaceController == null || !winAnimator.hasSurface()) {
continue;
}
@@ -701,7 +705,8 @@ public class WindowAnimator {
}
orAnimating(mService.getDisplayContentLocked(displayId).animateDimLayers());
-
+ orAnimating(mService.getDisplayContentLocked(displayId).getDockedDividerController()
+ .animate(mCurrentTime));
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null
&& displayId == Display.DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d1ffaa07ed13..69d2d20a9018 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -20,6 +20,7 @@ import android.Manifest;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IActivityManager;
@@ -41,6 +42,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -81,6 +83,7 @@ import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.PointerIcon;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.IDockedStackListener;
@@ -114,9 +117,10 @@ import android.view.WindowManagerPolicy.PointerEventListener;
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManagerInternal;
import android.widget.Toast;
-import com.android.internal.R;
+
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IShortcutService;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -190,6 +194,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
+import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -316,6 +322,8 @@ public class WindowManagerService extends IWindowManager.Stub
private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f;
+ private static final String PROPERTY_BUILD_DATE_UTC = "ro.build.date.utc";
+
final private KeyguardDisableHandler mKeyguardDisableHandler;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -356,6 +364,7 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowManagerPolicy mPolicy = new PhoneWindowManager();
final IActivityManager mActivityManager;
+ final ActivityManagerInternal mAmInternal;
final AppOpsManager mAppOps;
@@ -466,6 +475,7 @@ public class WindowManagerService extends IWindowManager.Stub
final float[] mTmpFloats = new float[9];
final Rect mTmpRect = new Rect();
final Rect mTmpRect2 = new Rect();
+ final Region mTmpRegion = new Region();
boolean mDisplayReady;
boolean mSafeMode;
@@ -661,13 +671,6 @@ public class WindowManagerService extends IWindowManager.Stub
private WindowContentFrameStats mTempWindowRenderStats;
- private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
- View.DRAG_FLAG_GLOBAL_URI_WRITE;
-
- private static final int DRAG_FLAGS_URI_PERMISSIONS = DRAG_FLAGS_URI_ACCESS |
- View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
- View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
-
final class DragInputEventReceiver extends InputEventReceiver {
// Set, if stylus button was down at the start of the drag.
private boolean mStylusButtonDownAtStart;
@@ -713,7 +716,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_DRAG) Slog.d(TAG_WM, "Button no longer pressed; dropping at "
+ newX + "," + newY);
synchronized (mWindowMap) {
- endDrag = completeDropLw(newX, newY);
+ endDrag = mDragState.notifyDropLw(newX, newY);
}
} else {
synchronized (mWindowMap) {
@@ -727,7 +730,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_DRAG) Slog.d(TAG_WM, "Got UP on move channel; dropping at "
+ newX + "," + newY);
synchronized (mWindowMap) {
- endDrag = completeDropLw(newX, newY);
+ endDrag = mDragState.notifyDropLw(newX, newY);
}
} break;
@@ -757,25 +760,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- private boolean completeDropLw(float x, float y) {
- WindowState dropTargetWin = mDragState.getDropTargetWinLw(x, y);
-
- DropPermissionsHandler dropPermissions = null;
- if (dropTargetWin != null &&
- (mDragState.mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
- (mDragState.mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
- dropPermissions = new DropPermissionsHandler(
- mDragState.mData,
- mDragState.mUid,
- dropTargetWin.getOwningPackage(),
- mDragState.mFlags & DRAG_FLAGS_URI_PERMISSIONS,
- UserHandle.getUserId(mDragState.mUid),
- UserHandle.getUserId(dropTargetWin.getOwningUid()));
- }
-
- return mDragState.notifyDropLw(dropTargetWin, dropPermissions, x, y);
- }
-
/**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
@@ -921,6 +905,7 @@ public class WindowManagerService extends IWindowManager.Stub
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
mActivityManager = ActivityManagerNative.getDefault();
+ mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
AppOpsManager.OnOpChangedInternalListener opListener =
new AppOpsManager.OnOpChangedInternalListener() {
@@ -1192,7 +1177,7 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
}
- if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"Based on layer: Adding window " + win + " at " + (i + 1) + " of "
+ windows.size());
windows.add(i + 1, win);
@@ -1224,7 +1209,7 @@ public class WindowManagerService extends IWindowManager.Stub
//apptoken note that the window could be a floating window
//that was created later or a window at the top of the list of
//windows associated with this token.
- if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
+ windows.size());
windows.add(newIdx + 1, win);
@@ -1262,7 +1247,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
i++;
- if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"Free window: Adding window " + win + " at " + i + " of " + windows.size());
windows.add(i, win);
mWindowsChanged = true;
@@ -1333,7 +1318,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
- if (DEBUG_FOCUS_LIGHT) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
+ if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindowToListInOrderLocked: win=" + win +
" Callers=" + Debug.getCallers(4));
if (win.mAttachedWindow == null) {
final WindowToken token = win.mToken;
@@ -1377,7 +1362,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ " policyVis=" + w.mPolicyVisibility
+ " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
+ " attachHid=" + w.mAttachedHidden
- + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
+ + " exiting=" + w.mAnimatingExit + " destroying=" + w.mDestroying);
if (w.mAppToken != null) {
Slog.i(TAG_WM, " mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
}
@@ -2017,8 +2002,10 @@ public class WindowManagerService extends IWindowManager.Stub
prepareWindowReplacementTransition(atoken);
if (displayContent.isDefaultDisplay) {
- mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,
- outOutsets);
+ if (mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,
+ outOutsets)) {
+ res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
+ }
} else {
outContentInsets.setEmpty();
outStableInsets.setEmpty();
@@ -2080,7 +2067,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState replacedWindow = null;
for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) {
WindowState candidate = atoken.windows.get(i);
- if (candidate.mExiting && candidate.mWillReplaceWindow
+ if (candidate.mAnimatingExit && candidate.mWillReplaceWindow
&& candidate.mAnimateReplacingWindow) {
replacedWindow = candidate;
}
@@ -2154,19 +2141,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (win == null) {
return;
}
- // We set this here instead of removeWindowLocked because we only want it to be
- // true when the client has requested we remove the window. In other remove
- // cases, we have to wait for activity stop to safely remove the window (as the
- // client may still be using the surface). In this case though, the client has
- // just dismissed a window (for example a Dialog) and activity stop isn't
- // necessarily imminent, so we need to know not to wait for it after our
- // hanimation (if applicable) finishes.
- win.mClientRemoveRequested = true;
removeWindowLocked(win);
}
}
void removeWindowLocked(WindowState win) {
+ win.mWindowRemovalAllowed = true;
final boolean startingWindow = win.mAttrs.type == TYPE_APPLICATION_STARTING;
if (startingWindow) {
if (DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + win);
@@ -2182,23 +2162,25 @@ public class WindowManagerService extends IWindowManager.Stub
win.disposeInputChannel();
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG_WM, "Remove " + win + ": mSurfaceController=" + win.mWinAnimator.mSurfaceController
- + " mExiting=" + win.mExiting
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+ "Remove " + win + ": mSurfaceController=" + win.mWinAnimator.mSurfaceController
+ + " mAnimatingExit=" + win.mAnimatingExit
+ + " mRemoveOnExit=" + win.mRemoveOnExit
+ + " mHasSurface=" + win.mHasSurface
+ + " surfaceShowing=" + win.mWinAnimator.getShown()
+ " isAnimating=" + win.mWinAnimator.isAnimating()
+ " app-animation="
+ (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
- + " mWillReplaceWindow="
- + win.mWillReplaceWindow
+ + " mWillReplaceWindow=" + win.mWillReplaceWindow
+ " inPendingTransaction="
+ (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
- + " mDisplayFrozen=" + mDisplayFrozen);
+ + " mDisplayFrozen=" + mDisplayFrozen
+ + " callers=" + Debug.getCallers(6));
// Visibility of the removed window. Will be used later to update orientation later on.
boolean wasVisible = false;
- // First, see if we need to run an animation. If we do, we have
- // to hold off on removing the window until the animation is done.
- // If the display is frozen, just remove immediately, since the
- // animation wouldn't be seen.
+ // First, see if we need to run an animation. If we do, we have to hold off on removing the
+ // window until the animation is done. If the display is frozen, just remove immediately,
+ // since the animation wouldn't be seen.
if (win.mHasSurface && okToDisplay()) {
final AppWindowToken appToken = win.mAppToken;
if (win.mWillReplaceWindow) {
@@ -2206,13 +2188,16 @@ public class WindowManagerService extends IWindowManager.Stub
// gets added, then we will get rid of this one.
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Preserving " + win + " until the new one is "
+ "added");
- win.mExiting = true;
+ // TODO: We are overloading mAnimatingExit flag to prevent the window state from
+ // been removed. We probably need another falg to indicate that window removal
+ // should be deffered vs. overloading the flag that says we are playing an exit
+ // animation.
+ win.mAnimatingExit = true;
win.mReplacingRemoveRequested = true;
Binder.restoreCallingIdentity(origId);
return;
}
- // If we are not currently running the exit animation, we
- // need to see about starting one.
+ // If we are not currently running the exit animation, we need to see about starting one
wasVisible = win.isWinVisibleLw();
if (win.shouldKeepVisibleDeadAppWindow()) {
@@ -2232,14 +2217,13 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
if (wasVisible) {
- final int transit = (!startingWindow)
- ? WindowManagerPolicy.TRANSIT_EXIT
- : WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+ final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
// Try starting an animation.
- if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
- win.mExiting = true;
+ if (winAnimator.applyAnimationLocked(transit, false)) {
+ win.mAnimatingExit = true;
}
//TODO (multidisplay): Magnification is supported only for the default display.
if (mAccessibilityController != null
@@ -2247,15 +2231,20 @@ public class WindowManagerService extends IWindowManager.Stub
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
}
- final boolean isAnimating = win.mWinAnimator.isAnimating()
- && !win.mWinAnimator.isDummyAnimation();
- // The starting window is the last window in this app token and it isn't animating.
- // Allow it to be removed now as there is no additional window or animation that will
- // trigger its removal.
- final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
- && appToken.allAppWindows.size() == 1 && !isAnimating;
- if (!lastWinStartingNotAnimating && win.mExiting) {
- // The exit animation is running... wait for it!
+ final boolean isAnimating =
+ winAnimator.isAnimating() && !winAnimator.isDummyAnimation();
+ final boolean lastWindowIsStartingWindow = startingWindow && appToken != null
+ && appToken.allAppWindows.size() == 1;
+ // We delay the removal of a window if it has a showing surface that can be used to run
+ // exit animation and it is marked as exiting.
+ // Also, If isn't the an animating starting window that is the last window in the app.
+ // We allow the removal of the non-animating starting window now as there is no
+ // additional window or animation that will trigger its removal.
+ if (winAnimator.getShown() && win.mAnimatingExit
+ && (!lastWindowIsStartingWindow || isAnimating)) {
+ // The exit animation is running or should run... wait for it!
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "Not removing " + win + " due to exit animation ");
win.mRemoveOnExit = true;
win.setDisplayLayoutNeeded();
final boolean focusChanged = updateFocusedWindowLocked(
@@ -2285,13 +2274,14 @@ public class WindowManagerService extends IWindowManager.Stub
void removeWindowInnerLocked(WindowState win) {
if (win.mRemoved) {
// Nothing to do.
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "removeWindowInnerLocked: " + win + " Already removed...");
return;
}
- for (int i=win.mChildWindows.size()-1; i>=0; i--) {
+ for (int i = win.mChildWindows.size() - 1; i >= 0; i--) {
WindowState cwin = win.mChildWindows.get(i);
- Slog.w(TAG_WM, "Force-removing child win " + cwin + " from container "
- + win);
+ Slog.w(TAG_WM, "Force-removing child win " + cwin + " from container " + win);
removeWindowInnerLocked(cwin);
}
@@ -2704,16 +2694,16 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean usingSavedSurfaceBeforeVisible =
oldVisibility != View.VISIBLE && win.isAnimatingWithSavedSurface();
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- if (winAnimator.hasSurface() && !win.mExiting
+ if (winAnimator.hasSurface() && !win.mAnimatingExit
&& usingSavedSurfaceBeforeVisible) {
Slog.d(TAG, "Ignoring layout to invisible when using saved surface " + win);
}
}
- if (winAnimator.hasSurface() && !win.mExiting
+ if (winAnimator.hasSurface() && !win.mAnimatingExit
&& !usingSavedSurfaceBeforeVisible) {
if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
- + ": mExiting=" + win.mExiting);
+ + ": mAnimatingExit=" + win.mAnimatingExit);
// If we are not currently running the exit animation, we
// need to see about starting one.
// We don't want to animate visibility of windows which are pending
@@ -2776,6 +2766,12 @@ public class WindowManagerService extends IWindowManager.Stub
winAnimator.mReportSurfaceResized = false;
result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
}
+ if (mPolicy.isNavBarForcedShownLw(win)) {
+ result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR;
+ }
+ if (!win.isGoneForLayoutLw()) {
+ win.mResizedWhileGone = false;
+ }
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
outContentInsets.set(win.mContentInsets);
@@ -2820,16 +2816,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = isDefaultDisplay;
- win.mExiting = true;
+ win.mAnimatingExit = true;
} else if (win.mWinAnimator.isAnimating()) {
// Currently in a hide animation... turn this into
// an exit.
- win.mExiting = true;
+ win.mAnimatingExit = true;
} else if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
- win.mExiting = true;
+ win.mAnimatingExit = true;
win.mWinAnimator.mAnimating = true;
} else {
if (mInputMethodWindow == win) {
@@ -2865,12 +2861,12 @@ public class WindowManagerService extends IWindowManager.Stub
private int relayoutVisibleWindow(Configuration outConfig, int result, WindowState win,
WindowStateAnimator winAnimator, int attrChanges, int oldVisibility) {
result |= !win.isVisibleLw() ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0;
- if (win.mExiting) {
- Slog.d(TAG, "relayoutVisibleWindow: " + win + " mExiting=true, mRemoveOnExit="
+ if (win.mAnimatingExit) {
+ Slog.d(TAG, "relayoutVisibleWindow: " + win + " mAnimatingExit=true, mRemoveOnExit="
+ win.mRemoveOnExit + ", mDestroying=" + win.mDestroying);
winAnimator.cancelExitAnimationForNextAnimationLocked();
- win.mExiting = false;
+ win.mAnimatingExit = false;
}
if (win.mDestroying) {
win.mDestroying = false;
@@ -2991,6 +2987,8 @@ public class WindowManagerService extends IWindowManager.Stub
// Determine the visible rect to calculate the thumbnail clip
final WindowState win = atoken.findMainWindow();
final Rect frame = new Rect(0, 0, width, height);
+ final Rect displayFrame = new Rect(0, 0,
+ displayInfo.logicalWidth, displayInfo.logicalHeight);
final Rect insets = new Rect();
Rect surfaceInsets = null;
final boolean freeform = win != null && win.inFreeformWorkspace();
@@ -3018,8 +3016,8 @@ public class WindowManagerService extends IWindowManager.Stub
+ " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+ " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
Animation a = mAppTransition.loadAnimation(lp, transit, enter,
- mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction,
- freeform, atoken.mTask.mTaskId);
+ mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets,
+ isVoiceInteraction, freeform, atoken.mTask.mTaskId);
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
final int containingWidth = frame.width();
@@ -3565,23 +3563,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized(mWindowMap) {
- final boolean orientationChanged = mCurConfiguration.orientation != config.orientation;
mCurConfiguration = new Configuration(config);
if (mWaitingForConfig) {
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
- if (orientationChanged) {
- updateTaskStackBoundsAfterRotation();
- }
+ onConfigurationChanged();
mWindowPlacerLocked.performSurfacePlacement();
}
}
- private void updateTaskStackBoundsAfterRotation() {
+ private void onConfigurationChanged() {
for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
- stack.updateBoundsAfterRotation();
+ stack.onConfigurationChanged();
}
}
@@ -3755,7 +3750,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
for (final WindowState win : mWindowMap.values()) {
final Task task = win.getTask();
- if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1) {
+ if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1
+ && task.inFreeformWorkspace()) {
final AppWindowToken appToken = win.mAppToken;
if (appToken != null && appToken.mAppAnimator != null) {
appToken.mAppAnimator.startProlongAnimation(scaleUp ?
@@ -4023,10 +4019,8 @@ public class WindowManagerService extends IWindowManager.Stub
public void removeAppStartingWindow(IBinder token) {
synchronized (mWindowMap) {
- AppWindowToken wtoken = mTokenMap.get(token).appWindowToken;
- if (wtoken.startingWindow != null) {
- scheduleRemoveStartingWindowLocked(wtoken);
- }
+ final AppWindowToken wtoken = mTokenMap.get(token).appWindowToken;
+ scheduleRemoveStartingWindowLocked(wtoken);
}
}
@@ -4176,11 +4170,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (visibilityChanged && visible && !delayed) {
- // The token was made immediately visible, there will be no entrance animation. We need
- // to inform the client the enter animation was finished.
- wtoken.mEnteringAnimation = true;
- mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(wtoken.token);
+ if (visibilityChanged && !delayed) {
+ if (visible) {
+ // The token was made immediately visible, there will be no entrance animation.
+ // We need to inform the client the enter animation was finished.
+ wtoken.mEnteringAnimation = true;
+ mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(wtoken.token);
+ }
+ getDefaultDisplayContentLocked().getDockedDividerController()
+ .notifyAppVisibilityChanged(wtoken, visible);
}
return delayed;
@@ -4236,7 +4234,6 @@ public class WindowManagerService extends IWindowManager.Stub
mOpeningApps.remove(wtoken);
mClosingApps.remove(wtoken);
- wtoken.mAppStopped = false;
wtoken.waitingToShow = false;
wtoken.hiddenRequested = !visible;
@@ -4246,6 +4243,9 @@ public class WindowManagerService extends IWindowManager.Stub
// if made visible again.
wtoken.appDied = false;
wtoken.removeAllWindows();
+ } else if (visible) {
+ wtoken.mAppStopped = false;
+ wtoken.setWindowsExiting(false);
}
// If we are preparing an app transition, then delay changing
@@ -4263,7 +4263,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
wtoken.inPendingTransaction = true;
if (visible) {
- wtoken.setWindowsExiting(false);
mOpeningApps.add(wtoken);
wtoken.startingMoved = false;
wtoken.mEnteringAnimation = true;
@@ -4500,17 +4499,30 @@ public class WindowManagerService extends IWindowManager.Stub
}
void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
+ if (wtoken == null) {
+ return;
+ }
if (mH.hasMessages(H.REMOVE_STARTING, wtoken)) {
// Already scheduled.
return;
}
- if (wtoken != null && wtoken.startingWindow != null) {
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) +
- ": Schedule remove starting " + wtoken + (wtoken != null ?
- " startingWindow=" + wtoken.startingWindow : ""));
- Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
- mH.sendMessage(m);
+
+ if (wtoken.startingWindow == null) {
+ if (wtoken.startingData != null) {
+ // Starting window has not been added yet, but it is scheduled to be added.
+ // Go ahead and cancel the request.
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+ "Clearing startingData for token=" + wtoken);
+ wtoken.startingData = null;
+ }
+ return;
}
+
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1) +
+ ": Schedule remove starting " + wtoken + (wtoken != null ?
+ " startingWindow=" + wtoken.startingWindow : ""));
+ Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
+ mH.sendMessage(m);
}
void dumpAppTokensLocked() {
@@ -4863,6 +4875,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @Override
public void getStackBounds(int stackId, Rect bounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
@@ -7471,8 +7484,22 @@ public class WindowManagerService extends IWindowManager.Stub
|| volumeDownState > 0;
try {
if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
- mSafeMode = true;
- SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
+ int auditSafeMode = SystemProperties.getInt(ShutdownThread.AUDIT_SAFEMODE_PROPERTY, 0);
+
+ if (auditSafeMode == 0) {
+ mSafeMode = true;
+ SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
+ } else {
+ // stay in safe mode until we have updated to a newer build
+ int buildDate = SystemProperties.getInt(PROPERTY_BUILD_DATE_UTC, 0);
+
+ if (auditSafeMode >= buildDate) {
+ mSafeMode = true;
+ } else {
+ SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
+ SystemProperties.set(ShutdownThread.AUDIT_SAFEMODE_PROPERTY, "");
+ }
+ }
}
} catch (IllegalArgumentException e) {
}
@@ -7594,6 +7621,9 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
+ public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
+ public static final int NOTIFY_STARTING_WINDOW_DRAWN = 48;
+
/**
* Used to denote that an integer field in a message will not be used.
*/
@@ -8145,14 +8175,14 @@ public class WindowManagerService extends IWindowManager.Stub
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
if (stack.isVisibleLocked()) {
- stack.adjustForIME(imeWin);
+ stack.setAdjustedForIme(imeWin);
}
}
} else {
final ArrayList<TaskStack> stacks = displayContent.getStacks();
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
- stack.adjustForIME(null);
+ stack.resetAdjustedForIme();
}
}
}
@@ -8177,7 +8207,7 @@ public class WindowManagerService extends IWindowManager.Stub
break;
case SHOW_NON_RESIZEABLE_DOCK_TOAST: {
final Toast toast = Toast.makeText(
- mContext, (String) msg.obj, Toast.LENGTH_LONG);
+ mContext, (String) msg.obj, Toast.LENGTH_SHORT);
final int gravity = toast.getGravity();
final int xOffset = toast.getXOffset() + msg.arg1;
final int yOffset = toast.getYOffset() + msg.arg2;
@@ -8191,6 +8221,13 @@ public class WindowManagerService extends IWindowManager.Stub
token.clearTimedoutReplacesLocked();
}
}
+ case NOTIFY_APP_TRANSITION_STARTING: {
+ mAmInternal.notifyAppTransitionStarting(msg.arg1);
+ }
+ break;
+ case NOTIFY_STARTING_WINDOW_DRAWN: {
+ mAmInternal.notifyStartingWindowDrawn();
+ }
break;
}
if (DEBUG_WINDOW_TRACE) {
@@ -8834,7 +8871,8 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG_WM, "Win " + w + " config changed: "
+ mCurConfiguration);
}
- final boolean dragResizingChanged = w.isDragResizeChanged();
+ final boolean dragResizingChanged = w.isDragResizeChanged()
+ && !w.isDragResizingChangeReported();
if (localLOGV) Slog.v(TAG_WM, "Resizing " + w
+ ": configChanged=" + configChanged
+ " dragResizingChanged=" + dragResizingChanged
@@ -9004,11 +9042,10 @@ public class WindowManagerService extends IWindowManager.Stub
EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
winAnimator.mSession.mPid, operation);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
- // There was some problem... first, do a sanity check of the
- // window list to make sure we haven't left any dangling surfaces
- // around.
+ // There was some problem... first, do a sanity check of the window list to make sure
+ // we haven't left any dangling surfaces around.
Slog.i(TAG_WM, "Out of memory for surface! Looking for leaks...");
final int numDisplays = mDisplayContents.size();
@@ -9017,28 +9054,27 @@ public class WindowManagerService extends IWindowManager.Stub
final int numWindows = windows.size();
for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
final WindowState ws = windows.get(winNdx);
- WindowStateAnimator wsa = ws.mWinAnimator;
- if (wsa.mSurfaceController != null) {
- if (!mSessions.contains(wsa.mSession)) {
- Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
- + ws + " surface=" + wsa.mSurfaceController
- + " token=" + ws.mToken
- + " pid=" + ws.mSession.mPid
- + " uid=" + ws.mSession.mUid);
- wsa.destroySurface();
- ws.setHasSurface(false);
- mForceRemoves.add(ws);
- leakedSurface = true;
- } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
- Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
- + ws + " surface=" + wsa.mSurfaceController
- + " token=" + ws.mAppToken
- + " saved=" + ws.mAppToken.hasSavedSurface());
- if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
- wsa.destroySurface();
- ws.setHasSurface(false);
- leakedSurface = true;
- }
+ final WindowStateAnimator wsa = ws.mWinAnimator;
+ if (wsa.mSurfaceController == null) {
+ continue;
+ }
+ if (!mSessions.contains(wsa.mSession)) {
+ Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
+ + ws + " surface=" + wsa.mSurfaceController
+ + " token=" + ws.mToken
+ + " pid=" + ws.mSession.mPid
+ + " uid=" + ws.mSession.mUid);
+ wsa.destroySurface();
+ mForceRemoves.add(ws);
+ leakedSurface = true;
+ } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
+ Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
+ + ws + " surface=" + wsa.mSurfaceController
+ + " token=" + ws.mAppToken
+ + " saved=" + ws.mAppToken.hasSavedSurface());
+ if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
+ wsa.destroySurface();
+ leakedSurface = true;
}
}
}
@@ -9081,8 +9117,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (surfaceController != null) {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
"RECOVER DESTROY", false);
- surfaceController.destroyInTransaction();
- winAnimator.mWin.setHasSurface(false);
+ winAnimator.destroySurface();
scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
}
@@ -10168,6 +10203,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayId == Display.DEFAULT_DISPLAY) {
displayContent.mTapDetector = new TaskTapPointerEventListener(this, displayContent);
registerPointerEventListener(displayContent.mTapDetector);
+ registerPointerEventListener(mMousePositionTracker);
}
return displayContent;
@@ -10260,6 +10296,7 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent.close();
if (displayId == Display.DEFAULT_DISPLAY) {
unregisterPointerEventListener(displayContent.mTapDetector);
+ unregisterPointerEventListener(mMousePositionTracker);
}
}
mAnimator.removeDisplayLocked(displayId);
@@ -10354,7 +10391,8 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public int getDockedStackSide() {
synchronized (mWindowMap) {
- TaskStack dockedStack = getDefaultDisplayContentLocked().getDockedStackLocked();
+ final TaskStack dockedStack = getDefaultDisplayContentLocked()
+ .getDockedStackVisibleForUserLocked();
return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
}
}
@@ -10438,11 +10476,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- private void getStableInsetsLocked(Rect outInsets) {
+ void getStableInsetsLocked(Rect outInsets) {
final DisplayInfo di = getDefaultDisplayInfoLocked();
mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
}
+ private void getNonDecorInsetsLocked(Rect outInsets) {
+ final DisplayInfo di = getDefaultDisplayInfoLocked();
+ mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
+ }
+
/**
* Intersects the specified {@code inOutBounds} with the display frame that excludes the stable
* inset areas.
@@ -10459,6 +10502,119 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ /**
+ * Intersects the specified {@code inOutBounds} with the display frame that excludes
+ * areas that could never be removed in Honeycomb. See
+ * {@link WindowManagerPolicy#getNonDecorInsetsLw}.
+ *
+ * @param inOutBounds The inOutBounds to subtract the inset areas from.
+ */
+ public void subtractNonDecorInsets(Rect inOutBounds) {
+ synchronized (mWindowMap) {
+ getNonDecorInsetsLocked(mTmpRect2);
+ final DisplayInfo di = getDefaultDisplayInfoLocked();
+ mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
+ mTmpRect.inset(mTmpRect2);
+ inOutBounds.intersect(mTmpRect);
+ }
+ }
+
+ private MousePositionTracker mMousePositionTracker = new MousePositionTracker();
+
+ private static class MousePositionTracker implements PointerEventListener {
+ private boolean mLatestEventWasMouse;
+ private float mLatestMouseX;
+ private float mLatestMouseY;
+
+ void updatePosition(float x, float y) {
+ synchronized (this) {
+ mLatestEventWasMouse = true;
+ mLatestMouseX = x;
+ mLatestMouseY = y;
+ }
+ }
+
+ @Override
+ public void onPointerEvent(MotionEvent motionEvent) {
+ if (motionEvent.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ updatePosition(motionEvent.getRawX(), motionEvent.getRawY());
+ } else {
+ synchronized (this) {
+ mLatestEventWasMouse = false;
+ }
+ }
+ }
+ };
+
+ void updatePointerIcon(IWindow client) {
+ float mouseX, mouseY;
+
+ synchronized(mMousePositionTracker) {
+ if (!mMousePositionTracker.mLatestEventWasMouse) {
+ return;
+ }
+ mouseX = mMousePositionTracker.mLatestMouseX;
+ mouseY = mMousePositionTracker.mLatestMouseY;
+ }
+
+ synchronized (mWindowMap) {
+ if (mDragState != null) {
+ // Drag cursor overrides the app cursor.
+ return;
+ }
+ WindowState callingWin = windowForClientLocked(null, client, false);
+ if (callingWin == null) {
+ Slog.w(TAG_WM, "Bad requesting window " + client);
+ return;
+ }
+ final DisplayContent displayContent = callingWin.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+ WindowState windowUnderPointer =
+ displayContent.getTouchableWinAtPointLocked(mouseX, mouseY);
+ if (windowUnderPointer != callingWin) {
+ return;
+ }
+ try {
+ windowUnderPointer.mClient.updatePointerIcon(
+ windowUnderPointer.translateToWindowX(mouseX),
+ windowUnderPointer.translateToWindowY(mouseY));
+ } catch (RemoteException e) {
+ Slog.w(TAG_WM, "unable to update pointer icon");
+ }
+ }
+ }
+
+ void restorePointerIconLocked(DisplayContent displayContent, float latestX, float latestY) {
+ // Mouse position tracker has not been getting updates while dragging, update it now.
+ mMousePositionTracker.updatePosition(latestX, latestY);
+
+ WindowState windowUnderPointer =
+ displayContent.getTouchableWinAtPointLocked(latestX, latestY);
+ if (windowUnderPointer != null) {
+ try {
+ windowUnderPointer.mClient.updatePointerIcon(
+ windowUnderPointer.translateToWindowX(latestX),
+ windowUnderPointer.translateToWindowY(latestY));
+ } catch (RemoteException e) {
+ Slog.w(TAG_WM, "unable to restore pointer icon");
+ }
+ } else {
+ InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_DEFAULT);
+ }
+ }
+
+ public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
+ throws RemoteException {
+ if (!checkCallingPermission(Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
+ "registerShortcutKey")) {
+ throw new SecurityException(
+ "Requires REGISTER_WINDOW_MANAGER_LISTENERS permission");
+ }
+ mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
+ }
+
private final class LocalService extends WindowManagerInternal {
@Override
public void requestTraversalFromDisplayManager() {
@@ -10567,6 +10723,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
+ boolean allWindowsDrawn = false;
synchronized (mWindowMap) {
mWaitingForDrawnCallback = callback;
final WindowList windows = getDefaultWindowListLocked();
@@ -10587,13 +10744,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
mWindowPlacerLocked.requestTraversal();
+ mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
+ if (mWaitingForDrawn.isEmpty()) {
+ allWindowsDrawn = true;
+ } else {
+ mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
+ checkDrawnWindowsLocked();
+ }
}
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- if (mWaitingForDrawn.isEmpty()) {
+ if (allWindowsDrawn) {
callback.run();
- } else {
- mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
- checkDrawnWindowsLocked();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3430b3484ef7..40b6b50da6dd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -161,6 +161,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean mAttachedHidden; // is our parent window hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
boolean mDragResizing;
+ boolean mDragResizingChangeReported;
int mResizeMode;
RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -357,7 +358,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean mLayoutNeeded;
/** Currently running an exit animation? */
- boolean mExiting;
+ boolean mAnimatingExit;
/** Currently on the mDestroySurface list? */
boolean mDestroying;
@@ -386,11 +387,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean mRemoved;
/**
- * Has the client requested we remove the window? In this case we know
- * that we can dispose of it when we wish without further synchronization
- * with the client
+ * It is save to remove the window and destroy the surface because the client requested removal
+ * or some other higher level component said so (e.g. activity manager).
+ * TODO: We should either have different booleans for the removal reason or use a bit-field.
*/
- boolean mClientRemoveRequested;
+ boolean mWindowRemovalAllowed;
/**
* Temp for keeping track of windows that have been removed when
@@ -447,6 +448,16 @@ final class WindowState implements WindowManagerPolicy.WindowState {
final private Rect mTmpRect = new Rect();
+ /**
+ * See {@link #notifyMovedInStack}.
+ */
+ private boolean mJustMovedInStack;
+
+ /**
+ * Whether the window was resized by us while it was gone for layout.
+ */
+ boolean mResizedWhileGone = false;
+
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
@@ -613,7 +624,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
@Override
public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
Rect osf) {
- if (mWillReplaceWindow && (mExiting || !mReplacingRemoveRequested)) {
+ if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
// want to apply any more changes to it, so it remains in this state until new window
@@ -1074,7 +1085,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
*/
private boolean isVisibleUnchecked() {
return mHasSurface && mPolicyVisibility && !mAttachedHidden
- && !mExiting && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
+ && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
}
/**
@@ -1099,7 +1110,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
final AppWindowToken atoken = mAppToken;
final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
- return mHasSurface && !mDestroying && !mExiting
+ return mHasSurface && !mDestroying && !mAnimatingExit
&& (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
&& ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
|| mWinAnimator.mAnimation != null || animating);
@@ -1142,7 +1153,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
&& mPolicyVisibility && !mAttachedHidden
&& (atoken == null || !atoken.hiddenRequested)
- && !mExiting && !mDestroying;
+ && !mAnimatingExit && !mDestroying;
}
/**
@@ -1234,9 +1245,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mViewVisibility == View.GONE
|| !mRelayoutCalled
|| (atoken == null && mRootToken.hidden)
- || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
+ || (atoken != null && atoken.hiddenRequested)
|| mAttachedHidden
- || (mExiting && !isAnimatingLw())
+ || (mAnimatingExit && !isAnimatingLw())
|| mDestroying;
}
@@ -1282,7 +1293,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
*/
boolean hasMoved() {
return mHasSurface && (mContentChanged || mMovedByResize)
- && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
+ && !mAnimatingExit && !mWinAnimator.mLastHidden && mService.okToDisplay()
&& (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
&& (mAttachedWindow == null || !mAttachedWindow.hasMoved());
}
@@ -1373,6 +1384,39 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
}
+ /**
+ * Notifies this window that the corresponding task has just moved in the stack.
+ * <p>
+ * This is used to fix the following: If we moved in the stack, and if the last clip rect was
+ * empty, meaning that our task was completely offscreen, we need to keep it invisible because
+ * the actual app transition that updates the visibility is delayed by a few transactions.
+ * Instead of messing around with the ordering and timing how transitions and transactions are
+ * executed, we introduce this little hack which prevents this window of getting visible again
+ * with the wrong bounds until the app transitions has started.
+ * <p>
+ * This method notifies the window about that we just moved in the stack so we can apply this
+ * logic in {@link WindowStateAnimator#updateSurfaceWindowCrop}
+ */
+ void notifyMovedInStack() {
+ mJustMovedInStack = true;
+ }
+
+ /**
+ * See {@link #notifyMovedInStack}.
+ *
+ * @return Whether we just got moved in the corresponding stack.
+ */
+ boolean hasJustMovedInStack() {
+ return mJustMovedInStack;
+ }
+
+ /**
+ * Resets that we just moved in the corresponding stack. See {@link #notifyMovedInStack}.
+ */
+ void resetJustMovedInStack() {
+ mJustMovedInStack = false;
+ }
+
private final class DeadWindowEventReceiver extends InputEventReceiver {
DeadWindowEventReceiver(InputChannel inputChannel) {
super(inputChannel, mService.mH.getLooper());
@@ -1437,11 +1481,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return;
}
- if (!mExiting && mAppDied) {
+ if (!mAnimatingExit && mAppDied) {
// If app died visible, apply a dim over the window to indicate that it's inactive
mDisplayContent.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
} else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
- && mDisplayContent != null && !mExiting && isDisplayedLw()) {
+ && mDisplayContent != null && !mAnimatingExit && isDisplayedLw()) {
mDisplayContent.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
}
}
@@ -1466,7 +1510,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
win.mAnimateReplacingWindow = false;
win.mReplacingRemoveRequested = false;
win.mReplacingWindow = null;
- if (win.mExiting) {
+ if (win.mAnimatingExit) {
mService.removeWindowInnerLocked(win);
}
}
@@ -1621,11 +1665,14 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mService.removeWindowLocked(win);
if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
// The owner of the docked divider died :( We reset the docked stack,
- // just in case they have the divider at an unstable position.
+ // 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);
if (stack != null) {
stack.resetDockedStackToMiddle();
}
+ mService.setDockedStackResizing(false);
}
} else if (mHasSurface) {
Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
@@ -1806,7 +1853,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
boolean isClosing() {
- return mExiting || (mService.mClosingApps.contains(mAppToken));
+ return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
}
boolean isAnimatingWithSavedSurface() {
@@ -1832,6 +1879,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return false;
}
+ if (mResizedWhileGone) {
+ // Somebody resized our window while we were gone for layout, which means that the
+ // client got an old size, so we have an outdated surface here.
+ return false;
+ }
+
if (DEBUG_DISABLE_SAVING_SURFACES) {
return false;
}
@@ -1864,6 +1917,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
public void restoreSavedSurface() {
+ if (!mSurfaceSaved) {
+ return;
+ }
mSurfaceSaved = false;
setHasSurface(true);
mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
@@ -2085,7 +2141,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mTmpRect;
}
- private int getStackId() {
+ @Override
+ public int getStackId() {
final TaskStack stack = getStack();
if (stack == null) {
return INVALID_STACK_ID;
@@ -2098,7 +2155,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
Configuration newConfig) throws RemoteException {
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
reportDraw, newConfig, getBackdropFrame(frame),
- isDragResizeChanged() /* forceRelayout */);
+ isDragResizeChanged() /* forceRelayout */, mPolicy.isNavBarForcedShownLw(this));
+ mDragResizingChangeReported = true;
}
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -2133,6 +2191,20 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mDragResizing != computeDragResizing();
}
+ /**
+ * @return Whether we reported a drag resize change to the application or not already.
+ */
+ boolean isDragResizingChangeReported() {
+ return mDragResizingChangeReported;
+ }
+
+ /**
+ * Resets the state whether we reported a drag resize change to the app.
+ */
+ void resetDragResizingChangeReported() {
+ mDragResizingChangeReported = false;
+ }
+
int getResizeMode() {
return mResizeMode;
}
@@ -2142,6 +2214,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (task == null) {
return false;
}
+ if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
+
+ // Floating windows never enter drag resize mode.
+ return false;
+ }
if (task.isDragResizing()) {
return true;
}
@@ -2157,7 +2234,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
void setDragResizing() {
- mDragResizing = computeDragResizing();
+ final boolean resizing = computeDragResizing();
+ if (resizing == mDragResizing) {
+ return;
+ }
+ mDragResizing = resizing;
mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
? DRAG_RESIZE_MODE_DOCKED_DIVIDER
: DRAG_RESIZE_MODE_FREEFORM;
@@ -2266,7 +2347,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
- pw.print(" hasSavedSurface()="); pw.println(hasSavedSurface());
+ pw.print(" hasSavedSurface()="); pw.print(hasSavedSurface());
+ pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
if (dumpAll) {
pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
pw.print(" last="); mLastFrame.printShortString(pw);
@@ -2309,8 +2391,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
mWinAnimator.dump(pw, prefix + " ", dumpAll);
- if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
- pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
+ if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
+ pw.print(prefix); pw.print("mAnimatingExit="); pw.print(mAnimatingExit);
pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
pw.print(" mDestroying="); pw.print(mDestroying);
pw.print(" mRemoved="); pw.println(mRemoved);
@@ -2371,12 +2453,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
@Override
public String toString() {
final CharSequence title = getWindowTag();
- if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) {
+ if (mStringNameCache == null || mLastTitle != title || mWasExiting != mAnimatingExit) {
mLastTitle = title;
- mWasExiting = mExiting;
+ mWasExiting = mAnimatingExit;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
+ " u" + UserHandle.getUserId(mSession.mUid)
- + " " + mLastTitle + (mExiting ? " EXITING}" : "}");
+ + " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}");
}
return mStringNameCache;
}
@@ -2479,4 +2561,20 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mReplacingWindow = null;
mAnimateReplacingWindow = false;
}
+
+ float translateToWindowX(float x) {
+ float winX = x - mFrame.left;
+ if (mEnforceSizeCompat) {
+ winX *= mGlobalScale;
+ }
+ return winX;
+ }
+
+ float translateToWindowY(float y) {
+ float winY = y - mFrame.top;
+ if (mEnforceSizeCompat) {
+ winY *= mGlobalScale;
+ }
+ return winY;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 02012961f5be..02f9aa13c939 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,7 +29,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -375,7 +374,7 @@ class WindowStateAnimator {
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
- TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
+ TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
+ ", reportedVisible="
+ (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
@@ -430,7 +429,7 @@ class WindowStateAnimator {
void finishExit() {
if (DEBUG_ANIM) Slog.v(
TAG, "finishExit in " + this
- + ": exiting=" + mWin.mExiting
+ + ": exiting=" + mWin.mAnimatingExit
+ " remove=" + mWin.mRemoveOnExit
+ " windowAnimating=" + isWindowAnimating());
@@ -460,7 +459,7 @@ class WindowStateAnimator {
}
}
- if (!mWin.mExiting) {
+ if (!mWin.mAnimatingExit) {
return;
}
@@ -475,27 +474,27 @@ class WindowStateAnimator {
mWin.mDestroying = true;
+ final boolean hasSurface = hasSurface();
+ if (hasSurface) {
+ hide("finishExit");
+ }
+
// If we have an app token, we ask it to destroy the surface for us,
// so that it can take care to ensure the activity has actually stopped
// and the surface is not still in use. Otherwise we add the service to
// mDestroySurface and allow it to be processed in our next transaction.
if (mWin.mAppToken != null) {
- if (hasSurface()) {
- hide("finishExit");
- }
mWin.mAppToken.destroySurfaces();
} else {
- if (hasSurface()) {
+ if (hasSurface) {
mService.mDestroySurface.add(mWin);
- hide("finishExit");
}
- mWin.mExiting = false;
if (mWin.mRemoveOnExit) {
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
}
}
-
+ mWin.mAnimatingExit = false;
mWallpaperControllerLocked.hideWallpapers(mWin);
}
@@ -557,14 +556,21 @@ class WindowStateAnimator {
if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = performShowLocked();
}
- if (mDestroyPreservedSurfaceUponRedraw) {
- mService.mDestroyPreservedSurface.add(mWin);
- }
return result;
}
void preserveSurfaceLocked() {
if (mDestroyPreservedSurfaceUponRedraw) {
+ // This could happen when switching the surface mode very fast. For example,
+ // we preserved a surface when dragResizing changed to true. Then before the
+ // preserved surface is removed, dragResizing changed to false again.
+ // In this case, we need to leave the preserved surface alone, and destroy
+ // the actual surface, so that the createSurface call could create a surface
+ // of the proper size. The preserved surface will still be removed when client
+ // finishes drawing to the new surface.
+ mSurfaceDestroyDeferred = false;
+ destroySurfaceLocked();
+ mSurfaceDestroyDeferred = true;
return;
}
if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false);
@@ -593,119 +599,118 @@ class WindowStateAnimator {
return mSurfaceController;
}
- if (mSurfaceController == null) {
- if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
- "createSurface " + this + ": mDrawState=DRAW_PENDING");
- mDrawState = DRAW_PENDING;
- if (w.mAppToken != null) {
- if (w.mAppToken.mAppAnimator.animation == null) {
- w.mAppToken.allDrawn = false;
- w.mAppToken.deferClearAllDrawn = false;
- } else {
- // Currently animating, persist current state of allDrawn until animation
- // is complete.
- w.mAppToken.deferClearAllDrawn = true;
- }
- }
+ if (mSurfaceController != null) {
+ return mSurfaceController;
+ }
- mService.makeWindowFreezingScreenIfNeededLocked(w);
+ w.setHasSurface(false);
- int flags = SurfaceControl.HIDDEN;
- final WindowManager.LayoutParams attrs = w.mAttrs;
+ if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
+ "createSurface " + this + ": mDrawState=DRAW_PENDING");
- if (mService.isSecureLocked(w)) {
- flags |= SurfaceControl.SECURE;
+ mDrawState = DRAW_PENDING;
+ if (w.mAppToken != null) {
+ if (w.mAppToken.mAppAnimator.animation == null) {
+ w.mAppToken.allDrawn = false;
+ w.mAppToken.deferClearAllDrawn = false;
+ } else {
+ // Currently animating, persist current state of allDrawn until animation
+ // is complete.
+ w.mAppToken.deferClearAllDrawn = true;
}
+ }
- mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
- calculateSurfaceBounds(w, attrs);
- final int width = mTmpSize.width();
- final int height = mTmpSize.height();
-
- if (DEBUG_VISIBILITY) {
- Slog.v(TAG, "Creating surface in session "
- + mSession.mSurfaceSession + " window " + this
- + " w=" + width + " h=" + height
- + " x=" + mTmpSize.left + " y=" + mTmpSize.top
- + " format=" + attrs.format + " flags=" + flags);
- }
+ mService.makeWindowFreezingScreenIfNeededLocked(w);
- // We may abort, so initialize to defaults.
- mLastSystemDecorRect.set(0, 0, 0, 0);
- mHasClipRect = false;
- mClipRect.set(0, 0, 0, 0);
- mLastClipRect.set(0, 0, 0, 0);
-
- // Set up surface control with initial size.
- try {
-
- final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
- final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
- if (!PixelFormat.formatHasAlpha(attrs.format)
- // Don't make surface with surfaceInsets opaque as they display a
- // translucent shadow.
- && attrs.surfaceInsets.left == 0
- && attrs.surfaceInsets.top == 0
- && attrs.surfaceInsets.right == 0
- && attrs.surfaceInsets.bottom == 0
- // Don't make surface opaque when resizing to reduce the amount of
- // artifacts shown in areas the app isn't drawing content to.
- && !w.isDragResizing()) {
- flags |= SurfaceControl.OPAQUE;
- }
+ int flags = SurfaceControl.HIDDEN;
+ final WindowManager.LayoutParams attrs = w.mAttrs;
- mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
- attrs.getTitle().toString(),
- width, height, format, flags, this);
+ if (mService.isSecureLocked(w)) {
+ flags |= SurfaceControl.SECURE;
+ }
- w.setHasSurface(true);
+ mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
+ calculateSurfaceBounds(w, attrs);
+ final int width = mTmpSize.width();
+ final int height = mTmpSize.height();
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- Slog.i(TAG, " CREATE SURFACE "
- + mSurfaceController + " IN SESSION "
- + mSession.mSurfaceSession
- + ": pid=" + mSession.mPid + " format="
- + attrs.format + " flags=0x"
- + Integer.toHexString(flags)
- + " / " + this);
- }
- } catch (OutOfResourcesException e) {
- w.setHasSurface(false);
- Slog.w(TAG, "OutOfResourcesException creating surface");
- mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
- mDrawState = NO_SURFACE;
- return null;
- } catch (Exception e) {
- w.setHasSurface(false);
- Slog.e(TAG, "Exception creating surface", e);
- mDrawState = NO_SURFACE;
- return null;
- }
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG, "Creating surface in session "
+ + mSession.mSurfaceSession + " window " + this
+ + " w=" + width + " h=" + height
+ + " x=" + mTmpSize.left + " y=" + mTmpSize.top
+ + " format=" + attrs.format + " flags=" + flags);
+ }
+
+ // We may abort, so initialize to defaults.
+ mLastSystemDecorRect.set(0, 0, 0, 0);
+ mHasClipRect = false;
+ mClipRect.set(0, 0, 0, 0);
+ mLastClipRect.set(0, 0, 0, 0);
+
+ // Set up surface control with initial size.
+ try {
- if (WindowManagerService.localLOGV) {
- Slog.v(TAG, "Got surface: " + mSurfaceController
- + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
- + ", animLayer=" + mAnimLayer);
+ final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
+ final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+ if (!PixelFormat.formatHasAlpha(attrs.format)
+ // Don't make surface with surfaceInsets opaque as they display a
+ // translucent shadow.
+ && attrs.surfaceInsets.left == 0
+ && attrs.surfaceInsets.top == 0
+ && attrs.surfaceInsets.right == 0
+ && attrs.surfaceInsets.bottom == 0
+ // Don't make surface opaque when resizing to reduce the amount of
+ // artifacts shown in areas the app isn't drawing content to.
+ && !w.isDragResizing()) {
+ flags |= SurfaceControl.OPAQUE;
}
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
- WindowManagerService.logSurface(w, "CREATE pos=("
- + w.mFrame.left + "," + w.mFrame.top + ") ("
- + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
+ mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
+ attrs.getTitle().toString(),
+ width, height, format, flags, this);
+
+ w.setHasSurface(true);
+
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ Slog.i(TAG, " CREATE SURFACE "
+ + mSurfaceController + " IN SESSION "
+ + mSession.mSurfaceSession
+ + ": pid=" + mSession.mPid + " format="
+ + attrs.format + " flags=0x"
+ + Integer.toHexString(flags)
+ + " / " + this);
}
+ } catch (OutOfResourcesException e) {
+ Slog.w(TAG, "OutOfResourcesException creating surface");
+ mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
+ mDrawState = NO_SURFACE;
+ return null;
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception creating surface", e);
+ mDrawState = NO_SURFACE;
+ return null;
+ }
- // Start a new transaction and apply position & offset.
- final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
- if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
- mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack,
- mAnimLayer);
- mLastHidden = true;
+ if (WindowManagerService.localLOGV) Slog.v(TAG, "Got surface: " + mSurfaceController
+ + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
+ + ", animLayer=" + mAnimLayer);
- if (WindowManagerService.localLOGV) Slog.v(
- TAG, "Created surface " + this);
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
+ WindowManagerService.logSurface(w, "CREATE pos=("
+ + w.mFrame.left + "," + w.mFrame.top + ") ("
+ + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
}
+
+ // Start a new transaction and apply position & offset.
+ final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
+ if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
+ mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
+ mLastHidden = true;
+
+ if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
return mSurfaceController;
}
@@ -776,59 +781,59 @@ class WindowStateAnimator {
mWin.mSurfaceSaved = false;
- if (mSurfaceController != null) {
- int i = mWin.mChildWindows.size();
- // When destroying a surface we want to make sure child windows
- // are hidden. If we are preserving the surface until redraw though
- // we intend to swap it out with another surface for resizing. In this case
- // the window always remains visible to the user and the child windows
- // should likewise remain visable.
- while (!mDestroyPreservedSurfaceUponRedraw && i > 0) {
- i--;
- WindowState c = mWin.mChildWindows.get(i);
- c.mAttachedHidden = true;
- }
+ if (mSurfaceController == null) {
+ return;
+ }
- try {
- if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
- + mSurfaceController + ", session " + mSession);
- if (mSurfaceDestroyDeferred) {
- if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
- if (mPendingDestroySurface != null) {
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
- }
- mPendingDestroySurface.destroyInTransaction();
+ int i = mWin.mChildWindows.size();
+ // When destroying a surface we want to make sure child windows are hidden. If we are
+ // preserving the surface until redraw though we intend to swap it out with another surface
+ // for resizing. In this case the window always remains visible to the user and the child
+ // windows should likewise remain visible.
+ while (!mDestroyPreservedSurfaceUponRedraw && i > 0) {
+ i--;
+ WindowState c = mWin.mChildWindows.get(i);
+ c.mAttachedHidden = true;
+ }
+
+ try {
+ if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
+ + mSurfaceController + ", session " + mSession);
+ if (mSurfaceDestroyDeferred) {
+ if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
+ if (mPendingDestroySurface != null) {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
}
- mPendingDestroySurface = mSurfaceController;
- }
- } else {
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- WindowManagerService.logSurface(mWin, "DESTROY", true);
+ mPendingDestroySurface.destroyInTransaction();
}
- destroySurface();
+ mPendingDestroySurface = mSurfaceController;
}
- // Don't hide wallpaper if we're deferring the surface destroy
- // because of a surface change.
- if (!(mSurfaceDestroyDeferred && mDestroyPreservedSurfaceUponRedraw)) {
- mWallpaperControllerLocked.hideWallpapers(mWin);
+ } else {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ WindowManagerService.logSurface(mWin, "DESTROY", true);
}
- } catch (RuntimeException e) {
- Slog.w(TAG, "Exception thrown when destroying Window " + this
- + " surface " + mSurfaceController + " session " + mSession
- + ": " + e.toString());
+ destroySurface();
}
-
- // Whether the surface was preserved (and copied to mPendingDestroySurface) or not, it
- // needs to be cleared to match the WindowState.mHasSurface state. It is also necessary
- // so it can be recreated successfully in mPendingDestroySurface case.
- mWin.setHasSurface(false);
- if (mSurfaceController != null) {
- mSurfaceController.setShown(false);
+ // Don't hide wallpaper if we're deferring the surface destroy
+ // because of a surface change.
+ if (!mDestroyPreservedSurfaceUponRedraw) {
+ mWallpaperControllerLocked.hideWallpapers(mWin);
}
- mSurfaceController = null;
- mDrawState = NO_SURFACE;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Exception thrown when destroying Window " + this
+ + " surface " + mSurfaceController + " session " + mSession + ": " + e.toString());
+ }
+
+ // Whether the surface was preserved (and copied to mPendingDestroySurface) or not, it
+ // needs to be cleared to match the WindowState.mHasSurface state. It is also necessary
+ // so it can be recreated successfully in mPendingDestroySurface case.
+ mWin.setHasSurface(false);
+ if (mSurfaceController != null) {
+ mSurfaceController.setShown(false);
}
+ mSurfaceController = null;
+ mDrawState = NO_SURFACE;
}
void destroyDeferredSurfaceLocked() {
@@ -1186,6 +1191,11 @@ class WindowStateAnimator {
w.transformFromScreenToSurfaceSpace(clipRect);
+ // See {@link WindowState#notifyMovedInStack} for why this is necessary.
+ if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
+ clipRect.setEmpty();
+ }
+
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1213,6 +1223,11 @@ class WindowStateAnimator {
return;
}
+ final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+ if (w == winShowWhenLocked) {
+ return;
+ }
+
final TaskStack stack = task.mStack;
stack.getDimBounds(mTmpStackBounds);
// When we resize we use the big surface approach, which means we can't trust the
@@ -1328,6 +1343,9 @@ class WindowStateAnimator {
if (prepared && mLastHidden && mDrawState == HAS_DRAWN) {
if (showSurfaceRobustlyLocked()) {
+ if (mDestroyPreservedSurfaceUponRedraw) {
+ mService.mDestroyPreservedSurface.add(mWin);
+ }
mAnimator.requestRemovalOfReplacedWindows(w);
mLastHidden = false;
if (mIsWallpaper) {
@@ -1509,23 +1527,7 @@ class WindowStateAnimator {
}
if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING && mWin.mAppToken != null) {
- mWin.mAppToken.firstWindowDrawn = true;
-
- // We now have a good window to show, remove dead placeholders
- mWin.mAppToken.removeAllDeadWindows();
-
- if (mWin.mAppToken.startingData != null) {
- if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
- + mWin.mToken + ": first real window is shown, no animation");
- // If this initial window is animating, stop it -- we
- // will do an animation to reveal it from behind the
- // starting window, so there is no need for it to also
- // be doing its own stuff.
- clearAnimation();
- mService.mFinishedStarting.add(mWin.mAppToken);
- mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
- }
- mWin.mAppToken.updateReportedVisibilityLocked();
+ mWin.mAppToken.onFirstWindowDrawn(mWin, this);
}
return true;
@@ -1736,8 +1738,18 @@ class WindowStateAnimator {
}
void destroySurface() {
- mSurfaceController.destroyInTransaction();
- mSurfaceController = null;
+ try {
+ if (mSurfaceController != null) {
+ mSurfaceController.destroyInTransaction();
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Exception thrown when destroying surface " + this
+ + " surface " + mSurfaceController + " session " + mSession + ": " + e);
+ } finally {
+ mWin.setHasSurface(false);
+ mSurfaceController = null;
+ mDrawState = NO_SURFACE;
+ }
}
void setMoveAnimation(int left, int top) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 3219bfe26aac..2972a248b00d 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
@@ -62,6 +63,8 @@ class WindowSurfaceController {
// the window. We achieve this by explicitly hiding the surface and not letting it be shown.
private boolean mHiddenForCrop = false;
+ // Initially a surface is hidden after just being created.
+ private boolean mHiddenForOtherReasons = true;
private final String title;
public WindowSurfaceController(SurfaceSession s,
@@ -94,6 +97,11 @@ class WindowSurfaceController {
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
+ mHiddenForOtherReasons = true;
+ updateVisibility();
+ }
+
+ private void hideSurface() {
if (mSurfaceControl != null) {
mSurfaceShown = false;
try {
@@ -133,11 +141,14 @@ class WindowSurfaceController {
Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(4));
// }
try {
- mSurfaceControl.destroy();
- mSurfaceShown = false;
- mSurfaceControl = null;
+ if (mSurfaceControl != null) {
+ mSurfaceControl.destroy();
+ }
} catch (RuntimeException e) {
Slog.w(TAG, "Error destroying surface in: " + this, e);
+ } finally {
+ mSurfaceShown = false;
+ mSurfaceControl = null;
}
}
@@ -148,9 +159,10 @@ class WindowSurfaceController {
if (clipRect.width() > 0 && clipRect.height() > 0) {
mSurfaceControl.setWindowCrop(clipRect);
mHiddenForCrop = false;
+ updateVisibility();
} else {
- hideInTransaction("setCrop");
mHiddenForCrop = true;
+ updateVisibility();
}
} catch (RuntimeException e) {
Slog.w(TAG, "Error setting crop surface of " + this
@@ -313,11 +325,26 @@ class WindowSurfaceController {
"SHOW (performLayout)", null);
if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
+ " during relayout");
+ mHiddenForOtherReasons = false;
+ return updateVisibility();
+ }
- if (mHiddenForCrop) {
+ private boolean updateVisibility() {
+ if (mHiddenForCrop || mHiddenForOtherReasons) {
+ if (mSurfaceShown) {
+ hideSurface();
+ }
return false;
+ } else {
+ if (!mSurfaceShown) {
+ return showSurface();
+ } else {
+ return true;
+ }
}
+ }
+ private boolean showSurface() {
try {
mSurfaceShown = true;
mSurfaceControl.show();
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4e1b644df368..856d30ab7cf1 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -1,5 +1,9 @@
package com.android.server.wm;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_SAVED_SURFACE;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_STARTING_WINDOW;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
@@ -7,7 +11,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
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_WALLPAPER;
@@ -43,6 +46,7 @@ import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -676,8 +680,10 @@ class WindowSurfacePlacer {
// currently animating... let's do something.
final int left = w.mFrame.left;
final int top = w.mFrame.top;
+ final boolean adjustedForMinimizedDockedStack = w.getTask() != null &&
+ w.getTask().mStack.isAdjustedForMinimizedDockedStack();
if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
- && !w.isDragResizing()) {
+ && !w.isDragResizing() && !adjustedForMinimizedDockedStack) {
winAnimator.setMoveAnimation(left, top);
}
@@ -751,7 +757,7 @@ class WindowSurfacePlacer {
}
if ((w.isOnScreenIgnoringKeyguard()
|| winAnimator.mAttrType == TYPE_BASE_APPLICATION)
- && !w.mExiting && !w.mDestroying) {
+ && !w.mAnimatingExit && !w.mDestroying) {
if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
Slog.v(TAG, "Eval win " + w + ": isDrawn="
+ w.isDrawnLw()
@@ -781,6 +787,7 @@ class WindowSurfacePlacer {
}
}
} else if (w.isDrawnLw()) {
+ mService.mH.sendEmptyMessage(NOTIFY_STARTING_WINDOW_DRAWN);
atoken.startingDisplayed = true;
}
}
@@ -1099,6 +1106,7 @@ class WindowSurfacePlacer {
processApplicationsAnimatingInPlace(transit);
+ mTmpLayerAndToken.token = null;
handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken);
final AppWindowToken topClosingApp = mTmpLayerAndToken.token;
final int topClosingLayer = mTmpLayerAndToken.layer;
@@ -1111,7 +1119,8 @@ class WindowSurfacePlacer {
final AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
topClosingApp.mAppAnimator;
- mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
+ mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator,
+ mService.mOpeningApps, mService.mClosingApps);
mService.mAppTransition.postAnimationCallback();
mService.mAppTransition.clear();
@@ -1181,17 +1190,17 @@ class WindowSurfacePlacer {
int layer = -1;
for (int j = 0; j < wtoken.windows.size(); j++) {
final WindowState win = wtoken.windows.get(j);
- // Clearing the mExiting flag before entering animation. It will be set to true
+ // Clearing the mAnimatingExit flag before entering animation. It will be set to true
// if app window is removed, or window relayout to invisible. We don't want to
// clear it out for windows that get replaced, because the animation depends on
// the flag to remove the replaced window.
//
- // We also don't clear the mExiting flag for windows which have the
+ // We also don't clear the mAnimatingExit flag for windows which have the
// mRemoveOnExit flag. This indicates an explicit remove request has been issued
// by the client. We should let animation proceed and not clear this flag or
// they won't eventually be removed by WindowStateAnimator#finishExit.
if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
- win.mExiting = false;
+ win.mAnimatingExit = false;
}
if (win.mWinAnimator.mAnimLayer > layer) {
layer = win.mWinAnimator.mAnimLayer;
@@ -1230,7 +1239,7 @@ class WindowSurfacePlacer {
wtoken.deferClearAllDrawn = false;
// Ensure that apps that are mid-starting are also scheduled to have their
// starting windows removed after the animation is complete
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+ if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
mService.scheduleRemoveStartingWindowLocked(wtoken);
}
mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
@@ -1259,6 +1268,7 @@ class WindowSurfacePlacer {
"Checking " + appsCount + " opening apps (frozen="
+ mService.mDisplayFrozen + " timeout="
+ mService.mAppTransition.isTimeout() + ")...");
+ int reason = APP_TRANSITION_TIMEOUT;
if (!mService.mAppTransition.isTimeout()) {
for (int i = 0; i < appsCount; i++) {
AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
@@ -1268,11 +1278,18 @@ class WindowSurfacePlacer {
+ wtoken.startingDisplayed + " startingMoved="
+ wtoken.startingMoved);
+ final boolean drawnBeforeRestoring = wtoken.allDrawn;
wtoken.restoreSavedSurfaces();
if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
return false;
}
+ if (wtoken.allDrawn) {
+ reason = drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN
+ : APP_TRANSITION_SAVED_SURFACE;
+ } else {
+ reason = APP_TRANSITION_STARTING_WINDOW;
+ }
}
// We also need to wait for the specs to be fetched, if needed.
@@ -1282,9 +1299,15 @@ class WindowSurfacePlacer {
}
// If the wallpaper is visible, we need to check it's ready too.
- return !mWallpaperControllerLocked.isWallpaperVisible() ||
+ boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
mWallpaperControllerLocked.wallpaperTransitionReady();
+ if (wallpaperReady) {
+ mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reason, 0).sendToTarget();
+ return true;
+ }
+ return false;
}
+ mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reason, 0).sendToTarget();
return true;
}
diff --git a/core/java/android/view/animation/ClipRectLRAnimation.java b/services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java
index 8993cd3a2753..0db4c70e2761 100644
--- a/core/java/android/view/animation/ClipRectLRAnimation.java
+++ b/services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 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.
@@ -11,12 +11,14 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
*/
-package android.view.animation;
+package com.android.server.wm.animation;
import android.graphics.Rect;
+import android.view.animation.ClipRectAnimation;
+import android.view.animation.Transformation;
/**
* Special case of ClipRectAnimation that animates only the left/right
diff --git a/services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java b/services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java
new file mode 100644
index 000000000000..1f5b1a3f9660
--- /dev/null
+++ b/services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java
@@ -0,0 +1,86 @@
+/*
+ * 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.animation;
+
+import android.graphics.Rect;
+import android.view.animation.ClipRectAnimation;
+import android.view.animation.Interpolator;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateAnimation;
+
+/**
+ * Special case of ClipRectAnimation that animates only the top/bottom
+ * dimensions of the clip, picking up the other dimensions from whatever is
+ * set on the transform already. In addition to that, information about a vertical translation
+ * animation can be specified so this animation simulates as the clip would be applied after instead
+ * of before applying the translation.
+ */
+public class ClipRectTBAnimation extends ClipRectAnimation {
+
+ private final int mFromTranslateY;
+ private final int mToTranslateY;
+ private final Interpolator mTranslateInterpolator;
+ private float mNormalizedTime;
+
+ /**
+ * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation
+ */
+ public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB,
+ int fromTranslateY, int toTranslateY, Interpolator translateInterpolator) {
+ super(0, fromT, 0, fromB, 0, toT, 0, toB);
+ mFromTranslateY = fromTranslateY;
+ mToTranslateY = toTranslateY;
+ mTranslateInterpolator = translateInterpolator;
+ }
+
+ @Override
+ public boolean getTransformation(long currentTime, Transformation outTransformation) {
+
+ // Hack: Because translation animation has a different interpolator, we need to duplicate
+ // code from Animation here and use it to calculate/store the uninterpolated normalized
+ // time.
+ final long startOffset = getStartOffset();
+ final long duration = getDuration();
+ float normalizedTime;
+ if (duration != 0) {
+ normalizedTime = ((float) (currentTime - (getStartTime() + startOffset))) /
+ (float) duration;
+ } else {
+ // time is a step-change with a zero duration
+ normalizedTime = currentTime < getStartTime() ? 0.0f : 1.0f;
+ }
+ mNormalizedTime = normalizedTime;
+ return super.getTransformation(currentTime, outTransformation);
+ }
+
+ /**
+ * Calculates and sets clip rect on given transformation. It uses existing values
+ * on the Transformation for Left/Right clip parameters.
+ */
+ @Override
+ protected void applyTransformation(float it, Transformation tr) {
+ float translationT = mTranslateInterpolator.getInterpolation(mNormalizedTime);
+ int translation =
+ (int) (mFromTranslateY + (mToTranslateY - mFromTranslateY) * translationT);
+ Rect oldClipRect = tr.getClipRect();
+ tr.setClipRect(oldClipRect.left,
+ mFromRect.top - translation + (int) ((mToRect.top - mFromRect.top) * it),
+ oldClipRect.right,
+ mFromRect.bottom - translation + (int) ((mToRect.bottom - mFromRect.bottom) * it));
+ }
+
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index bb571c3d0631..5e5c6d9321e3 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -17,6 +17,7 @@ LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
diff --git a/core/jni/android_os_HardwarePropertiesManager.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index dc1ba48097b8..214d9882c499 100644
--- a/core/jni/android_os_HardwarePropertiesManager.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "HardwarePropertiesManager-JNI"
+#define LOG_TAG "HardwarePropertiesManagerService-JNI"
#include "JNIHelp.h"
#include "jni.h"
@@ -137,7 +137,7 @@ static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
// ----------------------------------------------------------------------------
-static const JNINativeMethod gHardwarePropertiesManagerMethods[] = {
+static const JNINativeMethod gHardwarePropertiesManagerServiceMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()V",
(void*) nativeInit },
@@ -149,11 +149,11 @@ static const JNINativeMethod gHardwarePropertiesManagerMethods[] = {
(void*) nativeGetCpuUsages }
};
-int register_android_os_HardwarePropertiesManager(JNIEnv* env) {
+int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
gHardwarePropertiesModule = nullptr;
- int res = jniRegisterNativeMethods(env, "android/os/HardwarePropertiesManager",
- gHardwarePropertiesManagerMethods,
- NELEM(gHardwarePropertiesManagerMethods));
+ int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
+ gHardwarePropertiesManagerServiceMethods,
+ NELEM(gHardwarePropertiesManagerServiceMethods));
jclass clazz = env->FindClass("android/os/CpuUsageInfo");
gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index b72cf4dc94d0..656c2141ff2e 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -330,7 +330,7 @@ static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
jsize len = env->GetArrayLength(body);
message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
ScopedByteArrayRO bodyPtr(env, body);
- std::memcpy(message.body, bodyPtr.get(), len);
+ std::memcpy(message.body, bodyPtr.get(), message.length);
HdmiCecController* controller =
reinterpret_cast<HdmiCecController*>(controllerPtr);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e75775fa9237..c97323c60e70 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -29,10 +29,11 @@
#include "android_runtime/Log.h"
#include <arpa/inet.h>
-#include <string.h>
-#include <pthread.h>
+#include <limits>
#include <linux/in.h>
#include <linux/in6.h>
+#include <pthread.h>
+#include <string.h>
static jobject mCallbacksObj = NULL;
@@ -42,7 +43,7 @@ static jmethodID method_reportSvStatus;
static jmethodID method_reportAGpsStatus;
static jmethodID method_reportNmea;
static jmethodID method_setEngineCapabilities;
-static jmethodID method_setGpsYearOfHardware;
+static jmethodID method_setGnssYearOfHardware;
static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
static jmethodID method_requestRefLocation;
@@ -68,13 +69,14 @@ static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
-#define MAX_SATELLITE_COUNT 512
-#define MAX_GPS_SATELLITE_COUNT 512
+#define GPS_MAX_SATELLITE_COUNT 32
+#define GNSS_MAX_SATELLITE_COUNT 64
-#define PRN_SHIFT_WIDTH 3
+#define SVID_SHIFT_WIDTH 7
+#define CONSTELLATION_TYPE_SHIFT_WIDTH 3
// temporary storage for GPS callbacks
-static GnssSvInfo sGnssSvList[MAX_SATELLITE_COUNT];
+static GnssSvInfo sGnssSvList[GNSS_MAX_SATELLITE_COUNT];
static size_t sGnssSvListSize;
static const char* sNmeaString;
static int sNmeaStringLength;
@@ -113,56 +115,74 @@ static void sv_status_callback(GpsSvStatus* sv_status)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
size_t status_size = sv_status->size;
- // Some drive doesn't set the size field correctly. Assume GpsSvStatus_v1 if
- // it doesn't provide a valid size.
+ // Some drives doesn't set the size field correctly. Assume GpsSvStatus_v1
+ // if it doesn't provide a valid size.
if (status_size == 0) {
- status_size = sizeof(GpsSvStatus_v1);
- }
- if (status_size == sizeof(GpsSvStatus)) {
- sGnssSvListSize = sv_status->gnss_sv_list_size;
- // Cramp the list size
- if (sGnssSvListSize > MAX_SATELLITE_COUNT) {
- sGnssSvListSize = MAX_SATELLITE_COUNT;
- }
- // Copy GNSS SV info into sGnssSvList, if any.
- if (sGnssSvListSize > 0 && sv_status->gnss_sv_list) {
- memcpy(sGnssSvList, sv_status->gnss_sv_list, sizeof(GnssSvInfo) * sGnssSvListSize);
- }
- } else if (status_size == sizeof(GpsSvStatus_v1)) {
- sGnssSvListSize = sv_status->num_svs;
- // Cramp the list size
- if (sGnssSvListSize > MAX_GPS_SATELLITE_COUNT) {
- sGnssSvListSize = MAX_GPS_SATELLITE_COUNT;
- }
- uint32_t ephemeris_mask = sv_status->ephemeris_mask;
- uint32_t almanac_mask = sv_status->almanac_mask;
- uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
- for (size_t i = 0; i < sGnssSvListSize; i++) {
- GnssSvInfo& info = sGnssSvList[i];
+ ALOGW("Invalid size of GpsSvStatus found: %zd.", status_size);
+ }
+ sGnssSvListSize = sv_status->num_svs;
+ // Clamp the list size. Legacy GpsSvStatus has only 32 elements in sv_list.
+ if (sGnssSvListSize > GPS_MAX_SATELLITE_COUNT) {
+ ALOGW("Too many satellites %zd. Clamps to %d.",
+ sGnssSvListSize,
+ GPS_MAX_SATELLITE_COUNT);
+ sGnssSvListSize = GPS_MAX_SATELLITE_COUNT;
+ }
+ uint32_t ephemeris_mask = sv_status->ephemeris_mask;
+ uint32_t almanac_mask = sv_status->almanac_mask;
+ uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
+ for (size_t i = 0; i < sGnssSvListSize; i++) {
+ GnssSvInfo& info = sGnssSvList[i];
+ info.svid = sv_status->sv_list[i].prn;
+ if (info.svid >=1 && info.svid <= 32) {
info.constellation = GNSS_CONSTELLATION_GPS;
- info.prn = sv_status->sv_list[i].prn;
- info.snr = sv_status->sv_list[i].snr;
- info.elevation = sv_status->sv_list[i].elevation;
- info.azimuth = sv_status->sv_list[i].azimuth;
- info.flags = GNSS_SV_FLAGS_NONE;
- if (info.prn > 0 && info.prn <= 32) {
- int32_t this_prn_mask = (1 << (info.prn - 1));
- if ((ephemeris_mask & this_prn_mask) != 0) {
+ } else {
+ ALOGD("Unknown constellation type with Svid = %d.", info.svid);
+ info.constellation = GNSS_CONSTELLATION_UNKNOWN;
+ }
+ info.snr = sv_status->sv_list[i].snr;
+ info.elevation = sv_status->sv_list[i].elevation;
+ info.azimuth = sv_status->sv_list[i].azimuth;
+ info.flags = GNSS_SV_FLAGS_NONE;
+ if (info.svid > 0 && info.svid <= 32) {
+ int32_t this_svid_mask = (1 << (info.svid - 1));
+ if ((ephemeris_mask & this_svid_mask) != 0) {
info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
- }
- if ((almanac_mask & this_prn_mask) != 0) {
+ }
+ if ((almanac_mask & this_svid_mask) != 0) {
info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
- }
- if ((used_in_fix_mask & this_prn_mask) != 0) {
+ }
+ if ((used_in_fix_mask & this_svid_mask) != 0) {
info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
- }
}
}
- } else {
- sGnssSvListSize = 0;
- ALOGE("Invalid size of GpsSvStatus found: %zd.", status_size);
+ }
+ env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void gnss_sv_status_callback(GnssSvStatus* sv_status) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ size_t status_size = sv_status->size;
+ // Check the size, and reject the object that has invalid size.
+ if (status_size != sizeof(GnssSvStatus)) {
+ ALOGE("Invalid size of GnssSvStatus found: %zd.", status_size);
return;
}
+ sGnssSvListSize = sv_status->num_svs;
+ // Clamp the list size
+ if (sGnssSvListSize > GNSS_MAX_SATELLITE_COUNT) {
+ ALOGD("Too many satellites %zd. Clamps to %d.",
+ sGnssSvListSize,
+ GNSS_MAX_SATELLITE_COUNT);
+ sGnssSvListSize = GNSS_MAX_SATELLITE_COUNT;
+ }
+ // Copy GNSS SV info into sGnssSvList, if any.
+ if (sGnssSvListSize > 0) {
+ memcpy(sGnssSvList,
+ sv_status->gnss_sv_list,
+ sizeof(GnssSvInfo) * sGnssSvListSize);
+ }
env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
@@ -178,10 +198,10 @@ static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-static void set_system_info_callback(const GpsSystemInfo* info) {
+static void set_system_info_callback(const GnssSystemInfo* info) {
ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(mCallbacksObj, method_setGpsYearOfHardware,
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
info->year_of_hw);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
@@ -228,6 +248,7 @@ GpsCallbacks sGpsCallbacks = {
create_thread_callback,
request_utc_time_callback,
set_system_info_callback,
+ gnss_sv_status_callback,
};
static void xtra_download_request_callback()
@@ -515,7 +536,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
- method_setGpsYearOfHardware = env->GetMethodID(clazz, "setGpsYearOfHardware", "(I)V");
+ method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
@@ -677,31 +698,30 @@ static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /*
}
static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
- jintArray prnWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
- jfloatArray azumArray, jintArray constellationTypeArray)
+ jintArray svidWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+ jfloatArray azumArray)
{
// this should only be called from within a call to reportSvStatus
- jint* prnWithFlags = env->GetIntArrayElements(prnWithFlagArray, 0);
+ jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
- jint* constellationTypes = env->GetIntArrayElements(constellationTypeArray, 0);
// GNSS SV info.
for (size_t i = 0; i < sGnssSvListSize; ++i) {
const GnssSvInfo& info = sGnssSvList[i];
- constellationTypes[i] = info.constellation;
- prnWithFlags[i] = (info.prn << PRN_SHIFT_WIDTH) | info.flags;
+ svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
+ (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+ info.flags;
snrs[i] = info.snr;
elev[i] = info.elevation;
azim[i] = info.azimuth;
}
- env->ReleaseIntArrayElements(prnWithFlagArray, prnWithFlags, 0);
+ env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
env->ReleaseFloatArrayElements(snrArray, snrs, 0);
env->ReleaseFloatArrayElements(elevArray, elev, 0);
env->ReleaseFloatArrayElements(azumArray, azim, 0);
- env->ReleaseIntArrayElements(constellationTypeArray, constellationTypes, 0);
return (jint) sGnssSvListSize;
}
@@ -968,370 +988,380 @@ static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /*
return JNI_FALSE;
}
-static jobject translate_gps_clock(JNIEnv* env, void* data, size_t size) {
- const char* doubleSignature = "(D)V";
- const char* longSignature = "(J)V";
-
- GpsClock* clock = reinterpret_cast<GpsClock*>(data);
-
- jclass gpsClockClass = env->FindClass("android/location/GnssClock");
- jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
-
- jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
- GpsClockFlags flags = clock->flags;
-
- if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
- }
-
- jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
- env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
+template<class T>
+class JavaMethodHelper {
+ public:
+ // Helper function to call setter on a Java object.
+ static void callJavaMethod(
+ JNIEnv* env,
+ jclass clazz,
+ jobject object,
+ const char* method_name,
+ T value);
+
+ private:
+ static const char *const signature_;
+};
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
+template<class T>
+void JavaMethodHelper<T>::callJavaMethod(
+ JNIEnv* env,
+ jclass clazz,
+ jobject object,
+ const char* method_name,
+ T value) {
+ jmethodID method = env->GetMethodID(clazz, method_name, signature_);
+ env->CallVoidMethod(object, method, value);
+}
- if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
- }
+class JavaObject {
+ public:
+ JavaObject(JNIEnv* env, const char* class_name);
+ virtual ~JavaObject();
+
+ template<class T>
+ void callSetter(const char* method_name, T value);
+ template<class T>
+ void callSetter(const char* method_name, T* value, size_t size);
+ jobject get();
+
+ private:
+ JNIEnv* env_;
+ jclass clazz_;
+ jobject object_;
+};
- if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
- }
+JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) {
+ clazz_ = env_->FindClass(class_name);
+ jmethodID ctor = env->GetMethodID(clazz_, "<init>", "()V");
+ object_ = env_->NewObject(clazz_, ctor);
+}
- if (flags & GPS_CLOCK_HAS_BIAS) {
- jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
- }
+JavaObject::~JavaObject() {
+ env_->DeleteLocalRef(clazz_);
+}
- if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
- }
+template<class T>
+void JavaObject::callSetter(const char* method_name, T value) {
+ JavaMethodHelper<T>::callJavaMethod(
+ env_, clazz_, object_, method_name, value);
+}
- if (flags & GPS_CLOCK_HAS_DRIFT) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
- }
+template<>
+void JavaObject::callSetter(
+ const char* method_name, uint8_t* value, size_t size) {
+ jbyteArray array = env_->NewByteArray(size);
+ env_->SetByteArrayRegion(array, 0, size, (jbyte*) value);
+ jmethodID method = env_->GetMethodID(
+ clazz_,
+ method_name,
+ "([B)V");
+ env_->CallVoidMethod(object_, method, array);
+}
- if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
- env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
- }
+jobject JavaObject::get() {
+ return object_;
+}
- if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
- if (size == sizeof(GpsClock)) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass,
- "setTimeOfLastHwClockDiscontinuityInNs",
- longSignature);
- env->CallVoidMethod(gpsClockObject,
- setterMethod,
- clock->time_of_last_hw_clock_discontinuity_ns);
- }
- }
+// Define Java method signatures for all known types.
+
+template<>
+const char *const JavaMethodHelper<uint8_t>::signature_ = "(B)V";
+template<>
+const char *const JavaMethodHelper<int8_t>::signature_ = "(B)V";
+template<>
+const char *const JavaMethodHelper<int16_t>::signature_ = "(S)V";
+template<>
+const char *const JavaMethodHelper<uint16_t>::signature_ = "(S)V";
+template<>
+const char *const JavaMethodHelper<int32_t>::signature_ = "(I)V";
+template<>
+const char *const JavaMethodHelper<uint32_t>::signature_ = "(I)V";
+template<>
+const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V";
+template<>
+const char *const JavaMethodHelper<float>::signature_ = "(F)V";
+template<>
+const char *const JavaMethodHelper<double>::signature_ = "(D)V";
+template<>
+const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
+
+#define SET(setter, value) object.callSetter("set" # setter, (value))
+#define SET_IF(flag, setter, value) \
+ if (flags & (flag)) object.callSetter("set" # setter, (value))
+
+static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+ static uint32_t discontinuity_count_to_handle_old_lock_type = 0;
+ JavaObject object(env, "android/location/GnssClock");
+ GpsClockFlags flags = clock->flags;
- env->DeleteLocalRef(gpsClockClass);
- return gpsClockObject;
+ SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+
+ // GnssClock only supports the more effective HW_CLOCK type, so type
+ // handling and documentation complexity has been removed. To convert the
+ // old GPS_CLOCK types (active only in a limited number of older devices),
+ // the GPS time information is handled as an always discontinuous HW clock,
+ // with the GPS time information put into the full_bias_ns instead - so that
+ // time_ns + full_bias_ns = local estimate of GPS time (as remains true, in
+ // the new GnssClock struct.)
+ switch (clock->type) {
+ case GPS_CLOCK_TYPE_UNKNOWN:
+ // Clock type unsupported.
+ ALOGE("Unknown clock type provided.");
+ break;
+ case GPS_CLOCK_TYPE_LOCAL_HW_TIME:
+ // Already local hardware time. No need to do anything.
+ break;
+ case GPS_CLOCK_TYPE_GPS_TIME:
+ // GPS time, need to convert.
+ flags |= GNSS_CLOCK_HAS_FULL_BIAS;
+ clock->full_bias_ns = clock->time_ns;
+ clock->time_ns = 0;
+ SET(HardwareClockDiscontinuityCount,
+ discontinuity_count_to_handle_old_lock_type++);
+ break;
+ }
+
+ SET(TimeInNs, clock->time_ns);
+ SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
+ TimeUncertaintyInNs,
+ clock->time_uncertainty_ns);
+ SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
+ BiasUncertaintyInNs,
+ clock->bias_uncertainty_ns);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+ DriftUncertaintyInNsPerSec,
+ clock->drift_uncertainty_nsps);
+
+ return object.get();
}
-static jobject translate_gps_measurement(JNIEnv* env, void* data, size_t size) {
- const char* byteSignature = "(B)V";
- const char* shortSignature = "(S)V";
- const char* intSignature = "(I)V";
- const char* longSignature = "(J)V";
- const char* floatSignature = "(F)V";
- const char* doubleSignature = "(D)V";
+static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
+ JavaObject object(env, "android/location/GnssClock");
+ GpsClockFlags flags = clock->flags;
- jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
- jmethodID gnssMeasurementCtor = env->GetMethodID(gnssMeasurementClass, "<init>", "()V");
- GpsMeasurement* measurement = reinterpret_cast<GpsMeasurement*>(data);
+ SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+ SET(Type, static_cast<uint8_t>(GPS_CLOCK_TYPE_LOCAL_HW_TIME));
+ SET(TimeInNs, clock->time_ns);
+ SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
+ TimeUncertaintyInNs,
+ clock->time_uncertainty_ns);
+ SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
+ BiasUncertaintyInNs,
+ clock->bias_uncertainty_ns);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+ DriftUncertaintyInNsPerSec,
+ clock->drift_uncertainty_nsps);
+
+ SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
+
+ return object.get();
+}
- jobject gnssMeasurementObject = env->NewObject(gnssMeasurementClass, gnssMeasurementCtor);
+static jobject translate_gps_measurement(JNIEnv* env,
+ GpsMeasurement* measurement) {
+ JavaObject object(env, "android/location/GnssMeasurement");
GpsMeasurementFlags flags = measurement->flags;
+ SET(Svid, static_cast<int16_t>(measurement->prn));
+ if (measurement->prn >= 1 || measurement->prn <= 32) {
+ SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+ } else {
+ ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
+ SET(ConstellationType,
+ static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+ }
+ SET(TimeOffsetInNs, measurement->time_offset_ns);
+ SET(State, measurement->state);
+ SET(ReceivedSvTimeInNs, measurement->received_gps_tow_ns);
+ SET(ReceivedSvTimeUncertaintyInNs,
+ measurement->received_gps_tow_uncertainty_ns);
+ SET(Cn0InDbHz, measurement->c_n0_dbhz);
+ SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
+ SET(PseudorangeRateUncertaintyInMetersPerSec,
+ measurement->pseudorange_rate_uncertainty_mps);
+ SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
+ SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
+ SET(AccumulatedDeltaRangeUncertaintyInMeters,
+ measurement->accumulated_delta_range_uncertainty_m);
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
+ PseudorangeInMeters,
+ measurement->pseudorange_m);
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+ PseudorangeUncertaintyInMeters,
+ measurement->pseudorange_uncertainty_m);
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
+ CodePhaseInChips,
+ measurement->code_phase_chips);
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+ CodePhaseUncertaintyInChips,
+ measurement->code_phase_uncertainty_chips);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+ CarrierFrequencyInHz,
+ measurement->carrier_frequency_hz);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
+ CarrierCycles,
+ measurement->carrier_cycles);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
+ CarrierPhase,
+ measurement->carrier_phase);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+ CarrierPhaseUncertainty,
+ measurement->carrier_phase_uncertainty);
+ SET(LossOfLock, measurement->loss_of_lock);
+ SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+ SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+ TimeFromLastBitInMs,
+ measurement->time_from_last_bit_ms);
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+ DopplerShiftInHz,
+ measurement->doppler_shift_hz);
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+ DopplerShiftUncertaintyInHz,
+ measurement->doppler_shift_uncertainty_hz);
+ SET(MultipathIndicator, measurement->multipath_indicator);
+ SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
+ ElevationInDeg,
+ measurement->elevation_deg);
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+ ElevationUncertaintyInDeg,
+ measurement->elevation_uncertainty_deg);
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
+ AzimuthInDeg,
+ measurement->azimuth_deg);
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+ AzimuthUncertaintyInDeg,
+ measurement->azimuth_uncertainty_deg);
+ SET(UsedInFix,
+ (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+ return object.get();
+}
- jmethodID prnSetterMethod = env->GetMethodID(gnssMeasurementClass, "setPrn", byteSignature);
- env->CallVoidMethod(gnssMeasurementObject, prnSetterMethod, measurement->prn);
-
- jmethodID timeOffsetSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setTimeOffsetInNs", doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- timeOffsetSetterMethod,
- measurement->time_offset_ns);
+static jobject translate_gnss_measurement(JNIEnv* env,
+ GnssMeasurement* measurement) {
+ JavaObject object(env, "android/location/GnssMeasurement");
+ GpsMeasurementFlags flags = measurement->flags;
- jmethodID stateSetterMethod = env->GetMethodID(gnssMeasurementClass, "setState", shortSignature);
- env->CallVoidMethod(gnssMeasurementObject, stateSetterMethod, measurement->state);
+ SET(Svid, measurement->svid);
+ SET(ConstellationType, measurement->constellation);
+ SET(TimeOffsetInNs, measurement->time_offset_ns);
+ SET(State, measurement->state);
+ SET(ReceivedSvTimeInNs, measurement->received_sv_time_in_ns);
+ SET(ReceivedSvTimeUncertaintyInNs,
+ measurement->received_sv_time_uncertainty_in_ns);
+ SET(Cn0InDbHz, measurement->c_n0_dbhz);
+ SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
+ SET(PseudorangeRateUncertaintyInMetersPerSec,
+ measurement->pseudorange_rate_uncertainty_mps);
+ SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
+ SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
+ SET(AccumulatedDeltaRangeUncertaintyInMeters,
+ measurement->accumulated_delta_range_uncertainty_m);
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
+ PseudorangeInMeters,
+ measurement->pseudorange_m);
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+ PseudorangeUncertaintyInMeters,
+ measurement->pseudorange_uncertainty_m);
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
+ CodePhaseInChips,
+ measurement->code_phase_chips);
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+ CodePhaseUncertaintyInChips,
+ measurement->code_phase_uncertainty_chips);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+ CarrierFrequencyInHz,
+ measurement->carrier_frequency_hz);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
+ CarrierCycles,
+ measurement->carrier_cycles);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
+ CarrierPhase,
+ measurement->carrier_phase);
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+ CarrierPhaseUncertainty,
+ measurement->carrier_phase_uncertainty);
+ SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+ SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+ TimeFromLastBitInMs,
+ measurement->time_from_last_bit_ms);
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+ DopplerShiftInHz,
+ measurement->doppler_shift_hz);
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+ DopplerShiftUncertaintyInHz,
+ measurement->doppler_shift_uncertainty_hz);
+ SET(MultipathIndicator, measurement->multipath_indicator);
+ SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
+ ElevationInDeg,
+ measurement->elevation_deg);
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+ ElevationUncertaintyInDeg,
+ measurement->elevation_uncertainty_deg);
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
+ AzimuthInDeg,
+ measurement->azimuth_deg);
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+ AzimuthUncertaintyInDeg,
+ measurement->azimuth_uncertainty_deg);
+ SET(UsedInFix,
+ (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+ return object.get();
+}
- jmethodID receivedGpsTowSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setReceivedGpsTowInNs", longSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- receivedGpsTowSetterMethod,
- measurement->received_gps_tow_ns);
+static jobjectArray translate_gps_measurements(JNIEnv* env,
+ GpsMeasurement* measurements,
+ size_t count) {
+ if (count == 0) {
+ return NULL;
+ }
- jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setReceivedGpsTowUncertaintyInNs",
- longSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- receivedGpsTowUncertaintySetterMethod,
- measurement->received_gps_tow_uncertainty_ns);
-
- jmethodID cn0SetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCn0InDbHz", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
-
- jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setPseudorangeRateInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- pseudorangeRateSetterMethod,
- measurement->pseudorange_rate_mps);
-
- jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setPseudorangeRateUncertaintyInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- pseudorangeRateUncertaintySetterMethod,
- measurement->pseudorange_rate_uncertainty_mps);
-
- jmethodID accumulatedDeltaRangeStateSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- accumulatedDeltaRangeStateSetterMethod,
- measurement->accumulated_delta_range_state);
-
- jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setAccumulatedDeltaRangeInMeters",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- accumulatedDeltaRangeSetterMethod,
- measurement->accumulated_delta_range_m);
-
- jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
+ jclass gnssMeasurementClass = env->FindClass(
+ "android/location/GnssMeasurement");
+ jobjectArray gnssMeasurementArray = env->NewObjectArray(
+ count,
gnssMeasurementClass,
- "setAccumulatedDeltaRangeUncertaintyInMeters",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- accumulatedDeltaRangeUncertaintySetterMethod,
- measurement->accumulated_delta_range_uncertainty_m);
-
- if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setPseudorangeInMeters", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->pseudorange_m);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setPseudorangeUncertaintyInMeters",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->pseudorange_uncertainty_m);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCodePhaseInChips", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->code_phase_chips);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setCodePhaseUncertaintyInChips",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->code_phase_uncertainty_chips);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->carrier_frequency_hz);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCarrierCycles", longSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->carrier_cycles);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setCarrierPhase", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->carrier_phase);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setCarrierPhaseUncertainty",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->carrier_phase_uncertainty);
- }
-
- jmethodID lossOfLockSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setLossOfLock", byteSignature);
- env->CallVoidMethod(gnssMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
-
- if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setBitNumber", intSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->bit_number);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->time_from_last_bit_ms);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setDopplerShiftInHz", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->doppler_shift_hz);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setDopplerShiftUncertaintyInHz",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->doppler_shift_uncertainty_hz);
- }
-
- jmethodID multipathIndicatorSetterMethod =
- env->GetMethodID(gnssMeasurementClass, "setMultipathIndicator", byteSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- multipathIndicatorSetterMethod,
- measurement->multipath_indicator);
-
- if (flags & GPS_MEASUREMENT_HAS_SNR) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setSnrInDb", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->snr_db);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setElevationInDeg", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->elevation_deg);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->elevation_uncertainty_deg);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass, "setAzimuthInDeg", doubleSignature);
- env->CallVoidMethod(gnssMeasurementObject, setterMethod, measurement->azimuth_deg);
- }
-
- if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
- jmethodID setterMethod = env->GetMethodID(
- gnssMeasurementClass,
- "setAzimuthUncertaintyInDeg",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->azimuth_uncertainty_deg);
- }
-
- jmethodID usedInFixSetterMethod = env->GetMethodID(gnssMeasurementClass, "setUsedInFix", "(Z)V");
- env->CallVoidMethod(
- gnssMeasurementObject,
- usedInFixSetterMethod,
- (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
-
- if (size == sizeof(GpsMeasurement)) {
- jmethodID setterMethod =
- env->GetMethodID(gnssMeasurementClass,
- "setPseudorangeRateCarrierInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->pseudorange_rate_carrier_mps);
-
- setterMethod =
- env->GetMethodID(gnssMeasurementClass,
- "setPseudorangeRateCarrierUncertaintyInMetersPerSec",
- doubleSignature);
- env->CallVoidMethod(
- gnssMeasurementObject,
- setterMethod,
- measurement->pseudorange_rate_carrier_uncertainty_mps);
+ NULL /* initialElement */);
+
+ for (uint16_t i = 0; i < count; ++i) {
+ jobject gnssMeasurement = translate_gps_measurement(
+ env,
+ &measurements[i]);
+ env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
+ env->DeleteLocalRef(gnssMeasurement);
}
env->DeleteLocalRef(gnssMeasurementClass);
- return gnssMeasurementObject;
+ return gnssMeasurementArray;
}
-/**
- * <T> can only be GpsData or GpsData_v1. Must rewrite this function if more
- * types are introduced in the future releases.
- */
-template<class T>
-static jobjectArray translate_gps_measurements(JNIEnv* env, void* data) {
- T* gps_data = reinterpret_cast<T*>(data);
- size_t measurementCount = gps_data->measurement_count;
- if (measurementCount == 0) {
+static jobjectArray translate_gnss_measurements(JNIEnv* env,
+ GnssMeasurement* measurements,
+ size_t count) {
+ if (count == 0) {
return NULL;
}
- jclass gnssMeasurementClass = env->FindClass("android/location/GnssMeasurement");
+ jclass gnssMeasurementClass = env->FindClass(
+ "android/location/GnssMeasurement");
jobjectArray gnssMeasurementArray = env->NewObjectArray(
- measurementCount,
+ count,
gnssMeasurementClass,
NULL /* initialElement */);
- for (uint16_t i = 0; i < measurementCount; ++i) {
- jobject gnssMeasurement = translate_gps_measurement(
+ for (uint16_t i = 0; i < count; ++i) {
+ jobject gnssMeasurement = translate_gnss_measurement(
env,
- &(gps_data->measurements[i]),
- sizeof(gps_data->measurements[0]));
+ &measurements[i]);
env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
env->DeleteLocalRef(gnssMeasurement);
}
@@ -1340,50 +1370,81 @@ static jobjectArray translate_gps_measurements(JNIEnv* env, void* data) {
return gnssMeasurementArray;
}
+static void set_measurement_data(JNIEnv *env,
+ jobject clock,
+ jobjectArray measurementArray) {
+ jclass gnssMeasurementsEventClass = env->FindClass(
+ "android/location/GnssMeasurementsEvent");
+ jmethodID gnssMeasurementsEventCtor = env->GetMethodID(
+ gnssMeasurementsEventClass,
+ "<init>",
+ "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V");
+
+ jobject gnssMeasurementsEvent = env->NewObject(
+ gnssMeasurementsEventClass,
+ gnssMeasurementsEventCtor,
+ clock,
+ measurementArray);
+ env->CallVoidMethod(mCallbacksObj,
+ method_reportMeasurementData,
+ gnssMeasurementsEvent);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ env->DeleteLocalRef(gnssMeasurementsEventClass);
+ env->DeleteLocalRef(gnssMeasurementsEvent);
+}
+
static void measurement_callback(GpsData* data) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
if (data == NULL) {
ALOGE("Invalid data provided to gps_measurement_callback");
return;
}
- if (data->size != sizeof(GpsData) && data->size != sizeof(GpsData_v1)) {
- ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
+ if (data->size != sizeof(GpsData)) {
+ ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+ "size=%zd",
+ data->size);
return;
}
- jobject gpsClock;
+ jobject clock;
jobjectArray measurementArray;
- if (data->size == sizeof(GpsData)) {
- gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock));
- measurementArray = translate_gps_measurements<GpsData>(env, data);
- } else {
- gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock_v1));
- measurementArray = translate_gps_measurements<GpsData_v1>(env, data);
- }
- jclass gnssMeasurementsEventClass = env->FindClass("android/location/GnssMeasurementsEvent");
- jmethodID gnssMeasurementsEventCtor = env->GetMethodID(
- gnssMeasurementsEventClass,
- "<init>",
- "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V");
+ clock = translate_gps_clock(env, &data->clock);
+ measurementArray = translate_gps_measurements(
+ env, data->measurements, data->measurement_count);
+ set_measurement_data(env, clock, measurementArray);
- jobject gnssMeasurementsEvent = env->NewObject(
- gnssMeasurementsEventClass,
- gnssMeasurementsEventCtor,
- gpsClock,
- measurementArray);
+ env->DeleteLocalRef(clock);
+ env->DeleteLocalRef(measurementArray);
+}
- env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gnssMeasurementsEvent);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
+static void gnss_measurement_callback(GnssData* data) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (data == NULL) {
+ ALOGE("Invalid data provided to gps_measurement_callback");
+ return;
+ }
+ if (data->size != sizeof(GpsData)) {
+ ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+ "size=%zd",
+ data->size);
+ return;
+ }
+
+ jobject clock;
+ jobjectArray measurementArray;
+ clock = translate_gnss_clock(env, &data->clock);
+ measurementArray = translate_gnss_measurements(
+ env, data->measurements, data->measurement_count);
+ set_measurement_data(env, clock, measurementArray);
- env->DeleteLocalRef(gpsClock);
+ env->DeleteLocalRef(clock);
env->DeleteLocalRef(measurementArray);
- env->DeleteLocalRef(gnssMeasurementsEventClass);
- env->DeleteLocalRef(gnssMeasurementsEvent);
}
GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
sizeof(GpsMeasurementCallbacks),
measurement_callback,
+ gnss_measurement_callback,
};
static jboolean android_location_GnssLocationProvider_is_measurement_supported(
@@ -1431,69 +1492,96 @@ static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessag
ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
return NULL;
}
+ JavaObject object(env, "android/location/GnssNavigationMessage");
+ SET(Svid, static_cast<int16_t>(message->prn));
+ if (message->prn >=1 && message->prn <= 32) {
+ SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+ // Legacy driver doesn't set the higher byte to constellation type
+ // correctly. Set the higher byte to 'GPS'.
+ SET(Type, static_cast<int16_t>(message->type | 0x0100));
+ } else {
+ ALOGD("Unknown constellation type with Svid = %d.", message->prn);
+ SET(ConstellationType,
+ static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+ SET(Type, static_cast<int16_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
+ }
+ SET(MessageId, message->message_id);
+ SET(SubmessageId, message->submessage_id);
+ object.callSetter("setData", data, dataLength);
+ return object.get();
+}
- jclass navigationMessageClass = env->FindClass("android/location/GnssNavigationMessage");
- jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
- jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
-
- jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
- env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
-
- jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
- env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
-
- jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
- env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
-
- jmethodID setSubmessageIdMethod =
- env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
- env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
-
- jbyteArray dataArray = env->NewByteArray(dataLength);
- env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
- jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
- env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
+static jobject translate_gnss_navigation_message(
+ JNIEnv* env, GnssNavigationMessage* message) {
+ size_t dataLength = message->data_length;
+ uint8_t* data = message->data;
+ if (dataLength == 0 || data == NULL) {
+ ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
+ return NULL;
+ }
+ JavaObject object(env, "android/location/GnssNavigationMessage");
+ SET(Type, message->type);
+ SET(Svid, message->svid);
+ SET(MessageId, message->message_id);
+ SET(SubmessageId, message->submessage_id);
+ object.callSetter("setData", data, dataLength);
+ return object.get();
+}
- env->DeleteLocalRef(navigationMessageClass);
- env->DeleteLocalRef(dataArray);
- return navigationMessageObject;
+static void set_navigation_message(jobject navigationMessage) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jclass navigationMessageEventClass =
+ env->FindClass("android/location/GnssNavigationMessageEvent");
+ jmethodID navigationMessageEventCtor = env->GetMethodID(
+ navigationMessageEventClass,
+ "<init>",
+ "(Landroid/location/GnssNavigationMessage;)V");
+ jobject navigationMessageEvent = env->NewObject(
+ navigationMessageEventClass,
+ navigationMessageEventCtor,
+ navigationMessage);
+ env->CallVoidMethod(mCallbacksObj,
+ method_reportNavigationMessages,
+ navigationMessageEvent);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ env->DeleteLocalRef(navigationMessageEventClass);
+ env->DeleteLocalRef(navigationMessageEvent);
}
static void navigation_message_callback(GpsNavigationMessage* message) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
if (message == NULL) {
ALOGE("Invalid Navigation Message provided to callback");
return;
}
-
- if (message->size == sizeof(GpsNavigationMessage)) {
- jobject navigationMessage = translate_gps_navigation_message(env, message);
-
- jclass navigationMessageEventClass =
- env->FindClass("android/location/GnssNavigationMessageEvent");
- jmethodID navigationMessageEventCtor = env->GetMethodID(
- navigationMessageEventClass,
- "<init>",
- "(Landroid/location/GnssNavigationMessage;)V");
- jobject navigationMessageEvent = env->NewObject(
- navigationMessageEventClass,
- navigationMessageEventCtor,
- navigationMessage);
-
- env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
- env->DeleteLocalRef(navigationMessage);
- env->DeleteLocalRef(navigationMessageEventClass);
- env->DeleteLocalRef(navigationMessageEvent);
- } else {
+ if (message->size != sizeof(GpsNavigationMessage)) {
ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
+ return;
+ }
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject navigationMessage = translate_gps_navigation_message(env, message);
+ set_navigation_message(navigationMessage);
+ env->DeleteLocalRef(navigationMessage);
+}
+
+static void gnss_navigation_message_callback(GnssNavigationMessage* message) {
+ if (message == NULL) {
+ ALOGE("Invalid Navigation Message provided to callback");
+ return;
+ }
+ if (message->size != sizeof(GnssNavigationMessage)) {
+ ALOGE("Invalid GnssNavigationMessage size found: %zd", message->size);
+ return;
}
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject navigationMessage = translate_gnss_navigation_message(env, message);
+ set_navigation_message(navigationMessage);
+ env->DeleteLocalRef(navigationMessage);
}
GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
sizeof(GpsNavigationMessageCallbacks),
navigation_message_callback,
+ gnss_navigation_message_callback,
};
static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
@@ -1567,7 +1655,7 @@ static const JNINativeMethod sMethods[] = {
"(I)V",
(void*)android_location_GnssLocationProvider_delete_aiding_data},
{"native_read_sv_status",
- "([I[F[F[F[I)I",
+ "([I[F[F[F)I",
(void*)android_location_GnssLocationProvider_read_sv_status},
{"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ef5c56c1bcfa..be99673a4cb5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -44,6 +44,7 @@ int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
+int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
};
using namespace android;
@@ -83,6 +84,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
+ register_android_server_HardwarePropertiesManagerService(env);
return JNI_VERSION_1_4;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3fb5a0d39b84..0252ea45c0b6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -32,6 +32,7 @@ import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -115,6 +116,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -258,20 +260,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON);
}
- /** Keyguard features that when set on a profile will affect the profiles parent user. */
+ /**
+ * Keyguard features that when set on a managed profile that doesn't have its own challenge will
+ * affect the profile's parent user. These can also be set on the managed profile's parent DPM
+ * instance.
+ */
private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
- // STOPSHIP If the work challenge supports fingerprint, move DISABLE_FINGERPRINT
- // to PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE?
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
| DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
- /** Keyguard features that when set on a profile affect the profile content or challenge only */
- private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE =
+ /**
+ * Keyguard features that when set on a profile affect the profile content or challenge only.
+ * These cannot be set on the managed profile's parent DPM instance
+ */
+ private static final int PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY =
DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
/** Keyguard features that are allowed to be set on a managed profile */
private static final int PROFILE_KEYGUARD_FEATURES =
- PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
+ PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
+
+ private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
final Context mContext;
final Injector mInjector;
@@ -280,6 +289,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final UserManagerInternal mUserManagerInternal;
private final LockPatternUtils mLockPatternUtils;
+ /**
+ * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
+ * is requested for user u.
+ */
+ private final Set<Pair<String, Integer>> mPackagesToRemove =
+ new ArraySet<Pair<String, Integer>>();
+
final LocalService mLocalService;
// Stores and loads state on device and profile owners.
@@ -325,7 +341,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID);
+ RemoteBugreportUtils.NOTIFICATION_ID);
if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
onBugreportSharingAccepted();
} else if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED
@@ -426,9 +442,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
filterConsent.addAction(
RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notify(
- LOG_TAG, RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
- RemoteBugreportUtils.buildRemoteBugreportConsentNotification(mContext));
+ mInjector.getNotificationManager().notify(LOG_TAG,
+ RemoteBugreportUtils.NOTIFICATION_ID,
+ RemoteBugreportUtils.buildNotification(mContext,
+ RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -644,7 +661,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int getUid() { return info.getActivityInfo().applicationInfo.uid; }
public UserHandle getUserHandle() {
- return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
+ return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
}
void writeToXml(XmlSerializer out)
@@ -752,7 +769,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.attribute(null, ATTR_VALUE, Boolean.toString(disableContactsSearch));
out.endTag(null, TAG_DISABLE_CONTACTS_SEARCH);
}
- if (disableBluetoothContactSharing) {
+ if (!disableBluetoothContactSharing) {
out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
out.attribute(null, ATTR_VALUE,
Boolean.toString(disableBluetoothContactSharing));
@@ -1238,7 +1255,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (packageName == null || packageName.equals(adminPackage)) {
if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
|| mIPackageManager.getReceiverInfo(
- aa.info.getComponent(), 0, userHandle) == null) {
+ aa.info.getComponent(),
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ userHandle) == null) {
removed = true;
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
@@ -1670,7 +1689,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin,
- /* exceptionList =*/ null);
+ /* exceptionList =*/ null, /* isDeviceOwner =*/ true);
// Push DO user restrictions to user manager.
pushUserRestrictions(UserHandle.USER_SYSTEM);
@@ -1678,39 +1697,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mOwners.setDeviceOwnerUserRestrictionsMigrated();
}
- // Migrate for POs. We have a few more exceptions.
- final Set<String> normalExceptionList = Sets.newArraySet(
+ // Migrate for POs.
+
+ // The following restrictions can be set on secondary users by the device owner, so we
+ // assume they're not from the PO.
+ final Set<String> secondaryUserExceptionList = Sets.newArraySet(
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_SMS);
- final Set<String> managedExceptionList = new ArraySet<>(normalExceptionList.size() + 1);
- managedExceptionList.addAll(normalExceptionList);
- managedExceptionList.add(UserManager.DISALLOW_WALLPAPER);
-
for (UserInfo ui : mUserManager.getUsers()) {
final int userId = ui.id;
if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) {
- if (userId != UserHandle.USER_SYSTEM) {
- if (VERBOSE_LOG) {
- Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId);
- }
- migrated = true;
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId);
+ }
+ migrated = true;
- final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId);
+ final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId);
- final Set<String> exceptionList =
- ui.isManagedProfile() ? managedExceptionList : normalExceptionList;
+ final Set<String> exceptionList =
+ (userId == UserHandle.USER_SYSTEM) ? null : secondaryUserExceptionList;
- migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin,
- exceptionList);
+ migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin,
+ exceptionList, /* isDeviceOwner =*/ false);
- // Note if a secondary user has no PO but has a DA that disables camera, we
- // don't get here and won't push the camera user restriction to UserManager
- // here. That's okay because we'll push user restrictions anyway when a user
- // starts. But we still do it because we want to let user manager persist
- // upon migration.
- pushUserRestrictions(userId);
- }
+ // Note if a secondary user has no PO but has a DA that disables camera, we
+ // don't get here and won't push the camera user restriction to UserManager
+ // here. That's okay because we'll push user restrictions anyway when a user
+ // starts. But we still do it because we want to let user manager persist
+ // upon migration.
+ pushUserRestrictions(userId);
mOwners.setProfileOwnerUserRestrictionsMigrated(userId);
}
@@ -1721,7 +1737,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void migrateUserRestrictionsForUser(UserHandle user, ActiveAdmin admin,
- Set<String> exceptionList) {
+ Set<String> exceptionList, boolean isDeviceOwner) {
final Bundle origRestrictions = mUserManagerInternal.getBaseUserRestrictions(
user.getIdentifier());
@@ -1732,7 +1748,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!origRestrictions.getBoolean(key)) {
continue;
}
- if (exceptionList!= null && exceptionList.contains(key)) {
+ final boolean canOwnerChange = isDeviceOwner
+ ? UserRestrictionsUtils.canDeviceOwnerChange(key)
+ : UserRestrictionsUtils.canProfileOwnerChange(key, user.getIdentifier());
+
+ if (!canOwnerChange || (exceptionList!= null && exceptionList.contains(key))) {
newBaseRestrictions.putBoolean(key, true);
} else {
newOwnerRestrictions.putBoolean(key, true);
@@ -2014,66 +2034,50 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin != null) {
getUserData(userHandle).mRemovingAdmins.add(adminReceiver);
-
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- synchronized (DevicePolicyManagerService.this) {
- int userHandle = admin.getUserHandle().getIdentifier();
- DevicePolicyData policy = getUserData(userHandle);
- boolean doProxyCleanup = admin.info.usesPolicy(
- DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
- policy.mAdminList.remove(admin);
- policy.mAdminMap.remove(adminReceiver);
- validatePasswordOwnerLocked(policy);
- if (doProxyCleanup) {
- resetGlobalProxyLocked(getUserData(userHandle));
- }
- saveSettingsLocked(userHandle);
- updateMaximumTimeToLockLocked(userHandle);
- policy.mRemovingAdmins.remove(adminReceiver);
- }
- // The removed admin might have disabled camera, so update user
- // restrictions.
- pushUserRestrictions(userHandle);
+ removeAdminArtifacts(adminReceiver, userHandle);
+ removePackageIfRequired(adminReceiver.getPackageName(), userHandle);
}
});
}
}
+
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle,
boolean throwForMissiongPermission) {
if (!mHasFeature) {
return null;
}
enforceFullCrossUsersPermission(userHandle);
- Intent resolveIntent = new Intent();
- resolveIntent.setComponent(adminName);
- List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser(
- resolveIntent,
- PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
- PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
- userHandle);
- if (infos == null || infos.size() <= 0) {
+ ActivityInfo ai = null;
+ try {
+ ai = mIPackageManager.getReceiverInfo(adminName,
+ PackageManager.GET_META_DATA |
+ PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, userHandle);
+ } catch (RemoteException e) {
+ // shouldn't happen.
+ }
+ if (ai == null) {
throw new IllegalArgumentException("Unknown admin: " + adminName);
}
- final ResolveInfo ri = infos.get(0);
-
- if (!permission.BIND_DEVICE_ADMIN.equals(ri.activityInfo.permission)) {
+ if (!permission.BIND_DEVICE_ADMIN.equals(ai.permission)) {
final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
+ permission.BIND_DEVICE_ADMIN;
Slog.w(LOG_TAG, message);
if (throwForMissiongPermission &&
- ri.activityInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
+ ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
throw new IllegalArgumentException(message);
}
}
try {
- return new DeviceAdminInfo(mContext, ri);
+ return new DeviceAdminInfo(mContext, ai);
} catch (XmlPullParserException | IOException e) {
Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
e);
@@ -2699,6 +2703,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (info == null) {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
}
+ if (!info.getActivityInfo().applicationInfo.isInternal()) {
+ throw new IllegalArgumentException("Only apps in internal storage can be active admin: "
+ + adminReceiver);
+ }
synchronized (this) {
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -2816,6 +2824,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
enforceFullCrossUsersPermission(userHandle);
+ enforceUserUnlocked(userHandle);
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin == null) {
@@ -2841,16 +2850,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private boolean isAdminApiLevelMOrBelow(@NonNull ComponentName who, int userHandle) {
- DeviceAdminInfo adminInfo = findAdmin(who, userHandle, false);
- return adminInfo.getActivityInfo().applicationInfo.targetSdkVersion
- <= Build.VERSION_CODES.M;
- }
-
@Override
public boolean isSeparateProfileChallengeAllowed(int userHandle) {
ComponentName profileOwner = getProfileOwner(userHandle);
- return profileOwner != null && !isAdminApiLevelMOrBelow(profileOwner, userHandle);
+ try {
+ // Profile challenge is supported on N or newer release.
+ return profileOwner != null &&
+ getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
+ } catch (RemoteException e) {
+ return false;
+ }
}
@Override
@@ -3527,11 +3536,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
+ enforceFullCrossUsersPermission(userHandle);
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(
- null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+ if (!isCallerWithSystemUid()) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(
+ null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+ }
DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
@@ -3863,7 +3875,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// challenge only and keep the screen on. However there is no easy way of doing that at the
// moment so we set the screen off timeout regardless of whether it affects the parent user
// or the profile challenge only.
- long timeMs = Integer.MAX_VALUE;
+ long timeMs = Long.MAX_VALUE;
List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
for (UserInfo userInfo : profiles) {
DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
@@ -3887,15 +3899,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final long ident = mInjector.binderClearCallingIdentity();
try {
- if (policy.mLastMaximumTimeToLock != Integer.MAX_VALUE) {
+ if (policy.mLastMaximumTimeToLock != Long.MAX_VALUE) {
// Make sure KEEP_SCREEN_ON is disabled, since that
// would allow bypassing of the maximum time to lock.
mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
- // TODO It can overflow. Cap it.
- mInjector.getPowerManagerInternal()
- .setMaximumScreenOffTimeoutFromDeviceAdmin((int)policy.mLastMaximumTimeToLock);
+ mInjector.getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
+ (int) Math.min(policy.mLastMaximumTimeToLock, Integer.MAX_VALUE));
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
@@ -4079,16 +4090,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
+ public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias,
+ boolean requestAccess) {
enforceCanManageInstalledKeys(who);
- final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+ final int callingUid = mInjector.binderGetCallingUid();
final long id = mInjector.binderClearCallingIdentity();
try {
- final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
+ final KeyChainConnection keyChainConnection =
+ KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
try {
IKeyChainService keyChain = keyChainConnection.getService();
- return keyChain.installKeyPair(privKey, cert, alias);
+ if (!keyChain.installKeyPair(privKey, cert, alias)) {
+ return false;
+ }
+ if (requestAccess) {
+ keyChain.setGrant(callingUid, alias, true);
+ }
+ return true;
} catch (RemoteException e) {
Log.e(LOG_TAG, "Installing certificate", e);
} finally {
@@ -4195,6 +4214,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int userHandle = UserHandle.getCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ try {
+ if (getTargetSdk(who.getPackageName(), userHandle) >= Build.VERSION_CODES.N) {
+ if (installerPackage != null &&
+ !isPackageInstalledForUser(installerPackage, userHandle)) {
+ throw new IllegalArgumentException("Package " + installerPackage
+ + " is not installed on the current user");
+ }
+ }
+ } catch (RemoteException e) {
+ }
DevicePolicyData policy = getUserData(userHandle);
policy.mDelegatedCertInstallerPackage = installerPackage;
saveSettingsLocked(userHandle);
@@ -4481,7 +4510,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (mInjector.securityLogIsLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0);
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
+ /*method strength*/ 1);
}
}
@@ -4511,23 +4541,50 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (mInjector.securityLogIsLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1);
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1,
+ /*method strength*/ 1);
}
}
@Override
- public void reportKeyguardDismissed() {
+ public void reportFailedFingerprintAttempt(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
if (mInjector.securityLogIsLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0,
+ /*method strength*/ 0);
+ }
+ }
+
+ @Override
+ public void reportSuccessfulFingerprintAttempt(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ if (mInjector.securityLogIsLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1,
+ /*method strength*/ 0);
+ }
+ }
+
+ @Override
+ public void reportKeyguardDismissed(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
}
}
@Override
- public void reportKeyguardSecured() {
+ public void reportKeyguardSecured(int userHandle) {
+ enforceFullCrossUsersPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
if (mInjector.securityLogIsLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
}
@@ -4919,6 +4976,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ // Allow setting this policy to true only if there is a split system user.
+ if (forceEphemeralUsers && !mInjector.userManagerIsSplitSystemUser()) {
+ throw new UnsupportedOperationException(
+ "Cannot force ephemeral users on systems without split system user.");
+ }
boolean removeAllUsers = false;
synchronized (this) {
final ActiveAdmin deviceOwner =
@@ -5006,13 +5068,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mRemoteBugreportServiceIsActive.set(true);
mRemoteBugreportSharingAccepted.set(false);
registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notify(
- LOG_TAG, RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
- RemoteBugreportUtils.buildRemoteBugreportConsentNotification(mContext));
- mInjector.getNotificationManager().notify(
- LOG_TAG, RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID,
- RemoteBugreportUtils.buildRemoteBugreportInProgressNotification(mContext,
- /* canCancelBugReport */ true));
+ mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+ RemoteBugreportUtils.buildNotification(mContext,
+ RemoteBugreportUtils.NOTIFICATION_BUGREPORT_STARTED));
mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
return true;
@@ -5062,8 +5120,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void onBugreportFinished(Intent intent) {
mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
mRemoteBugreportServiceIsActive.set(false);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID);
Uri bugreportUri = intent.getData();
String bugreportUriString = null;
if (bugreportUri != null) {
@@ -5073,8 +5129,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
RemoteBugreportUtils.EXTRA_REMOTE_BUGREPORT_HASH);
if (mRemoteBugreportSharingAccepted.get()) {
shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().cancel(LOG_TAG,
+ RemoteBugreportUtils.NOTIFICATION_ID);
} else {
setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+ RemoteBugreportUtils.buildNotification(mContext,
+ RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
}
mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
}
@@ -5085,10 +5146,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
mRemoteBugreportSharingAccepted.set(false);
setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID);
+ mInjector.getNotificationManager().cancel(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID);
Bundle extras = new Bundle();
extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
@@ -5108,10 +5166,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (bugreportUriString != null) {
shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
} else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notify(LOG_TAG,
- RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID,
- RemoteBugreportUtils.buildRemoteBugreportInProgressNotification(mContext,
- /* canCancelBugReport */ false));
+ mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+ RemoteBugreportUtils.buildNotification(mContext,
+ RemoteBugreportUtils.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED));
}
}
@@ -5125,8 +5182,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
mRemoteBugreportSharingAccepted.set(false);
setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID);
sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
}
@@ -5240,8 +5295,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (isManagedProfile(userHandle)) {
if (parent) {
which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
- } else if (isSeparateProfileChallengeEnabled(userHandle)){
- which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
} else {
which = which & PROFILE_KEYGUARD_FEATURES;
}
@@ -5289,7 +5342,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
int userId = admin.getUserHandle().getIdentifier();
- if (userId == userHandle || !isManagedProfile(userHandle)) {
+ boolean isRequestedUser = !parent && (userId == userHandle);
+ if (isRequestedUser || !isManagedProfile(userId)) {
// If we are being asked explicitly about this user
// return all disabled features even if its a managed profile.
which |= admin.disabledKeyguardFeatures;
@@ -5355,6 +5409,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
synchronized (this) {
enforceCanSetDeviceOwnerLocked(userId);
+ if (getActiveAdminUncheckedLocked(admin, userId) == null) {
+ throw new IllegalArgumentException("Not active admin: " + admin);
+ }
// Shutting down backup manager service permanently.
long ident = mInjector.binderClearCallingIdentity();
@@ -5489,6 +5546,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new SecurityException(
"clearDeviceOwner can only be called by the device owner");
}
+ enforceUserUnlocked(deviceOwnerUserId);
final ActiveAdmin admin = getDeviceOwnerAdminLocked();
if (admin != null) {
@@ -5529,6 +5587,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
synchronized (this) {
enforceCanSetProfileOwnerLocked(userHandle);
+
+ if (getActiveAdminUncheckedLocked(who, userHandle) == null) {
+ throw new IllegalArgumentException("Not active admin: " + who);
+ }
+
mOwners.setProfileOwner(who, ownerName, userHandle);
mOwners.writeProfileOwner(userHandle);
return true;
@@ -5543,6 +5606,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final UserHandle callingUser = mInjector.binderGetCallingUserHandle();
final int userId = callingUser.getIdentifier();
enforceNotManagedProfile(userId, "clear profile owner");
+ enforceUserUnlocked(userId);
// Check if this is the profile owner who is calling
final ActiveAdmin admin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5918,6 +5982,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private void enforceUserUnlocked(int userId) {
+ Preconditions.checkState(mUserManager.isUserUnlocked(userId),
+ "User must be running and unlocked");
+ }
+
private void enforceManageUsers() {
final int callingUid = mInjector.binderGetCallingUid();
if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) {
@@ -6093,9 +6162,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void 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)) {
+ throw new IllegalArgumentException("Package " + packageName + " is not installed "
+ + "on the current user");
+ }
DevicePolicyData policy = getUserData(userHandle);
policy.mApplicationRestrictionsManagingPackage = packageName;
saveSettingsLocked(userHandle);
@@ -6104,6 +6179,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@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);
@@ -6674,57 +6751,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- @Override
- public UserHandle createUser(ComponentName who, String name) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-
- long id = mInjector.binderClearCallingIdentity();
- try {
- UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */);
- if (userInfo != null) {
- return userInfo.getUserHandle();
- }
- return null;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
- }
- }
- }
-
- @Override
- public UserHandle createAndInitializeUser(ComponentName who, String name,
- String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
- UserHandle user = createUser(who, name);
- if (user == null) {
- return null;
- }
- long id = mInjector.binderClearCallingIdentity();
- try {
- String profileOwnerPkg = profileOwnerComponent.getPackageName();
-
- final int userHandle = user.getIdentifier();
- try {
- // Install the profile owner if not present.
- if (!mIPackageManager.isPackageAvailable(profileOwnerPkg, userHandle)) {
- mIPackageManager.installExistingPackageAsUser(profileOwnerPkg, userHandle);
- }
-
- // Start user in background.
- mInjector.getIActivityManager().startUserInBackground(userHandle);
- } catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
- }
-
- setActiveAdmin(profileOwnerComponent, true, userHandle, adminExtras);
- setProfileOwner(profileOwnerComponent, ownerName, userHandle);
- return user;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
- }
- }
-
private void sendAdminEnabledBroadcastLocked(int userHandle) {
DevicePolicyData policyData = getUserData(userHandle);
if (policyData.mAdminBroadcastPending) {
@@ -6750,6 +6776,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("profileOwner " + profileOwner + " and admin "
+ admin + " are not in the same package");
}
+ // Only allow the system user to use this method
+ if (!mInjector.binderGetCallingUserHandle().isSystem()) {
+ throw new SecurityException("createAndManageUser was called from non-system user");
+ }
+ if (!mInjector.userManagerIsSplitSystemUser()
+ && (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
+ throw new IllegalArgumentException(
+ "Ephemeral users are only supported on systems with a split system user.");
+ }
// Create user.
UserHandle user = null;
synchronized (this) {
@@ -6761,7 +6796,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if ((flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
userInfoFlags |= UserInfo.FLAG_EPHEMERAL;
}
- UserInfo userInfo = mUserManager.createUser(name, userInfoFlags);
+ UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
+ userInfoFlags);
if (userInfo != null) {
user = userInfo.getUserHandle();
}
@@ -6867,7 +6903,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean setPackageSuspended(ComponentName who, String packageName,
+ public String[] setPackagesSuspended(ComponentName who, String[] packageNames,
boolean suspended) {
Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
@@ -6876,15 +6912,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long id = mInjector.binderClearCallingIdentity();
try {
- return mIPackageManager.setPackageSuspendedAsUser(
- packageName, suspended, callingUserId);
+ return mIPackageManager.setPackagesSuspendedAsUser(
+ packageNames, suspended, callingUserId);
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
- return false;
+ return packageNames;
}
}
@@ -6897,10 +6933,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long id = mInjector.binderClearCallingIdentity();
try {
- ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(
- packageName, 0, callingUserId);
- return appInfo != null &&
- (appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+ return mIPackageManager.isPackageSuspendedForUser(packageName, callingUserId);
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
@@ -7091,7 +7124,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- 0, // no flags
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
parentUserId);
if (VERBOSE_LOG) {
@@ -7709,9 +7742,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (mUserSetupComplete.equals(uri)) {
updateUserSetupComplete();
} else if (mDeviceProvisioned.equals(uri)) {
- // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
- // is delayed until device is marked as provisioned.
- setDeviceOwnerSystemPropertyLocked();
+ synchronized (DevicePolicyManagerService.this) {
+ // Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
+ // is delayed until device is marked as provisioned.
+ setDeviceOwnerSystemPropertyLocked();
+ }
}
}
}
@@ -7990,7 +8025,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean isPackageInstalledForUser(String packageName, int userHandle) {
try {
- PackageInfo pi = mIPackageManager.getPackageInfo(packageName, 0, userHandle);
+ PackageInfo pi = mInjector.getIPackageManager().getPackageInfo(packageName, 0,
+ userHandle);
return (pi != null) && (pi.applicationInfo.flags != 0);
} catch (RemoteException re) {
throw new RuntimeException("Package manager has died", re);
@@ -8084,7 +8120,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean hasFeatureManagedUsers() {
try {
- return mIPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
+ return mIPackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0);
} catch (RemoteException e) {
return false;
}
@@ -8273,6 +8309,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public void setOrganizationColorForUser(int color, int userId) {
+ if (!mHasFeature) {
+ return;
+ }
+ enforceFullCrossUsersPermission(userId);
+ enforceManageUsers();
+ enforceManagedProfile(userId, "set organization color");
+ synchronized (this) {
+ ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
+ admin.organizationColor = color;
+ saveSettingsLocked(userId);
+ }
+ }
+
+ @Override
public int getOrganizationColor(@NonNull ComponentName who) {
if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
@@ -8392,7 +8443,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
- private void disableDeviceLoggingIfNotCompliant() {
+ private synchronized void disableDeviceLoggingIfNotCompliant() {
if (!isDeviceOwnerManagedSingleUserDevice()) {
mInjector.securityLogSetLoggingEnabledProperty(false);
Slog.w(LOG_TAG, "Device logging turned off as it's no longer a single user device.");
@@ -8405,6 +8456,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ensureDeviceOwnerManagingSingleUser(admin);
synchronized (this) {
+ if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
+ return;
+ }
mInjector.securityLogSetLoggingEnabledProperty(enabled);
if (enabled) {
mSecurityLogMonitor.start();
@@ -8446,4 +8500,139 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
}
+
+ private void enforceCanManageDeviceAdmin() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ null);
+ }
+
+ @Override
+ public boolean isUninstallInQueue(final String packageName) {
+ enforceCanManageDeviceAdmin();
+ final int userId = mInjector.userHandleGetCallingUserId();
+ Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ return mPackagesToRemove.contains(packageUserPair);
+ }
+ }
+
+ @Override
+ public void uninstallPackageWithActiveAdmins(final String packageName) {
+ enforceCanManageDeviceAdmin();
+ Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
+
+ final int userId = mInjector.userHandleGetCallingUserId();
+
+ enforceUserUnlocked(userId);
+
+ final ComponentName profileOwner = getProfileOwner(userId);
+ if (profileOwner != null && packageName.equals(profileOwner.getPackageName())) {
+ throw new IllegalArgumentException("Cannot uninstall a package with a profile owner");
+ }
+
+ final ComponentName deviceOwner = getDeviceOwnerComponent(/* callingUserOnly= */ false);
+ if (getDeviceOwnerUserId() == userId && deviceOwner != null
+ && packageName.equals(deviceOwner.getPackageName())) {
+ throw new IllegalArgumentException("Cannot uninstall a package with a device owner");
+ }
+
+ final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ mPackagesToRemove.add(packageUserPair);
+ }
+
+ // All active admins on the user.
+ final List<ComponentName> allActiveAdmins = getActiveAdmins(userId);
+
+ // Active admins in the target package.
+ final List<ComponentName> packageActiveAdmins = new ArrayList<>();
+ if (allActiveAdmins != null) {
+ for (ComponentName activeAdmin : allActiveAdmins) {
+ if (packageName.equals(activeAdmin.getPackageName())) {
+ packageActiveAdmins.add(activeAdmin);
+ removeActiveAdmin(activeAdmin, userId);
+ }
+ }
+ }
+ if (packageActiveAdmins.size() == 0) {
+ startUninstallIntent(packageName, userId);
+ } else {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ for (ComponentName activeAdmin : packageActiveAdmins) {
+ removeAdminArtifacts(activeAdmin, userId);
+ }
+ startUninstallIntent(packageName, userId);
+ }
+ }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway.
+ }
+ }
+
+ private void removePackageIfRequired(final String packageName, final int userId) {
+ if (!packageHasActiveAdmins(packageName, userId)) {
+ // Will not do anything if uninstall was not requested or was already started.
+ startUninstallIntent(packageName, userId);
+ }
+ }
+
+ private void startUninstallIntent(final String packageName, final int userId) {
+ final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ if (!mPackagesToRemove.contains(packageUserPair)) {
+ // Do nothing if uninstall was not requested or was already started.
+ return;
+ }
+ mPackagesToRemove.remove(packageUserPair);
+ }
+ try {
+ if (mInjector.getIPackageManager().getPackageInfo(packageName, 0, userId) == null) {
+ // Package does not exist. Nothing to do.
+ return;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Failure talking to PackageManager while getting package info");
+ }
+
+ try { // force stop the package before uninstalling
+ mInjector.getIActivityManager().forceStopPackage(packageName, userId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package");
+ }
+ final Uri packageURI = Uri.parse("package:" + packageName);
+ final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+ uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(uninstallIntent, UserHandle.of(userId));
+ }
+
+ /**
+ * Removes the admin from the policy. Ideally called after the admin's
+ * {@link DeviceAdminReceiver#onDisabled(Context, Intent)} has been successfully completed.
+ *
+ * @param adminReceiver The admin to remove
+ * @param userHandle The user for which this admin has to be removed.
+ */
+ private void removeAdminArtifacts(final ComponentName adminReceiver, final int userHandle) {
+ synchronized (this) {
+ final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
+ if (admin == null) {
+ return;
+ }
+ final DevicePolicyData policy = getUserData(userHandle);
+ final boolean doProxyCleanup = admin.info.usesPolicy(
+ DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
+ policy.mAdminList.remove(admin);
+ policy.mAdminMap.remove(adminReceiver);
+ validatePasswordOwnerLocked(policy);
+ if (doProxyCleanup) {
+ resetGlobalProxyLocked(policy);
+ }
+ saveSettingsLocked(userHandle);
+ updateMaximumTimeToLockLocked(userHandle);
+ policy.mRemovingAdmins.remove(adminReceiver);
+ }
+ // The removed admin might have disabled camera, so update user
+ // restrictions.
+ pushUserRestrictions(userHandle);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 880f810107a0..68fd0f681aa5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -716,11 +716,11 @@ class Owners {
}
File getLegacyConfigFileWithTestOverride() {
- return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML_LEGACY);
+ return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML_LEGACY);
}
File getDeviceOwnerFileWithTestOverride() {
- return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML);
+ return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML);
}
File getProfileOwnerFileWithTestOverride(int userId) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 3e1fbc7a9b37..117ba15cf65a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -16,6 +16,7 @@
package com.android.server.devicepolicy;
+import android.annotation.IntDef;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
@@ -24,13 +25,26 @@ import android.text.format.DateUtils;
import com.android.internal.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Utilities class for the remote bugreport operation.
*/
class RemoteBugreportUtils {
- static final int REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID = 678435657;
- static final int REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID = 590907895;
+ static final int NOTIFICATION_ID = 678432343;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ NOTIFICATION_BUGREPORT_STARTED,
+ NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+ NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+ })
+ @interface RemoteBugreportNotificationType {}
+ static final int NOTIFICATION_BUGREPORT_STARTED = 1;
+ static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
+ static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
@@ -47,65 +61,57 @@ class RemoteBugreportUtils {
static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
- static Notification buildRemoteBugreportConsentNotification(Context context) {
- PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(
- context, REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
- new Intent(ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(
- context, REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
- new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
- PendingIntent.FLAG_CANCEL_CURRENT);
-
- return new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setContentTitle(context.getString(
- R.string.share_remote_bugreport_notification_title))
- .setTicker(context.getString(R.string.share_remote_bugreport_notification_title))
- .setContentText(context.getString(
- R.string.share_remote_bugreport_notification_message))
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.share_remote_bugreport_notification_message)))
- .addAction(new Notification.Action.Builder(null /* icon */,
- context.getString(R.string.share_remote_bugreport_notification_decline),
- pendingIntentDecline).build())
- .addAction(new Notification.Action.Builder(null /* icon */,
- context.getString(R.string.share_remote_bugreport_notification_accept),
- pendingIntentAccept).build())
- .setOngoing(true)
- .setLocalOnly(true)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setPriority(Notification.PRIORITY_MAX)
- .setVibrate(new long[0])
- .build();
- }
-
- static Notification buildRemoteBugreportInProgressNotification(Context context,
- boolean canCancelBugreport) {
+ static Notification buildNotification(Context context,
+ @RemoteBugreportNotificationType int type) {
Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setContentTitle(context.getString(
- R.string.remote_bugreport_progress_notification_title))
- .setTicker(context.getString(
- R.string.remote_bugreport_progress_notification_title))
.setOngoing(true)
.setLocalOnly(true)
.setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setPriority(Notification.PRIORITY_HIGH);
+ com.android.internal.R.color.system_notification_accent_color));
- if (canCancelBugreport) {
- PendingIntent pendingIntentCancel = PendingIntent.getBroadcast(context,
- REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID,
- new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
+ if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+ builder.setContentTitle(context.getString(
+ R.string.sharing_remote_bugreport_notification_title))
+ .setContentText(context.getString(
+ R.string.sharing_remote_bugreport_notification_message))
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setProgress(0, 0, true)
+ .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+ R.string.sharing_remote_bugreport_notification_message)));
+ } else {
+ PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
+ new Intent(ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID, new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
PendingIntent.FLAG_CANCEL_CURRENT);
- String message = context.getString(
- R.string.remote_bugreport_progress_notification_message_can_cancel);
- builder.setContentText(message)
- .setContentIntent(pendingIntentCancel)
- .setStyle(new Notification.BigTextStyle().bigText(message));
+ builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
+ R.string.share_remote_bugreport_notification_decline),
+ pendingIntentDecline).build())
+ .addAction(new Notification.Action.Builder(null /* icon */, context.getString(
+ R.string.share_remote_bugreport_notification_accept),
+ pendingIntentAccept).build())
+ .setContentTitle(context.getString(
+ R.string.share_remote_bugreport_notification_title));
+
+ if (type == NOTIFICATION_BUGREPORT_STARTED) {
+ builder.setContentText(context.getString(
+ R.string.share_remote_bugreport_notification_message))
+ .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+ R.string.share_remote_bugreport_notification_message)))
+ .setProgress(0, 0, true)
+ .setPriority(Notification.PRIORITY_MAX)
+ .setVibrate(new long[0]);
+ } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
+ builder.setContentText(context.getString(
+ R.string.share_finished_remote_bugreport_notification_message))
+ .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+ R.string.share_finished_remote_bugreport_notification_message)))
+ .setPriority(Notification.PRIORITY_HIGH);
+ }
}
+
return builder.build();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index f2d6180d34a3..cacc671df393 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -28,6 +28,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import android.os.Process;
@@ -42,6 +44,8 @@ import android.os.Process;
class SecurityLogMonitor implements Runnable {
private final DevicePolicyManagerService mService;
+ private final Lock mLock = new ReentrantLock();
+
SecurityLogMonitor(DevicePolicyManagerService service) {
mService = service;
}
@@ -68,36 +72,50 @@ class SecurityLogMonitor implements Runnable {
*/
private static final long POLLING_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(1);
- @GuardedBy("this")
+ @GuardedBy("mLock")
private Thread mMonitorThread = null;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private ArrayList<SecurityEvent> mPendingLogs = new ArrayList<SecurityEvent>();
- @GuardedBy("this")
+ @GuardedBy("mLock")
private boolean mAllowedToRetrieve = false;
// When DO will be allowed to retrieves the log, in milliseconds.
- @GuardedBy("this")
+ @GuardedBy("mLock")
private long mNextAllowedRetrivalTimeMillis = -1;
- synchronized void start() {
- if (mMonitorThread == null) {
- mPendingLogs = new ArrayList<SecurityEvent>();
- mAllowedToRetrieve = false;
- mNextAllowedRetrivalTimeMillis = -1;
+ void start() {
+ mLock.lock();
+ try {
+ if (mMonitorThread == null) {
+ mPendingLogs = new ArrayList<SecurityEvent>();
+ mAllowedToRetrieve = false;
+ mNextAllowedRetrivalTimeMillis = -1;
- mMonitorThread = new Thread(this);
- mMonitorThread.start();
+ mMonitorThread = new Thread(this);
+ mMonitorThread.start();
+ }
+ } finally {
+ mLock.unlock();
}
}
- synchronized void stop() {
- if (mMonitorThread != null) {
- mMonitorThread.interrupt();
- try {
- mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+ void stop() {
+ mLock.lock();
+ try {
+ if (mMonitorThread != null) {
+ mMonitorThread.interrupt();
+ try {
+ mMonitorThread.join(TimeUnit.SECONDS.toMillis(5));
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for thread to stop", e);
+ }
+ // Reset state and clear buffer
+ mPendingLogs = new ArrayList<SecurityEvent>();
+ mAllowedToRetrieve = false;
+ mNextAllowedRetrivalTimeMillis = -1;
+ mMonitorThread = null;
}
- mMonitorThread = null;
+ } finally {
+ mLock.unlock();
}
}
@@ -105,16 +123,21 @@ class SecurityLogMonitor implements Runnable {
* Returns the new batch of logs since the last call to this method. Returns null if
* rate limit is exceeded.
*/
- synchronized List<SecurityEvent> retrieveLogs() {
- if (mAllowedToRetrieve) {
- mAllowedToRetrieve = false;
- mNextAllowedRetrivalTimeMillis = System.currentTimeMillis()
- + RATE_LIMIT_INTERVAL_MILLISECONDS;
- List<SecurityEvent> result = mPendingLogs;
- mPendingLogs = new ArrayList<SecurityEvent>();
- return result;
- } else {
- return null;
+ List<SecurityEvent> retrieveLogs() {
+ mLock.lock();
+ try {
+ if (mAllowedToRetrieve) {
+ mAllowedToRetrieve = false;
+ mNextAllowedRetrivalTimeMillis = System.currentTimeMillis()
+ + RATE_LIMIT_INTERVAL_MILLISECONDS;
+ List<SecurityEvent> result = mPendingLogs;
+ mPendingLogs = new ArrayList<SecurityEvent>();
+ return result;
+ } else {
+ return null;
+ }
+ } finally {
+ mLock.unlock();
}
}
@@ -141,7 +164,8 @@ class SecurityLogMonitor implements Runnable {
}
if (!logs.isEmpty()) {
if (DEBUG) Slog.d(TAG, "processing new logs");
- synchronized (this) {
+ mLock.lockInterruptibly();
+ try {
mPendingLogs.addAll(logs);
if (mPendingLogs.size() > BUFFER_ENTRIES_MAXIMUM_LEVEL) {
// Truncate buffer down to half of BUFFER_ENTRIES_MAXIMUM_LEVEL
@@ -149,6 +173,8 @@ class SecurityLogMonitor implements Runnable {
mPendingLogs.size() - (BUFFER_ENTRIES_MAXIMUM_LEVEL / 2),
mPendingLogs.size()));
}
+ } finally {
+ mLock.unlock();
}
lastLogTimestampNanos = logs.get(logs.size() - 1).getTimeNanos();
logs.clear();
@@ -163,18 +189,13 @@ class SecurityLogMonitor implements Runnable {
}
}
if (DEBUG) Slog.d(TAG, "MonitorThread exit.");
- synchronized (this) {
- // Reset state and clear buffer
- mPendingLogs = new ArrayList<SecurityEvent>();
- mAllowedToRetrieve = false;
- mNextAllowedRetrivalTimeMillis = -1;
- }
}
- private void notifyDeviceOwnerIfNeeded() {
+ private void notifyDeviceOwnerIfNeeded() throws InterruptedException {
boolean shouldNotifyDO = false;
boolean allowToRetrieveNow = false;
- synchronized (this) {
+ mLock.lockInterruptibly();
+ try {
int logSize = mPendingLogs.size();
if (logSize >= BUFFER_ENTRIES_NOTIFICATION_LEVEL) {
// Allow DO to retrieve logs if too many pending logs
@@ -188,6 +209,8 @@ class SecurityLogMonitor implements Runnable {
}
shouldNotifyDO = (!mAllowedToRetrieve) && allowToRetrieveNow;
mAllowedToRetrieve = allowToRetrieveNow;
+ } finally {
+ mLock.unlock();
}
if (shouldNotifyDO) {
if (DEBUG) Slog.d(TAG, "notify DO");
@@ -195,4 +218,4 @@ class SecurityLogMonitor implements Runnable {
null);
}
}
-} \ No newline at end of file
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0cf93288714f..0ece6aafc742 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -59,6 +59,7 @@ import com.android.server.am.ActivityManagerService;
import com.android.server.audio.AudioService;
import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
+import com.android.server.connectivity.MetricsLoggerService;
import com.android.server.content.ContentService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
@@ -341,8 +342,8 @@ public final class SystemServer {
// always make sure uncrypt gets executed properly when needed.
// If '/cache/recovery/block.map' hasn't been created, stop the
// reboot which will fail for sure, and get a chance to capture a
- // bugreport when that's still feasible. (Bug; 26444951)
- if (PowerManager.REBOOT_RECOVERY.equals(reason)) {
+ // bugreport when that's still feasible. (Bug: 26444951)
+ if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
File packageFile = new File(UNCRYPT_PACKAGE_FILE);
if (packageFile.exists()) {
String filename = null;
@@ -488,6 +489,7 @@ public final class SystemServer {
MmsServiceBroker mmsService = null;
EntropyMixer entropyMixer = null;
VrManagerService vrManagerService = null;
+ HardwarePropertiesManagerService hardwarePropertiesService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -601,6 +603,10 @@ public final class SystemServer {
} else {
mSystemServiceManager.startService(BluetoothService.class);
}
+
+ traceBeginAndSlog("ConnectivityMetricsLoggerService");
+ mSystemServiceManager.startService(MetricsLoggerService.class);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
@@ -760,7 +766,7 @@ public final class SystemServer {
traceBeginAndSlog("StartNetworkStatsService");
try {
- networkStats = new NetworkStatsService(context, networkManagement, alarm);
+ networkStats = NetworkStatsService.create(context, networkManagement);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
} catch (Throwable e) {
reportWtf("starting NetworkStats Service", e);
@@ -832,6 +838,10 @@ public final class SystemServer {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
+ if (!disableNonCoreServices) {
+ mSystemServiceManager.startService(RecoverySystemService.class);
+ }
+
/*
* MountService has a few dependencies: Notification Manager and
* AppWidget Provider. Make sure MountService is completely started
@@ -962,6 +972,17 @@ public final class SystemServer {
Slog.e(TAG, "Failure starting SerialService", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+ "StartHardwarePropertiesManagerService");
+ try {
+ hardwarePropertiesService = new HardwarePropertiesManagerService(context);
+ ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
+ hardwarePropertiesService);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
mSystemServiceManager.startService(TwilightService.class);
@@ -1258,10 +1279,12 @@ public final class SystemServer {
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Slog.i(TAG, "WebViewFactory preparation");
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
- mWebViewUpdateService.prepareWebViewInSystemServer();
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ if (!mOnlyCore) {
+ Slog.i(TAG, "WebViewFactory preparation");
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
+ mWebViewUpdateService.prepareWebViewInSystemServer();
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
try {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 2329b4251fc7..4f99bffe245b 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -19,6 +19,7 @@ package android.net.dhcp;
import com.android.internal.util.HexDump;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
+import com.android.internal.util.MessageUtils;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
@@ -26,15 +27,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.DhcpResults;
-import android.net.BaseDhcpStateMachine;
-import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message;
-import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -42,16 +40,15 @@ import android.system.ErrnoException;
import android.system.Os;
import android.system.PacketSocketAddress;
import android.util.Log;
+import android.util.SparseArray;
import android.util.TimeUtils;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.Thread;
import java.net.Inet4Address;
-import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
-import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
@@ -84,7 +81,7 @@ import static android.net.dhcp.DhcpPacket.*;
*
* @hide
*/
-public class DhcpClient extends BaseDhcpStateMachine {
+public class DhcpClient extends StateMachine {
private static final String TAG = "DhcpClient";
private static final boolean DBG = true;
@@ -103,12 +100,40 @@ public class DhcpClient extends BaseDhcpStateMachine {
// t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
private static final int DHCP_TIMEOUT_MS = 36 * SECONDS;
+ private static final int PUBLIC_BASE = Protocol.BASE_DHCP;
+
+ /* Commands from controller to start/stop DHCP */
+ public static final int CMD_START_DHCP = PUBLIC_BASE + 1;
+ public static final int CMD_STOP_DHCP = PUBLIC_BASE + 2;
+ public static final int CMD_RENEW_DHCP = PUBLIC_BASE + 3;
+
+ /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+ public static final int CMD_PRE_DHCP_ACTION = PUBLIC_BASE + 4;
+ /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+ * success/failure */
+ public static final int CMD_POST_DHCP_ACTION = PUBLIC_BASE + 5;
+ /* Notification from DHCP state machine before quitting */
+ public static final int CMD_ON_QUIT = PUBLIC_BASE + 6;
+
+ /* Command from controller to indicate DHCP discovery/renewal can continue
+ * after pre DHCP action is complete */
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = PUBLIC_BASE + 7;
+
+ /* Message.arg1 arguments to CMD_POST_DHCP notification */
+ public static final int DHCP_SUCCESS = 1;
+ public static final int DHCP_FAILURE = 2;
+
// Messages.
- private static final int BASE = Protocol.BASE_DHCP + 100;
- private static final int CMD_KICK = BASE + 1;
- private static final int CMD_RECEIVED_PACKET = BASE + 2;
- private static final int CMD_TIMEOUT = BASE + 3;
- private static final int CMD_ONESHOT_TIMEOUT = BASE + 4;
+ private static final int PRIVATE_BASE = Protocol.BASE_DHCP + 100;
+ private static final int CMD_KICK = PRIVATE_BASE + 1;
+ private static final int CMD_RECEIVED_PACKET = PRIVATE_BASE + 2;
+ private static final int CMD_TIMEOUT = PRIVATE_BASE + 3;
+ private static final int CMD_ONESHOT_TIMEOUT = PRIVATE_BASE + 4;
+
+ // For message logging.
+ private static final Class[] sMessageClasses = { DhcpClient.class };
+ private static final SparseArray<String> sMessageNames =
+ MessageUtils.findMessageNames(sMessageClasses);
// DHCP parameters that we request.
private static final byte[] REQUESTED_PARAMS = new byte[] {
@@ -211,19 +236,18 @@ public class DhcpClient extends BaseDhcpStateMachine {
// Used to time out PacketRetransmittingStates.
mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
// Used to schedule DHCP renews.
- mRenewAlarm = makeWakeupMessage("RENEW", DhcpStateMachine.CMD_RENEW_DHCP);
+ mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
// Used to tell the caller when its request (CMD_START_DHCP or CMD_RENEW_DHCP) timed out.
// TODO: when the legacy DHCP client is gone, make the client fully asynchronous and
// remove this.
mOneshotTimeoutAlarm = makeWakeupMessage("ONESHOT_TIMEOUT", CMD_ONESHOT_TIMEOUT);
}
- @Override
public void registerForPreDhcpNotification() {
mRegisteredForPreDhcpNotification = true;
}
- public static BaseDhcpStateMachine makeDhcpStateMachine(
+ public static DhcpClient makeDhcpClient(
Context context, StateMachine controller, String intf) {
DhcpClient client = new DhcpClient(context, controller, intf);
client.start();
@@ -400,13 +424,12 @@ public class DhcpClient extends BaseDhcpStateMachine {
}
private void notifySuccess() {
- mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
- DhcpStateMachine.DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
+ mController.sendMessage(
+ CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
}
private void notifyFailure() {
- mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
- DhcpStateMachine.DHCP_FAILURE, 0, null);
+ mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
}
private void clearDhcpState() {
@@ -420,15 +443,15 @@ public class DhcpClient extends BaseDhcpStateMachine {
*
* @hide
*/
- @Override
public void doQuit() {
Log.d(TAG, "doQuit");
quit();
}
+ @Override
protected void onQuitting() {
Log.d(TAG, "onQuitting");
- mController.sendMessage(DhcpStateMachine.CMD_ON_QUIT);
+ mController.sendMessage(CMD_ON_QUIT);
}
private void maybeLog(String msg) {
@@ -441,30 +464,7 @@ public class DhcpClient extends BaseDhcpStateMachine {
}
private String messageName(int what) {
- switch (what) {
- case DhcpStateMachine.CMD_START_DHCP:
- return "CMD_START_DHCP";
- case DhcpStateMachine.CMD_STOP_DHCP:
- return "CMD_STOP_DHCP";
- case DhcpStateMachine.CMD_RENEW_DHCP:
- return "CMD_RENEW_DHCP";
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
- return "CMD_PRE_DHCP_ACTION";
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
- return "CMD_PRE_DHCP_ACTION_COMPLETE";
- case DhcpStateMachine.CMD_POST_DHCP_ACTION:
- return "CMD_POST_DHCP_ACTION";
- case CMD_KICK:
- return "CMD_KICK";
- case CMD_RECEIVED_PACKET:
- return "CMD_RECEIVED_PACKET";
- case CMD_TIMEOUT:
- return "CMD_TIMEOUT";
- case CMD_ONESHOT_TIMEOUT:
- return "CMD_ONESHOT_TIMEOUT";
- default:
- return Integer.toString(what);
- }
+ return sMessageNames.get(what, Integer.toString(what));
}
private String messageToString(Message message) {
@@ -495,14 +495,14 @@ public class DhcpClient extends BaseDhcpStateMachine {
@Override
public void enter() {
super.enter();
- mController.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION);
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
}
@Override
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
transitionTo(mOtherState);
return HANDLED;
default:
@@ -532,7 +532,7 @@ public class DhcpClient extends BaseDhcpStateMachine {
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_START_DHCP:
+ case CMD_START_DHCP:
scheduleOneshotTimeout();
if (mRegisteredForPreDhcpNotification) {
transitionTo(mWaitBeforeStartState);
@@ -588,7 +588,7 @@ public class DhcpClient extends BaseDhcpStateMachine {
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_STOP_DHCP:
+ case CMD_STOP_DHCP:
transitionTo(mStoppedState);
return HANDLED;
case CMD_ONESHOT_TIMEOUT:
@@ -801,7 +801,7 @@ public class DhcpClient extends BaseDhcpStateMachine {
super.enter();
mOneshotTimeoutAlarm.cancel();
notifySuccess();
- // TODO: DhcpStateMachine only supports renewing at 50% of the lease time, and does not
+ // TODO: DhcpStateMachine only supported renewing at 50% of the lease time, and did not
// support rebinding. Once the legacy DHCP client is gone, fix this.
scheduleRenew();
}
@@ -810,7 +810,7 @@ public class DhcpClient extends BaseDhcpStateMachine {
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case DhcpStateMachine.CMD_RENEW_DHCP:
+ case CMD_RENEW_DHCP:
if (mRegisteredForPreDhcpNotification) {
transitionTo(mWaitBeforeRenewalState);
} else {
@@ -869,7 +869,7 @@ public class DhcpClient extends BaseDhcpStateMachine {
}
}
- // Not implemented. DhcpStateMachine does not implement it either.
+ // Not implemented. DhcpStateMachine did not implement it either.
class DhcpRebindingState extends LoggingState {
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 06b6ee75da7a..2a90c60656ab 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -16,14 +16,15 @@
package android.net.ip;
+import com.android.internal.util.MessageUtils;
+
import android.content.Context;
-import android.net.BaseDhcpStateMachine;
import android.net.DhcpResults;
-import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
+import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
@@ -31,8 +32,9 @@ import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -61,44 +63,37 @@ import java.util.Objects;
* @hide
*/
public class IpManager extends StateMachine {
- private static final String TAG = IpManager.class.getSimpleName();
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ private static final boolean NO_CALLBACKS = false;
+ private static final boolean SEND_CALLBACKS = true;
+
+ // For message logging.
+ private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
+ private static final SparseArray<String> sWhatToString =
+ MessageUtils.findMessageNames(sMessageClasses);
+
/**
- * Callbacks for both configuration of IpManager and for handling
- * events as desired.
+ * Callbacks for handling IpManager events.
*/
public static class Callback {
- /**
- * Configuration callbacks.
- *
- * Override methods as desired in order to control which features
- * IpManager will use at run time.
- */
-
- // An IpReachabilityMonitor will always be started, if only for logging.
- // This method is checked before probing neighbors and before calling
- // onProvisioningLost() (see below).
- public boolean usingIpReachabilityMonitor() {
- return false;
- }
-
- /**
- * Event callbacks.
- *
- * Override methods as desired in order to handle event callbacks
- * as IpManager invokes them.
- */
-
- // Implementations must call IpManager#completedPreDhcpAction().
+ // In order to receive onPreDhcpAction(), call #withPreDhcpAction()
+ // when constructing a ProvisioningConfiguration.
+ //
+ // Implementations of onPreDhcpAction() must call
+ // IpManager#completedPreDhcpAction() to indicate that DHCP is clear
+ // to proceed.
public void onPreDhcpAction() {}
public void onPostDhcpAction() {}
- // TODO: Kill with fire once DHCP and static configuration are moved
- // out of WifiStateMachine.
- public void onIPv4ProvisioningSuccess(DhcpResults dhcpResults) {}
- public void onIPv4ProvisioningFailure() {}
+ // This is purely advisory and not an indication of provisioning
+ // success or failure. This is only here for callers that want to
+ // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+ // DHCPv4 or static IPv4 configuration failure or success can be
+ // determined by whether or not the passed-in DhcpResults object is
+ // null or not.
+ public void onNewDhcpResults(DhcpResults dhcpResults) {}
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
@@ -109,6 +104,96 @@ public class IpManager extends StateMachine {
// Called when the internal IpReachabilityMonitor (if enabled) has
// detected the loss of a critical number of required neighbors.
public void onReachabilityLost(String logMsg) {}
+
+ // Called when the IpManager state machine terminates.
+ public void onQuit() {}
+ }
+
+ public static class WaitForProvisioningCallback extends Callback {
+ private LinkProperties mCallbackLinkProperties;
+
+ public LinkProperties waitForProvisioning() {
+ synchronized (this) {
+ try {
+ wait();
+ } catch (InterruptedException e) {}
+ return mCallbackLinkProperties;
+ }
+ }
+
+ @Override
+ public void onProvisioningSuccess(LinkProperties newLp) {
+ synchronized (this) {
+ mCallbackLinkProperties = newLp;
+ notify();
+ }
+ }
+
+ @Override
+ public void onProvisioningFailure(LinkProperties newLp) {
+ synchronized (this) {
+ mCallbackLinkProperties = null;
+ notify();
+ }
+ }
+ }
+
+ /**
+ * This class encapsulates parameters to be passed to
+ * IpManager#startProvisioning(). A defensive copy is made by IpManager
+ * and the values specified herein are in force until IpManager#stop()
+ * is called.
+ *
+ * Example use:
+ *
+ * final ProvisioningConfiguration config =
+ * mIpManager.buildProvisioningConfiguration()
+ * .withPreDhcpAction()
+ * .build();
+ * mIpManager.startProvisioning(config);
+ * ...
+ * mIpManager.stop();
+ *
+ * The specified provisioning configuration will only be active until
+ * IpManager#stop() is called. Future calls to IpManager#startProvisioning()
+ * must specify the configuration again.
+ */
+ public static class ProvisioningConfiguration {
+
+ public static class Builder {
+ private ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
+
+ public Builder withoutIpReachabilityMonitor() {
+ mConfig.mUsingIpReachabilityMonitor = false;
+ return this;
+ }
+
+ public Builder withPreDhcpAction() {
+ mConfig.mRequestedPreDhcpAction = true;
+ return this;
+ }
+
+ public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+ mConfig.mStaticIpConfig = staticConfig;
+ return this;
+ }
+
+ public ProvisioningConfiguration build() {
+ return new ProvisioningConfiguration(mConfig);
+ }
+ }
+
+ /* package */ boolean mUsingIpReachabilityMonitor = true;
+ /* package */ boolean mRequestedPreDhcpAction;
+ /* package */ StaticIpConfiguration mStaticIpConfig;
+
+ public ProvisioningConfiguration() {}
+
+ public ProvisioningConfiguration(ProvisioningConfiguration other) {
+ mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
+ mRequestedPreDhcpAction = other.mRequestedPreDhcpAction;
+ mStaticIpConfig = other.mStaticIpConfig;
+ }
}
private static final int CMD_STOP = 1;
@@ -117,13 +202,17 @@ public class IpManager extends StateMachine {
private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 4;
// Sent by NetlinkTracker to communicate netlink events.
private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
+ private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
+ private static final int CMD_UPDATE_HTTP_PROXY = 7;
private static final int MAX_LOG_RECORDS = 1000;
private final Object mLock = new Object();
private final State mStoppedState = new StoppedState();
+ private final State mStoppingState = new StoppingState();
private final State mStartedState = new StartedState();
+ private final String mTag;
private final Context mContext;
private final String mInterfaceName;
@VisibleForTesting
@@ -136,10 +225,12 @@ public class IpManager extends StateMachine {
/**
* Non-final member variables accessed only from within our StateMachine.
*/
+ private ProvisioningConfiguration mConfiguration;
private IpReachabilityMonitor mIpReachabilityMonitor;
- private BaseDhcpStateMachine mDhcpStateMachine;
+ private DhcpClient mDhcpClient;
private DhcpResults mDhcpResults;
- private StaticIpConfiguration mStaticIpConfig;
+ private String mTcpBufferSizes;
+ private ProxyInfo mHttpProxy;
/**
* Member variables accessed both from within the StateMachine thread
@@ -150,11 +241,11 @@ public class IpManager extends StateMachine {
public IpManager(Context context, String ifName, Callback callback)
throws IllegalArgumentException {
- super(TAG + "." + ifName);
+ super(IpManager.class.getSimpleName() + "." + ifName);
+ mTag = getName();
mContext = context;
mInterfaceName = ifName;
-
mCallback = callback;
mNwService = INetworkManagementService.Stub.asInterface(
@@ -171,7 +262,7 @@ public class IpManager extends StateMachine {
try {
mNwService.registerObserver(mNetlinkTracker);
} catch (RemoteException e) {
- Log.e(TAG, "Couldn't register NetlinkTracker: " + e.toString());
+ Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
resetLinkProperties();
@@ -179,6 +270,8 @@ public class IpManager extends StateMachine {
// Super simple StateMachine.
addState(mStoppedState);
addState(mStartedState);
+ addState(mStoppingState);
+
setInitialState(mStoppedState);
setLogRecSize(MAX_LOG_RECORDS);
super.start();
@@ -192,7 +285,9 @@ public class IpManager extends StateMachine {
*/
@VisibleForTesting
protected IpManager(String ifName, Callback callback) {
- super(TAG + ".test-" + ifName);
+ super(IpManager.class.getSimpleName() + ".test-" + ifName);
+ mTag = getName();
+
mInterfaceName = ifName;
mCallback = callback;
@@ -201,16 +296,35 @@ public class IpManager extends StateMachine {
mNetlinkTracker = null;
}
- public void startProvisioning(StaticIpConfiguration staticIpConfig) {
- getInterfaceIndex();
+ @Override
+ protected void onQuitting() {
+ mCallback.onQuit();
+ }
- sendMessage(CMD_START, staticIpConfig);
+ // Shut down this IpManager instance altogether.
+ public void shutdown() {
+ stop();
+ quit();
}
- public void startProvisioning() {
+ public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
+ return new ProvisioningConfiguration.Builder();
+ }
+
+ public void startProvisioning(ProvisioningConfiguration req) {
getInterfaceIndex();
+ sendMessage(CMD_START, new ProvisioningConfiguration(req));
+ }
- sendMessage(CMD_START);
+ // TODO: Delete this.
+ public void startProvisioning(StaticIpConfiguration staticIpConfig) {
+ startProvisioning(buildProvisioningConfiguration()
+ .withStaticConfiguration(staticIpConfig)
+ .build());
+ }
+
+ public void startProvisioning() {
+ startProvisioning(new ProvisioningConfiguration());
}
public void stop() {
@@ -225,6 +339,26 @@ public class IpManager extends StateMachine {
sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
}
+ /**
+ * Set the TCP buffer sizes to use.
+ *
+ * This may be called, repeatedly, at any time before or after a call to
+ * #startProvisioning(). The setting is cleared upon calling #stop().
+ */
+ public void setTcpBufferSizes(String tcpBufferSizes) {
+ sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
+ }
+
+ /**
+ * Set the HTTP Proxy configuration to use.
+ *
+ * This may be called, repeatedly, at any time before or after a call to
+ * #startProvisioning(). The setting is cleared upon calling #stop().
+ */
+ public void setHttpProxy(ProxyInfo proxyInfo) {
+ sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
+ }
+
public LinkProperties getLinkProperties() {
synchronized (mLock) {
return new LinkProperties(mLinkProperties);
@@ -236,12 +370,29 @@ public class IpManager extends StateMachine {
* Internals.
*/
+ @Override
+ protected String getWhatToString(int what) {
+ return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
+ }
+
+ @Override
+ protected String getLogRecString(Message msg) {
+ final String logLine = String.format(
+ "iface{%s/%d} arg1{%d} arg2{%d} obj{%s}",
+ mInterfaceName, mInterfaceIndex,
+ msg.arg1, msg.arg2, Objects.toString(msg.obj));
+ if (VDBG) {
+ Log.d(mTag, getWhatToString(msg.what) + " " + logLine);
+ }
+ return logLine;
+ }
+
private void getInterfaceIndex() {
try {
mInterfaceIndex = NetworkInterface.getByName(mInterfaceName).getIndex();
} catch (SocketException | NullPointerException e) {
// TODO: throw new IllegalStateException.
- Log.e(TAG, "ALERT: Failed to get interface index: ", e);
+ Log.e(mTag, "ALERT: Failed to get interface index: ", e);
}
}
@@ -251,8 +402,10 @@ public class IpManager extends StateMachine {
// assigned to the interface, etc.
private void resetLinkProperties() {
mNetlinkTracker.clearLinkProperties();
+ mConfiguration = null;
mDhcpResults = null;
- mStaticIpConfig = null;
+ mTcpBufferSizes = "";
+ mHttpProxy = null;
synchronized (mLock) {
mLinkProperties = new LinkProperties();
@@ -260,16 +413,93 @@ public class IpManager extends StateMachine {
}
}
+ // For now: use WifiStateMachine's historical notion of provisioned.
+ private static boolean isProvisioned(LinkProperties lp) {
+ // For historical reasons, we should connect even if all we have is
+ // an IPv4 address and nothing else.
+ return lp.isProvisioned() || lp.hasIPv4Address();
+ }
+
+ // TODO: Investigate folding all this into the existing static function
+ // LinkProperties.compareProvisioning() or some other single function that
+ // takes two LinkProperties objects and returns a ProvisioningChange
+ // object that is a correct and complete assessment of what changed, taking
+ // account of the asymmetries described in the comments in this function.
+ // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+ private static ProvisioningChange compareProvisioning(
+ LinkProperties oldLp, LinkProperties newLp) {
+ ProvisioningChange delta;
+
+ final boolean wasProvisioned = isProvisioned(oldLp);
+ final boolean isProvisioned = isProvisioned(newLp);
+
+ if (!wasProvisioned && isProvisioned) {
+ delta = ProvisioningChange.GAINED_PROVISIONING;
+ } else if (wasProvisioned && isProvisioned) {
+ delta = ProvisioningChange.STILL_PROVISIONED;
+ } else if (!wasProvisioned && !isProvisioned) {
+ delta = ProvisioningChange.STILL_NOT_PROVISIONED;
+ } else {
+ // (wasProvisioned && !isProvisioned)
+ //
+ // Note that this is true even if we lose a configuration element
+ // (e.g., a default gateway) that would not be required to advance
+ // into provisioned state. This is intended: if we have a default
+ // router and we lose it, that's a sure sign of a problem, but if
+ // we connect to a network with no IPv4 DNS servers, we consider
+ // that to be a network without DNS servers and connect anyway.
+ //
+ // See the comment below.
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ // Additionally:
+ //
+ // Partial configurations (e.g., only an IPv4 address with no DNS
+ // servers and no default route) are accepted as long as DHCPv4
+ // succeeds. On such a network, isProvisioned() will always return
+ // false, because the configuration is not complete, but we want to
+ // connect anyway. It might be a disconnected network such as a
+ // Chromecast or a wireless printer, for example.
+ //
+ // Because on such a network isProvisioned() will always return false,
+ // delta will never be LOST_PROVISIONING. So check for loss of
+ // provisioning here too.
+ if ((oldLp.hasIPv4Address() && !newLp.hasIPv4Address()) ||
+ (oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned())) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ return delta;
+ }
+
+ private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+ switch (delta) {
+ case GAINED_PROVISIONING:
+ if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+ mCallback.onProvisioningSuccess(newLp);
+ break;
+
+ case LOST_PROVISIONING:
+ if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ mCallback.onProvisioningFailure(newLp);
+ break;
+
+ default:
+ if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
+ mCallback.onLinkPropertiesChange(newLp);
+ break;
+ }
+ }
+
private ProvisioningChange setLinkProperties(LinkProperties newLp) {
if (mIpReachabilityMonitor != null) {
mIpReachabilityMonitor.updateLinkProperties(newLp);
}
- // TODO: Figure out whether and how to incorporate static configuration
- // into the notion of provisioning.
ProvisioningChange delta;
synchronized (mLock) {
- delta = LinkProperties.compareProvisioning(mLinkProperties, newLp);
+ delta = compareProvisioning(mLinkProperties, newLp);
mLinkProperties = new LinkProperties(newLp);
}
@@ -277,7 +507,7 @@ public class IpManager extends StateMachine {
switch (delta) {
case GAINED_PROVISIONING:
case LOST_PROVISIONING:
- Log.d(TAG, "provisioning: " + delta);
+ Log.d(mTag, "provisioning: " + delta);
break;
}
}
@@ -332,34 +562,84 @@ public class IpManager extends StateMachine {
newLp.setDomains(mDhcpResults.domains);
}
- if (VDBG) {
- Log.d(TAG, "newLp{" + newLp + "}");
+ // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
+ if (!TextUtils.isEmpty(mTcpBufferSizes)) {
+ newLp.setTcpBufferSizes(mTcpBufferSizes);
+ }
+ if (mHttpProxy != null) {
+ newLp.setHttpProxy(mHttpProxy);
}
+ if (VDBG) {
+ Log.d(mTag, "newLp{" + newLp + "}");
+ }
return newLp;
}
+ // Returns false if we have lost provisioning, true otherwise.
+ private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
+ final LinkProperties newLp = assembleLinkProperties();
+ if (linkPropertiesUnchanged(newLp)) {
+ return true;
+ }
+ final ProvisioningChange delta = setLinkProperties(newLp);
+ if (sendCallbacks) {
+ dispatchCallback(delta, newLp);
+ }
+ return (delta != ProvisioningChange.LOST_PROVISIONING);
+ }
+
private void clearIPv4Address() {
try {
final InterfaceConfiguration ifcg = new InterfaceConfiguration();
ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
} catch (RemoteException e) {
- Log.e(TAG, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
+ Log.e(mTag, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
}
}
private void handleIPv4Success(DhcpResults dhcpResults) {
mDhcpResults = new DhcpResults(dhcpResults);
- setLinkProperties(assembleLinkProperties());
- mCallback.onIPv4ProvisioningSuccess(dhcpResults);
+ final LinkProperties newLp = assembleLinkProperties();
+ final ProvisioningChange delta = setLinkProperties(newLp);
+
+ if (VDBG) {
+ Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+ }
+ mCallback.onNewDhcpResults(dhcpResults);
+
+ dispatchCallback(delta, newLp);
}
private void handleIPv4Failure() {
+ // TODO: Figure out to de-dup this and the same code in DhcpClient.
clearIPv4Address();
mDhcpResults = null;
- setLinkProperties(assembleLinkProperties());
- mCallback.onIPv4ProvisioningFailure();
+ final LinkProperties newLp = assembleLinkProperties();
+ ProvisioningChange delta = setLinkProperties(newLp);
+ // If we've gotten here and we're still not provisioned treat that as
+ // a total loss of provisioning.
+ //
+ // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+ // there was no usable IPv6 obtained before the DHCPv4 timeout.
+ //
+ // Regardless: GAME OVER.
+ //
+ // TODO: Make the DHCP client not time out and just continue in
+ // exponential backoff. Callers such as Wi-Fi which need a timeout
+ // should implement it themselves.
+ if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ if (VDBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
+ mCallback.onNewDhcpResults(null);
+
+ dispatchCallback(delta, newLp);
+ if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ transitionTo(mStoppingState);
+ }
}
class StoppedState extends State {
@@ -369,7 +649,7 @@ public class IpManager extends StateMachine {
mNwService.disableIpv6(mInterfaceName);
mNwService.clearInterfaceAddresses(mInterfaceName);
} catch (Exception e) {
- Log.e(TAG, "Failed to clear addresses or disable IPv6" + e);
+ Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
}
resetLinkProperties();
@@ -382,22 +662,27 @@ public class IpManager extends StateMachine {
break;
case CMD_START:
- mStaticIpConfig = (StaticIpConfiguration) msg.obj;
+ mConfiguration = (ProvisioningConfiguration) msg.obj;
transitionTo(mStartedState);
break;
case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
- setLinkProperties(assembleLinkProperties());
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
break;
- case DhcpStateMachine.CMD_ON_QUIT:
- // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
- // Shutting down DHCPv4 progresses simultaneously with
- // transitioning to StoppedState, so we can receive this
- // message after we've already transitioned here.
- //
- // TODO: Figure out if this is actually useful and if not
- // expunge it.
+ case CMD_UPDATE_TCP_BUFFER_SIZES:
+ mTcpBufferSizes = (String) msg.obj;
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_HTTP_PROXY:
+ mHttpProxy = (ProxyInfo) msg.obj;
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case DhcpClient.CMD_ON_QUIT:
+ // Everything is already stopped.
+ Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
break;
default:
@@ -407,6 +692,30 @@ public class IpManager extends StateMachine {
}
}
+ class StoppingState extends State {
+ @Override
+ public void enter() {
+ if (mDhcpClient == null) {
+ // There's no DHCPv4 for which to wait; proceed to stopped.
+ transitionTo(mStoppedState);
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case DhcpClient.CMD_ON_QUIT:
+ mDhcpClient = null;
+ transitionTo(mStoppedState);
+ break;
+
+ default:
+ deferMessage(msg);
+ }
+ return HANDLED;
+ }
+ }
+
class StartedState extends State {
@Override
public void enter() {
@@ -416,48 +725,54 @@ public class IpManager extends StateMachine {
mNwService.enableIpv6(mInterfaceName);
// TODO: Perhaps clearIPv4Address() as well.
} catch (RemoteException re) {
- Log.e(TAG, "Unable to change interface settings: " + re);
+ Log.e(mTag, "Unable to change interface settings: " + re);
} catch (IllegalStateException ie) {
- Log.e(TAG, "Unable to change interface settings: " + ie);
+ Log.e(mTag, "Unable to change interface settings: " + ie);
}
- mIpReachabilityMonitor = new IpReachabilityMonitor(
- mContext,
- mInterfaceName,
- new IpReachabilityMonitor.Callback() {
- @Override
- public void notifyLost(InetAddress ip, String logMsg) {
- if (mCallback.usingIpReachabilityMonitor()) {
+ if (mConfiguration.mUsingIpReachabilityMonitor) {
+ mIpReachabilityMonitor = new IpReachabilityMonitor(
+ mContext,
+ mInterfaceName,
+ new IpReachabilityMonitor.Callback() {
+ @Override
+ public void notifyLost(InetAddress ip, String logMsg) {
mCallback.onReachabilityLost(logMsg);
}
- }
- });
+ });
+ }
// If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly.
- if (mStaticIpConfig != null) {
+ if (mConfiguration.mStaticIpConfig != null) {
if (applyStaticIpConfig()) {
- handleIPv4Success(new DhcpResults(mStaticIpConfig));
+ handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
- handleIPv4Failure();
+ if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ mCallback.onProvisioningFailure(getLinkProperties());
+ transitionTo(mStoppingState);
}
} else {
// Start DHCPv4.
- makeDhcpStateMachine();
- mDhcpStateMachine.registerForPreDhcpNotification();
- mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
+ mDhcpClient = DhcpClient.makeDhcpClient(
+ mContext,
+ IpManager.this,
+ mInterfaceName);
+ mDhcpClient.registerForPreDhcpNotification();
+ mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
}
}
@Override
public void exit() {
- mIpReachabilityMonitor.stop();
- mIpReachabilityMonitor = null;
+ if (mIpReachabilityMonitor != null) {
+ mIpReachabilityMonitor.stop();
+ mIpReachabilityMonitor = null;
+ }
- if (mDhcpStateMachine != null) {
- mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
- mDhcpStateMachine.doQuit();
- mDhcpStateMachine = null;
+ if (mDhcpClient != null) {
+ mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
+ mDhcpClient.doQuit();
}
resetLinkProperties();
@@ -471,7 +786,7 @@ public class IpManager extends StateMachine {
break;
case CMD_START:
- Log.e(TAG, "ALERT: START received in StartedState. Please fix caller.");
+ Log.e(mTag, "ALERT: START received in StartedState. Please fix caller.");
break;
case CMD_CONFIRM:
@@ -479,7 +794,7 @@ public class IpManager extends StateMachine {
// that both probes (a) on-link neighbors and (b) does
// a DHCPv4 RENEW. We used to do this on Wi-Fi framework
// roams.
- if (mCallback.usingIpReachabilityMonitor()) {
+ if (mIpReachabilityMonitor != null) {
mIpReachabilityMonitor.probeAll();
}
break;
@@ -488,69 +803,63 @@ public class IpManager extends StateMachine {
// It's possible to reach here if, for example, someone
// calls completedPreDhcpAction() after provisioning with
// a static IP configuration.
- if (mDhcpStateMachine != null) {
- mDhcpStateMachine.sendMessage(
- DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ if (mDhcpClient != null) {
+ mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
}
break;
- case EVENT_NETLINK_LINKPROPERTIES_CHANGED: {
- final LinkProperties newLp = assembleLinkProperties();
- if (linkPropertiesUnchanged(newLp)) {
- break;
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
+ transitionTo(mStoppedState);
}
- final ProvisioningChange delta = setLinkProperties(newLp);
-
- // NOTE: The only receiver of these callbacks currently
- // treats all three of them identically, namely it calls
- // IpManager#getLinkProperties() and makes its own determination.
- switch (delta) {
- case GAINED_PROVISIONING:
- mCallback.onProvisioningSuccess(newLp);
- break;
+ break;
- case LOST_PROVISIONING:
- mCallback.onProvisioningFailure(newLp);
- break;
+ case CMD_UPDATE_TCP_BUFFER_SIZES:
+ mTcpBufferSizes = (String) msg.obj;
+ // This cannot possibly change provisioning state.
+ handleLinkPropertiesUpdate(SEND_CALLBACKS);
+ break;
- default:
- // TODO: Only notify on STILL_PROVISIONED?
- mCallback.onLinkPropertiesChange(newLp);
- break;
- }
+ case CMD_UPDATE_HTTP_PROXY:
+ mHttpProxy = (ProxyInfo) msg.obj;
+ // This cannot possibly change provisioning state.
+ handleLinkPropertiesUpdate(SEND_CALLBACKS);
break;
- }
- case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
- mCallback.onPreDhcpAction();
+ case DhcpClient.CMD_PRE_DHCP_ACTION:
+ if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
+ if (mConfiguration.mRequestedPreDhcpAction) {
+ mCallback.onPreDhcpAction();
+ } else {
+ sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+ }
break;
- case DhcpStateMachine.CMD_POST_DHCP_ACTION: {
+ case DhcpClient.CMD_POST_DHCP_ACTION: {
// Note that onPostDhcpAction() is likely to be
// asynchronous, and thus there is no guarantee that we
// will be able to observe any of its effects here.
+ if (VDBG) { Log.d(mTag, "onPostDhcpAction()"); }
mCallback.onPostDhcpAction();
final DhcpResults dhcpResults = (DhcpResults) msg.obj;
switch (msg.arg1) {
- case DhcpStateMachine.DHCP_SUCCESS:
+ case DhcpClient.DHCP_SUCCESS:
handleIPv4Success(dhcpResults);
break;
- case DhcpStateMachine.DHCP_FAILURE:
+ case DhcpClient.DHCP_FAILURE:
handleIPv4Failure();
break;
default:
- Log.e(TAG, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
+ Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
}
break;
}
- case DhcpStateMachine.CMD_ON_QUIT:
- // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
- // Regardless, we ignore it.
- //
- // TODO: Figure out if this is actually useful and if not
- // expunge it.
+ case DhcpClient.CMD_ON_QUIT:
+ // DHCPv4 quit early for some reason.
+ Log.e(mTag, "Unexpected CMD_ON_QUIT.");
+ mDhcpClient = null;
break;
default:
@@ -561,35 +870,17 @@ public class IpManager extends StateMachine {
private boolean applyStaticIpConfig() {
final InterfaceConfiguration ifcg = new InterfaceConfiguration();
- ifcg.setLinkAddress(mStaticIpConfig.ipAddress);
+ ifcg.setLinkAddress(mConfiguration.mStaticIpConfig.ipAddress);
ifcg.setInterfaceUp();
try {
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
- if (DBG) Log.d(TAG, "Static IP configuration succeeded");
+ if (DBG) Log.d(mTag, "Static IP configuration succeeded");
} catch (IllegalStateException | RemoteException e) {
- Log.e(TAG, "Static IP configuration failed: ", e);
+ Log.e(mTag, "Static IP configuration failed: ", e);
return false;
}
return true;
}
-
- private void makeDhcpStateMachine() {
- final boolean usingLegacyDhcp = (Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1);
-
- if (usingLegacyDhcp) {
- mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
- mContext,
- IpManager.this,
- mInterfaceName);
- } else {
- mDhcpStateMachine = DhcpClient.makeDhcpStateMachine(
- mContext,
- IpManager.this,
- mInterfaceName);
- }
- }
}
}
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
new file mode 100644
index 000000000000..c0977f79127a
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<profile-owner package="com.android.frameworks.servicestests" name="0" userId="0" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
new file mode 100644
index 000000000000..6b53840434c1
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2">
+ </admin>
+</policies>
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index 313dc8bac749..e45b92a1b486 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -145,14 +145,10 @@ public class SyncOperationTest extends AndroidTestCase {
"provider", 0);
Bundle extras = new Bundle();
SyncOperation periodic = new SyncOperation(ep, 0, "package", 0, 0, extras, false, true,
- SyncOperation.NO_JOB_ID);
- periodic.periodMillis = 60000;
- periodic.flexMillis = 10000;
+ SyncOperation.NO_JOB_ID, 60000, 10000);
SyncOperation oneoff = periodic.createOneTimeSyncOperation();
assertFalse("Conversion to oneoff sync failed.", oneoff.isPeriodic);
- SyncOperation recreated = oneoff.createPeriodicSyncOperation();
- assertTrue("Conversion to periodic sync failed.", oneoff.isPeriodic);
- assertEquals("Period not restored", periodic.periodMillis, recreated.periodMillis);
- assertEquals("Flex not restored", periodic.flexMillis, recreated.flexMillis);
+ assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
+ assertEquals("Flex not restored", periodic.flexMillis, oneoff.flexMillis);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index f32f2096b592..3a6b983854af 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -92,6 +92,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(10))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_REMOVE_USER,
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_WALLPAPER,
@@ -100,6 +101,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(11))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_REMOVE_USER,
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_WALLPAPER,
@@ -137,53 +139,142 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
mContext.binder.restoreCallingIdentity(ident);
}
+ assertTrue(dpms.mOwners.hasDeviceOwner());
+ assertFalse(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
+ assertTrue(dpms.mOwners.hasProfileOwner(10));
+ assertTrue(dpms.mOwners.hasProfileOwner(11));
+ assertFalse(dpms.mOwners.hasProfileOwner(12));
+
// Now all information should be migrated.
assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
+ assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
+ UserHandle.USER_SYSTEM));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12));
// Check the new base restrictions.
DpmTestUtils.assertRestrictions(
- DpmTestUtils.newRestrictions(),
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_RECORD_AUDIO
+ ),
newBaseRestrictions.get(UserHandle.USER_SYSTEM));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
- UserManager.DISALLOW_OUTGOING_CALLS
+ UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_RECORD_AUDIO,
+ UserManager.DISALLOW_WALLPAPER
),
newBaseRestrictions.get(10));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
- UserManager.DISALLOW_WALLPAPER
+ UserManager.DISALLOW_WALLPAPER,
+ UserManager.DISALLOW_RECORD_AUDIO
),
newBaseRestrictions.get(11));
// Check the new owner restrictions.
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
- UserManager.DISALLOW_ADD_USER,
- UserManager.DISALLOW_RECORD_AUDIO
+ UserManager.DISALLOW_ADD_USER
),
dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions());
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
- UserManager.DISALLOW_REMOVE_USER,
- UserManager.DISALLOW_WALLPAPER,
- UserManager.DISALLOW_RECORD_AUDIO
+ UserManager.DISALLOW_REMOVE_USER
),
dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions());
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
- UserManager.DISALLOW_REMOVE_USER,
- UserManager.DISALLOW_RECORD_AUDIO
+ UserManager.DISALLOW_REMOVE_USER
),
dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions());
}
+
+ public void testMigration2_profileOwnerOnUser0() throws Exception {
+ setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+ // Create the legacy owners & policies file.
+ DpmTestUtils.writeToFile(
+ (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml"));
+
+ DpmTestUtils.writeToFile(
+ (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml"));
+
+ // Set up UserManager
+ when(mMockContext.userManagerInternal.getBaseUserRestrictions(
+ eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
+ UserManager.DISALLOW_RECORD_AUDIO,
+ UserManager.DISALLOW_SMS,
+ UserManager.DISALLOW_OUTGOING_CALLS));
+
+ final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Integer userId = (Integer) invocation.getArguments()[0];
+ Bundle bundle = (Bundle) invocation.getArguments()[1];
+
+ newBaseRestrictions.put(userId, bundle);
+
+ return null;
+ }
+ }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
+ anyInt(), any(Bundle.class));
+
+ // Initialize DPM/DPMS and let it migrate the persisted information.
+ // (Need clearCallingIdentity() to pass permission checks.)
+
+ final DevicePolicyManagerServiceTestable dpms;
+
+ final long ident = mContext.binder.clearCallingIdentity();
+ try {
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+ dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
+ dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
+ } finally {
+ mContext.binder.restoreCallingIdentity(ident);
+ }
+ assertFalse(dpms.mOwners.hasDeviceOwner());
+ assertTrue(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
+
+ // Now all information should be migrated.
+ assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
+ assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
+ UserHandle.USER_SYSTEM));
+
+ // Check the new base restrictions.
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_RECORD_AUDIO
+ ),
+ newBaseRestrictions.get(UserHandle.USER_SYSTEM));
+
+ // Check the new owner restrictions.
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
+ UserManager.DISALLOW_SMS,
+ UserManager.DISALLOW_OUTGOING_CALLS
+ ),
+ dpms.getProfileOwnerAdminLocked(UserHandle.USER_SYSTEM).ensureUserRestrictions());
+ }
}
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 64f60d93628b..212b37cebead 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -22,13 +22,17 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.wifi.WifiInfo;
import android.os.Build.VERSION_CODES;
+import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
@@ -43,7 +47,6 @@ import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,6 +61,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -91,6 +95,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
.thenReturn(true);
+ // By default, pretend all users are running and unlocked.
+ when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(true);
+
initializeDpms();
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
@@ -203,7 +210,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
/**
* Test for:
* {@link DevicePolicyManager#setActiveAdmin}
- * with replace=false and replace=true
+ * with replace=false and replace=true
* {@link DevicePolicyManager#isAdminActive}
* {@link DevicePolicyManager#isAdminActiveAsUser}
* {@link DevicePolicyManager#getActiveAdmins}
@@ -331,7 +338,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
/**
* Test for:
* {@link DevicePolicyManager#setActiveAdmin}
- * with replace=false
+ * with replace=false
*/
public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
// 1. Make sure the caller has proper permissions.
@@ -412,6 +419,45 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
/**
+ * {@link DevicePolicyManager#removeActiveAdmin} should fail with the user is not unlocked
+ * (because we can't send the remove broadcast).
+ */
+ public void testRemoveActiveAdmin_userNotRunningOrLocked() {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ // Add admin.
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ assertTrue(dpm.isAdminActive(admin1));
+
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // 1. User not unlocked.
+ when(mContext.userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
+ .thenReturn(false);
+ try {
+ dpm.removeActiveAdmin(admin1);
+ fail("Didn't throw IllegalStateException");
+ } catch (IllegalStateException expected) {
+ MoreAsserts.assertContainsRegex(
+ "User must be running and unlocked", expected.getMessage());
+ }
+
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // 2. User unlocked.
+ when(mContext.userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
+ .thenReturn(true);
+
+ dpm.removeActiveAdmin(admin1);
+
+ assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+ }
+
+ /**
* Test for:
* {@link DevicePolicyManager#removeActiveAdmin}
*/
@@ -779,6 +825,18 @@ public class DevicePolicyManagerTest extends DpmTestBase {
doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser(
eq(admin1.getPackageName()),
anyInt());
+
+ // But first pretend the user is locked. Then it should fail.
+ when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(false);
+ try {
+ dpm.clearDeviceOwnerApp(admin1.getPackageName());
+ fail("Didn't throw IllegalStateException");
+ } catch (IllegalStateException expected) {
+ MoreAsserts.assertContainsRegex(
+ "User must be running and unlocked", expected.getMessage());
+ }
+
+ when(mContext.userManager.isUserUnlocked(anyInt())).thenReturn(true);
reset(mContext.userManagerInternal);
dpm.clearDeviceOwnerApp(admin1.getPackageName());
@@ -866,7 +924,19 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName()));
assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
- // Clear
+ // First try when the user is locked, which should fail.
+ when(mContext.userManager.isUserUnlocked(anyInt()))
+ .thenReturn(false);
+ try {
+ dpm.clearProfileOwner(admin1);
+ fail("Didn't throw IllegalStateException");
+ } catch (IllegalStateException expected) {
+ MoreAsserts.assertContainsRegex(
+ "User must be running and unlocked", expected.getMessage());
+ }
+ // Clear, really.
+ when(mContext.userManager.isUserUnlocked(anyInt()))
+ .thenReturn(true);
dpm.clearProfileOwner(admin1);
// Check
@@ -931,7 +1001,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
/**
* This essentially tests
- * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is private.)
+ * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is
+ * private.)
*
* We didn't use to persist the DO component class name, but now we do, and the above method
* finds the right component from a package name upon migration.
@@ -995,6 +1066,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
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(
@@ -1004,6 +1076,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(DpmMockContext.CALLER_USER_HANDLE));
mContext.binder.callingUid = appRestrictionsManagerUid;
+ final PackageInfo pi = new PackageInfo();
+ pi.applicationInfo = new ApplicationInfo();
+ pi.applicationInfo.flags = ApplicationInfo.FLAG_HAS_CODE;
+ doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+ eq(appRestrictionsManagerPackage),
+ anyInt(),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+
// appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
// delegated that permission yet.
assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
@@ -1028,6 +1108,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
+ // Check the API does not allow setting a non-existent package
+ try {
+ dpm.setApplicationRestrictionsManagingPackage(admin1,
+ nonExistAppRestrictionsManagerPackage);
+ fail("Non-existent app set as app restriction manager.");
+ } catch (IllegalArgumentException expected) {
+ MoreAsserts.assertContainsRegex(
+ "is not installed on the current user", expected.getMessage());
+ }
+
// Let appRestrictionsManagerPackage manage app restrictions
dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
assertEquals(appRestrictionsManagerPackage,
@@ -1109,7 +1199,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ );
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1581,7 +1671,12 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// that the test user is not affiliated anymore.
dpm.clearProfileOwner(admin2);
final ComponentName admin = new ComponentName("test", "test");
- markPackageAsInstalled(admin.getPackageName(), null, DpmMockContext.CALLER_USER_HANDLE);
+
+ setUpPackageManagerForFakeAdmin(admin, DpmMockContext.CALLER_UID,
+ /* enabledSetting =*/ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ /* appTargetSdk = */ null, admin2);
+
+ dpm.setActiveAdmin(admin, /* refreshing =*/ true, DpmMockContext.CALLER_USER_HANDLE);
assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
assertFalse(dpm.isAffiliatedUser());
@@ -1741,4 +1836,76 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
}
+
+ public void testSetMaximumTimeToLock() {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 0);
+ verifyScreenTimeoutCall(null, false);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 1);
+ verifyScreenTimeoutCall(1, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, 10);
+ verifyScreenTimeoutCall(null, false);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 5);
+ verifyScreenTimeoutCall(5, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, 4);
+ verifyScreenTimeoutCall(4, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 0);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE);
+ verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE + 1);
+ verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, 10);
+ verifyScreenTimeoutCall(10, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ // There's no restriction; shold be set to MAX.
+ dpm.setMaximumTimeToLock(admin2, 0);
+ verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
+ }
+
+ private void verifyScreenTimeoutCall(Integer expectedTimeout,
+ boolean shouldStayOnWhilePluggedInBeCleared) {
+ if (expectedTimeout == null) {
+ verify(mMockContext.powerManagerInternal, times(0))
+ .setMaximumScreenOffTimeoutFromDeviceAdmin(anyInt());
+ } else {
+ verify(mMockContext.powerManagerInternal, times(1))
+ .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(expectedTimeout));
+ }
+ // TODO Verify calls to settingsGlobalPutInt. Tried but somehow mockito threw
+ // UnfinishedVerificationException.
+ }
}
+
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 7a000985a5ca..ef8e420e53f0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -44,11 +44,14 @@ import android.test.mock.MockContext;
import android.view.IWindowManager;
import org.junit.Assert;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -294,6 +297,50 @@ public class DpmMockContext extends MockContext {
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
+ when(userManager.getUserInfo(anyInt())).thenAnswer(
+ new Answer<UserInfo>() {
+ @Override
+ public UserInfo answer(InvocationOnMock invocation) throws Throwable {
+ final int userId = (int) invocation.getArguments()[0];
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ return ui;
+ }
+ }
+ return null;
+ }
+ }
+ );
+ when(userManager.getProfiles(anyInt())).thenAnswer(
+ new Answer<List<UserInfo>>() {
+ @Override
+ public List<UserInfo> answer(InvocationOnMock invocation) throws Throwable {
+ final int userId = (int) invocation.getArguments()[0];
+ final ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
+ UserInfo parent = null;
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ parent = ui;
+ break;
+ }
+ }
+ if (parent == null) {
+ return ret;
+ }
+ ret.add(parent);
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ continue;
+ }
+ if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ && ui.profileGroupId == parent.profileGroupId) {
+ ret.add(ui);
+ }
+ }
+ return ret;
+ }
+ }
+ );
// Create a data directory.
final File dir = new File(dataDir, "user" + userId);
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 53ca45dde5ae..c80ca6c996a2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -96,12 +97,26 @@ public abstract class DpmTestBase extends AndroidTestCase {
protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
Integer enabledSetting, Integer appTargetSdk) throws Exception {
+ setUpPackageManagerForFakeAdmin(admin, packageUid, enabledSetting, appTargetSdk,
+ admin);
+ }
+
+ /**
+ * Set up a component in the mock package manager to be an active admin.
+ *
+ * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
+ * @param copyFromAdmin package information for {@code admin} will be built based on this
+ * component's information.
+ */
+ protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+ Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
+ throws Exception {
// Set up getApplicationInfo().
final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
mRealTestContext.getPackageManager().getApplicationInfo(
- admin.getPackageName(),
+ copyFromAdmin.getPackageName(),
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
ai.enabledSetting = enabledSetting == null
@@ -111,6 +126,8 @@ public abstract class DpmTestBase extends AndroidTestCase {
ai.targetSdkVersion = appTargetSdk;
}
ai.uid = packageUid;
+ ai.packageName = admin.getPackageName();
+ ai.name = admin.getClassName();
doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
eq(admin.getPackageName()),
@@ -120,7 +137,7 @@ public abstract class DpmTestBase extends AndroidTestCase {
// Set up queryBroadcastReceivers().
final Intent resolveIntent = new Intent();
- resolveIntent.setComponent(admin);
+ resolveIntent.setComponent(copyFromAdmin);
final List<ResolveInfo> realResolveInfo =
mRealTestContext.getPackageManager().queryBroadcastReceivers(
resolveIntent,
@@ -132,10 +149,15 @@ public abstract class DpmTestBase extends AndroidTestCase {
realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
// We need to rewrite the UID in the activity info.
- realResolveInfo.get(0).activityInfo.applicationInfo = ai;
+ final ActivityInfo aci = realResolveInfo.get(0).activityInfo;
+ aci.applicationInfo = ai;
+ aci.packageName = admin.getPackageName();
+ aci.name = admin.getClassName();
+
+ // Note we don't set up queryBroadcastReceivers. We don't use it in DPMS.
- doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
- MockUtils.checkIntentComponent(admin),
+ doReturn(aci).when(mMockContext.ipackageManager).getReceiverInfo(
+ eq(admin),
anyInt(),
eq(UserHandle.getUserId(packageUid)));
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index ae0a25ed05d6..edbff83736ad 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -12,6 +12,7 @@ import android.test.RenamingDelegatingContext;
import android.util.Log;
import android.util.ArraySet;
+import com.android.server.job.JobStore.JobSet;
import com.android.server.job.controllers.JobStatus;
import java.util.Iterator;
@@ -58,15 +59,15 @@ public class JobStoreTest extends AndroidTestCase {
.setMinimumLatency(runFromMillis)
.setPersisted(true)
.build();
- final JobStatus ts = new JobStatus(task, SOME_UID);
+ final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(ts);
Thread.sleep(IO_WAIT);
// Manually load tasks from xml file.
- final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size());
- final JobStatus loadedTaskStatus = jobStatusSet.iterator().next();
+ final JobStatus loadedTaskStatus = jobStatusSet.getAllJobs().get(0);
assertTasksEqual(task, loadedTaskStatus.getJob());
assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(ts));
assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid());
@@ -91,16 +92,16 @@ public class JobStoreTest extends AndroidTestCase {
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true)
.build();
- final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID);
- final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID);
+ final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1, null);
+ final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(taskStatus1);
mTaskStoreUnderTest.add(taskStatus2);
Thread.sleep(IO_WAIT);
- final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size());
- Iterator<JobStatus> it = jobStatusSet.iterator();
+ Iterator<JobStatus> it = jobStatusSet.getAllJobs().iterator();
JobStatus loaded1 = it.next();
JobStatus loaded2 = it.next();
@@ -140,46 +141,90 @@ public class JobStoreTest extends AndroidTestCase {
extras.putInt("into", 3);
b.setExtras(extras);
final JobInfo task = b.build();
- JobStatus taskStatus = new JobStatus(task, SOME_UID);
+ JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
- final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
- JobStatus loaded = jobStatusSet.iterator().next();
+ JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
assertTasksEqual(task, loaded.getJob());
}
+ public void testWritingTaskWithSourcePackage() throws Exception {
+ JobInfo.Builder b = new Builder(8, mComponent)
+ .setRequiresDeviceIdle(true)
+ .setPeriodic(10000L)
+ .setRequiresCharging(true)
+ .setPersisted(true);
+ JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
+ "com.google.android.gms", 0, null);
+
+ mTaskStoreUnderTest.add(taskStatus);
+ Thread.sleep(IO_WAIT);
+
+ final JobSet jobStatusSet = new JobSet();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+ assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
+ JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
+ assertEquals("Source package not equal.", loaded.getSourcePackageName(),
+ taskStatus.getSourcePackageName());
+ assertEquals("Source user not equal.", loaded.getSourceUserId(),
+ taskStatus.getSourceUserId());
+ }
+
+ public void testWritingTaskWithFlex() throws Exception {
+ JobInfo.Builder b = new Builder(8, mComponent)
+ .setRequiresDeviceIdle(true)
+ .setPeriodic(5*60*60*1000, 1*60*60*1000)
+ .setRequiresCharging(true)
+ .setPersisted(true);
+ JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
+
+ mTaskStoreUnderTest.add(taskStatus);
+ Thread.sleep(IO_WAIT);
+
+ final JobSet jobStatusSet = new JobSet();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+ assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
+ JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
+ assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(),
+ taskStatus.getJob().getIntervalMillis());
+ assertEquals("Flex not equal.", loaded.getJob().getFlexMillis(),
+ taskStatus.getJob().getFlexMillis());
+ }
public void testMassivePeriodClampedOnRead() throws Exception {
- final long TEN_SECONDS = 10000L;
+ final long ONE_HOUR = 60*60*1000L; // flex
+ final long TWO_HOURS = 2 * ONE_HOUR; // period
JobInfo.Builder b = new Builder(8, mComponent)
- .setPeriodic(TEN_SECONDS)
+ .setPeriodic(TWO_HOURS, ONE_HOUR)
.setPersisted(true);
final long invalidLateRuntimeElapsedMillis =
- SystemClock.elapsedRealtime() + (TEN_SECONDS * 2) + 5000; // >2P from now.
+ SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS; // > period+flex
final long invalidEarlyRuntimeElapsedMillis =
- invalidLateRuntimeElapsedMillis - TEN_SECONDS; // Early is (late - period).
- final JobStatus js = new JobStatus(b.build(), SOME_UID,
+ invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period).
+ final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
+ 0 /* sourceUserId */, "someTag",
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
mTaskStoreUnderTest.add(js);
Thread.sleep(IO_WAIT);
- final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
- JobStatus loaded = jobStatusSet.iterator().next();
+ JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
// Assert early runtime was clamped to be under now + period. We can do <= here b/c we'll
// call SystemClock.elapsedRealtime after doing the disk i/o.
final long newNowElapsed = SystemClock.elapsedRealtime();
assertTrue("Early runtime wasn't correctly clamped.",
- loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS);
- // Assert late runtime was clamped to be now + period*2.
+ loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS);
+ // Assert late runtime was clamped to be now + period + flex.
assertTrue("Early runtime wasn't correctly clamped.",
- loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS * 2);
+ loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR);
}
public void testPriorityPersisted() throws Exception {
@@ -187,12 +232,12 @@ public class JobStoreTest extends AndroidTestCase {
.setOverrideDeadline(5000)
.setPriority(42)
.setPersisted(true);
- final JobStatus js = new JobStatus(b.build(), SOME_UID);
+ final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(js);
Thread.sleep(IO_WAIT);
- final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
- JobStatus loaded = jobStatusSet.iterator().next();
+ JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
assertEquals("Priority not correctly persisted.", 42, loaded.getPriority());
}
@@ -203,18 +248,18 @@ public class JobStoreTest extends AndroidTestCase {
JobInfo.Builder b = new Builder(42, mComponent)
.setOverrideDeadline(10000)
.setPersisted(false);
- JobStatus jsNonPersisted = new JobStatus(b.build(), SOME_UID);
+ JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(jsNonPersisted);
b = new Builder(43, mComponent)
.setOverrideDeadline(10000)
.setPersisted(true);
- JobStatus jsPersisted = new JobStatus(b.build(), SOME_UID);
+ JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(jsPersisted);
Thread.sleep(IO_WAIT);
- final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
assertEquals("Job count is incorrect.", 1, jobStatusSet.size());
- JobStatus jobStatus = jobStatusSet.iterator().next();
+ JobStatus jobStatus = jobStatusSet.getAllJobs().iterator().next();
assertEquals("Wrong job persisted.", 43, jobStatus.getJobId());
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
new file mode 100644
index 000000000000..b9e9aa9b23ed
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
@@ -0,0 +1,634 @@
+/*
+ * 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.net;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.when;
+
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.ROAMING_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import android.app.usage.NetworkStatsManager;
+import android.net.DataUsageRequest;
+import android.net.NetworkIdentity;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+
+import android.os.ConditionVariable;
+import android.os.Looper;
+import android.os.Messenger;
+import android.os.Message;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+
+import com.android.internal.net.VpnInfo;
+import com.android.server.net.NetworkStatsService;
+import com.android.server.net.NetworkStatsServiceTest.IdleableHandlerThread;
+import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link NetworkStatsObservers}.
+ */
+public class NetworkStatsObserversTest extends TestCase {
+ private static final String TEST_IFACE = "test0";
+ private static final String TEST_IFACE2 = "test1";
+ private static final long TEST_START = 1194220800000L;
+
+ private static final String IMSI_1 = "310004";
+ private static final String IMSI_2 = "310260";
+ private static final String TEST_SSID = "AndroidAP";
+
+ private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
+ private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
+ private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
+
+ private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
+ private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
+ private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
+ private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
+
+ private static final long WAIT_TIMEOUT = 500; // 1/2 sec
+ private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
+ private static final long BASE_BYTES = 7 * MB_IN_BYTES;
+ private static final int INVALID_TYPE = -1;
+
+ private static final int[] NO_UIDS = null;
+ private static final VpnInfo[] VPN_INFO = new VpnInfo[0];
+
+ private long mElapsedRealtime;
+
+ private IdleableHandlerThread mObserverHandlerThread;
+ private Handler mObserverNoopHandler;
+
+ private LatchedHandler mHandler;
+ private ConditionVariable mCv;
+
+ private NetworkStatsObservers mStatsObservers;
+ private Messenger mMessenger;
+ private ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
+ private ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
+
+ @Mock private IBinder mockBinder;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+
+ mObserverHandlerThread = new IdleableHandlerThread("HandlerThread");
+ mObserverHandlerThread.start();
+ final Looper observerLooper = mObserverHandlerThread.getLooper();
+ mStatsObservers = new NetworkStatsObservers() {
+ @Override
+ protected Looper getHandlerLooperLocked() {
+ return observerLooper;
+ }
+ };
+
+ mCv = new ConditionVariable();
+ mHandler = new LatchedHandler(Looper.getMainLooper(), mCv);
+ mMessenger = new Messenger(mHandler);
+
+ mActiveIfaces = new ArrayMap<>();
+ mActiveUidIfaces = new ArrayMap<>();
+ }
+
+ public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
+ long thresholdTooLowBytes = 1L;
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, thresholdTooLowBytes);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ }
+
+ public void testRegister_highThreshold_accepted() throws Exception {
+ long highThresholdBytes = 2 * THRESHOLD_BYTES;
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, highThresholdBytes);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(highThresholdBytes, request.thresholdInBytes);
+ }
+
+ public void testRegister_twoRequests_twoIds() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request1.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request1.templates));
+ assertNull(request1.uids);
+ assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
+
+ DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request2.requestId > request1.requestId);
+ assertTrue(Arrays.deepEquals(templates, request2.templates));
+ assertNull(request2.uids);
+ assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
+ }
+
+ public void testRegister_defaultAccess_otherUids_securityException() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ try {
+ mStatsObservers.register(inputRequest, mMessenger, mockBinder, UID_RED,
+ NetworkStatsAccess.Level.DEFAULT);
+ fail("Should have denied access");
+ } catch (SecurityException expected) {}
+ }
+
+ public void testRegister_userAccess_otherUidsSameUser()
+ throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.USER);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids, request.uids));
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ }
+
+ public void testRegister_defaultAccess_sameUid() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEFAULT);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids, request.uids));
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ }
+
+ public void testUnregister_unknownRequest_noop() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest unknownRequest = new DataUsageRequest(
+ 123456 /* id */, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ mStatsObservers.unregister(unknownRequest, UID_RED);
+ }
+
+ public void testUnregister_knownRequest_releasesCaller() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mStatsObservers.unregister(request, Process.SYSTEM_UID);
+ waitForObserverToIdle();
+
+ Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ }
+
+ public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mStatsObservers.unregister(request, UID_BLUE);
+ waitForObserverToIdle();
+
+ Mockito.verifyZeroInteractions(mockBinder);
+ }
+
+ public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
+ NetworkStats uidSnapshot = null;
+
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
+ NetworkStats uidSnapshot = null;
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ mCv.block(WAIT_TIMEOUT);
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_aboveThresholdNetwork_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
+ NetworkStats uidSnapshot = null;
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
+ BASE_BYTES + THRESHOLD_BYTES, 22L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_aboveThresholdMultipleNetwork_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEVICESUMMARY);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet1 = new NetworkIdentitySet();
+ identSet1.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet1);
+
+ NetworkIdentitySet identSet2 = new NetworkIdentitySet();
+ identSet2.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_2, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE2, identSet2);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L)
+ .addIfaceValues(TEST_IFACE2, BASE_BYTES + 1234L, 18L, BASE_BYTES, 12L);
+ NetworkStats uidSnapshot = null;
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta - traffic on IMSI2
+ xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L)
+ .addIfaceValues(TEST_IFACE2, BASE_BYTES + THRESHOLD_BYTES, 22L,
+ BASE_BYTES + THRESHOLD_BYTES, 24L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_aboveThresholdUid_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids,request.uids));
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_defaultAccess_noUid_notifiesSameUid() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEFAULT);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_defaultAccess_noUid_usageOtherUid_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_BLUE, NetworkStatsAccess.Level.USER);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.USER);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ private void waitForObserverToIdle() {
+ // Send dummy message to make sure that any previous message has been handled
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mObserverHandlerThread.waitForIdle(WAIT_TIMEOUT);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index 8cbd32d2bc65..4f6c7b9484c7 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.net;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
@@ -43,6 +43,7 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
@@ -54,7 +55,10 @@ import android.app.AlarmManager;
import android.app.IAlarmListener;
import android.app.IAlarmManager;
import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
+import android.content.Context;
import android.content.Intent;
+import android.net.DataUsageRequest;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsSession;
@@ -65,7 +69,17 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.INetworkManagementService;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Messenger;
+import android.os.MessageQueue;
+import android.os.MessageQueue.IdleHandler;
+import android.os.Message;
+import android.os.PowerManager;
import android.os.WorkSource;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
@@ -74,6 +88,7 @@ import android.test.suitebuilder.annotation.Suppress;
import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
+import com.android.server.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -85,6 +100,7 @@ import org.easymock.EasyMock;
import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -113,16 +129,20 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
private static final int UID_BLUE = 1002;
private static final int UID_GREEN = 1003;
+ private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
+ private static final int INVALID_TYPE = -1;
+
private long mElapsedRealtime;
private BroadcastInterceptingContext mServiceContext;
private File mStatsDir;
private INetworkManagementService mNetManager;
- private IAlarmManager mAlarmManager;
private TrustedTime mTime;
private NetworkStatsSettings mSettings;
private IConnectivityManager mConnManager;
+ private IdleableHandlerThread mHandlerThread;
+ private Handler mHandler;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
@@ -139,13 +159,28 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
}
mNetManager = createMock(INetworkManagementService.class);
- mAlarmManager = createMock(IAlarmManager.class);
+
+ // TODO: Mock AlarmManager when migrating this test to Mockito.
+ AlarmManager alarmManager = (AlarmManager) mServiceContext
+ .getSystemService(Context.ALARM_SERVICE);
mTime = createMock(TrustedTime.class);
mSettings = createMock(NetworkStatsSettings.class);
mConnManager = createMock(IConnectivityManager.class);
+ PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
+ Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock =
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
mService = new NetworkStatsService(
- mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings);
+ mServiceContext, mNetManager, alarmManager, wakeLock, mTime,
+ TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
+ mStatsDir, getBaseDir(mStatsDir));
+ mHandlerThread = new IdleableHandlerThread("HandlerThread");
+ mHandlerThread.start();
+ Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
+ mHandler = new Handler(mHandlerThread.getLooper(), callback);
+ mService.setHandler(mHandler, callback);
mService.bindConnectivityManager(mConnManager);
mElapsedRealtime = 0L;
@@ -178,7 +213,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mStatsDir = null;
mNetManager = null;
- mAlarmManager = null;
mTime = null;
mSettings = null;
mConnManager = null;
@@ -217,7 +251,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
@@ -234,7 +268,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
@@ -282,7 +316,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
@@ -362,7 +396,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
@@ -380,7 +414,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify identical stats, but spread across 4 buckets now
history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
@@ -420,7 +454,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xF00D, 10);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
@@ -446,7 +480,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
replay();
mService.forceUpdateIfaces();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
verifyAndReset();
// create traffic on second network
@@ -465,7 +499,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify original history still intact
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
@@ -511,7 +545,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
@@ -578,7 +612,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xF00D, 5);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
@@ -598,7 +632,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
replay();
mService.forceUpdateIfaces();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
verifyAndReset();
// create traffic on second network
@@ -616,7 +650,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify that ALL_MOBILE template combines both
assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
@@ -652,7 +686,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
@@ -671,7 +705,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// first verify entire history present
NetworkStats stats = mSession.getSummaryForAllUid(
@@ -722,7 +756,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
@@ -744,7 +778,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// test that we combined correctly
assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
@@ -795,7 +829,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
@@ -843,7 +877,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
@@ -853,6 +887,285 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
}
+ public void testRegisterDataUsageCallback_network() throws Exception {
+ // pretend that wifi network comes online; service should ask about full
+ // network state, and poll any existing interfaces before updating.
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkState(buildWifiState());
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
+
+ replay();
+ mService.forceUpdateIfaces();
+
+ // verify service has empty history for wifi
+ assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
+ verifyAndReset();
+
+ String callingPackage = "the.calling.package";
+ long thresholdInBytes = 1L; // very small; should be overriden by framework
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, null /* uids */, thresholdInBytes);
+
+ // Create a messenger that waits for callback activity
+ ConditionVariable cv = new ConditionVariable(false);
+ LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
+ Messenger messenger = new Messenger(latchedHandler);
+
+ // Allow binder to connect
+ IBinder mockBinder = createMock(IBinder.class);
+ mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
+ EasyMock.replay(mockBinder);
+
+ // Force poll
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ replay();
+
+ // Register and verify request and that binder was called
+ DataUsageRequest request =
+ mService.registerDataUsageCallback(callingPackage, inputRequest,
+ messenger, mockBinder);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
+ assertEquals(minThresholdInBytes, request.thresholdInBytes);
+
+ // Send dummy message to make sure that any previous message has been handled
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+
+ verifyAndReset();
+
+ // Make sure that the caller binder gets connected
+ EasyMock.verify(mockBinder);
+ EasyMock.reset(mockBinder);
+
+ // modify some number on wifi, and trigger poll event
+ // not enough traffic to call data usage callback
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ verifyAndReset();
+ assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
+
+ // make sure callback has not being called
+ assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
+
+ // and bump forward again, with counters going higher. this is
+ // important, since it will trigger the data usage callback
+ incrementCurrentTime(DAY_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
+ verifyAndReset();
+
+ // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
+ cv.close();
+
+ // Allow binder to disconnect
+ expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
+ .andReturn(true);
+ EasyMock.replay(mockBinder);
+
+ // Unregister request
+ mService.unregisterDataUsageRequest(request);
+
+ // Wait for the caller to ack receipt of CALLBACK_RELEASED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
+
+ // Make sure that the caller binder gets disconnected
+ EasyMock.verify(mockBinder);
+ }
+
+ public void testRegisterDataUsageCallback_uids() throws Exception {
+ // pretend that network comes online
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
+
+ replay();
+ mService.forceUpdateIfaces();
+ verifyAndReset();
+
+ String callingPackage = "the.calling.package";
+ long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+ int[] uids = new int[] { UID_RED };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, thresholdInBytes);
+
+ // Create a messenger that waits for callback activity
+ ConditionVariable cv = new ConditionVariable(false);
+ cv.close();
+ LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
+ Messenger messenger = new Messenger(latchedHandler);
+
+ // Allow binder to connect
+ IBinder mockBinder = createMock(IBinder.class);
+ mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
+ EasyMock.replay(mockBinder);
+
+ // Force poll
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ replay();
+
+ // Register and verify request and that binder was called
+ DataUsageRequest request =
+ mService.registerDataUsageCallback(callingPackage, inputRequest,
+ messenger, mockBinder);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids, request.uids));
+ assertEquals(thresholdInBytes, request.thresholdInBytes);
+
+ // Wait for service to handle internal MSG_REGISTER_DATA_USAGE_LISTENER
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+
+ verifyAndReset();
+
+ // Make sure that the caller binder gets connected
+ EasyMock.verify(mockBinder);
+ EasyMock.reset(mockBinder);
+
+ // modify some number on mobile interface, and trigger poll event
+ // not enough traffic to call data usage callback
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 2L,
+ 128L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+ 1L, 0L));
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
+
+ // verify entire history present
+ NetworkStats stats = mSession.getSummaryForAllUid(
+ sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(2, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 2L,
+ 128L, 2L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING, 64L, 1L, 64L,
+ 1L, 0);
+
+ verifyAndReset();
+
+ // make sure callback has not being called
+ assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
+
+ // and bump forward again, with counters going higher. this is
+ // important, since it will trigger the data usage callback
+ incrementCurrentTime(DAY_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ 128000000L, 2L, 128000000L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT,
+ 64000000L, 1L, 64000000L, 1L, 0L));
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertUidTotal(sTemplateImsi1, UID_RED, 128000000L, 2L, 128000000L, 2L, 0);
+
+ // verify entire history present
+ stats = mSession.getSummaryForAllUid(
+ sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(2, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING,
+ 128000000L, 2L, 128000000L, 2L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING,
+ 64000000L, 1L, 64000000L, 1L, 0);
+
+ verifyAndReset();
+
+ // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
+ cv.close();
+
+ // Allow binder to disconnect
+ expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
+ .andReturn(true);
+ EasyMock.replay(mockBinder);
+
+ // Unregister request
+ mService.unregisterDataUsageRequest(request);
+
+ // Wait for the caller to ack receipt of CALLBACK_RELEASED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
+
+ // Make sure that the caller binder gets disconnected
+ EasyMock.verify(mockBinder);
+ }
+
+ public void testUnregisterDataUsageCallback_unknown_noop() throws Exception {
+ String callingPackage = "the.calling.package";
+ long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+ DataUsageRequest unknownRequest = new DataUsageRequest(
+ 2, templates, null /* uids */, thresholdInBytes);
+
+ mService.unregisterDataUsageRequest(unknownRequest);
+ }
+
+ private static File getBaseDir(File statsDir) {
+ File baseDir = new File(statsDir, "netstats");
+ baseDir.mkdirs();
+ return baseDir;
+ }
+
private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) throws Exception {
assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
@@ -894,16 +1207,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
}
private void expectSystemReady() throws Exception {
- mAlarmManager.remove(isA(PendingIntent.class), EasyMock.<IAlarmListener>isNull());
- expectLastCall().anyTimes();
-
- mAlarmManager.set(eq(getContext().getPackageName()),
- eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
- anyInt(), isA(PendingIntent.class), EasyMock.<IAlarmListener>isNull(),
- EasyMock.<String>isNull(), EasyMock.<WorkSource>isNull(),
- EasyMock.<AlarmManager.AlarmClockInfo>isNull());
- expectLastCall().anyTimes();
-
mNetManager.setGlobalAlert(anyLong());
expectLastCall().atLeastOnce();
@@ -1093,11 +1396,75 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
}
private void replay() {
- EasyMock.replay(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
+ EasyMock.replay(mNetManager, mTime, mSettings, mConnManager);
}
private void verifyAndReset() {
- EasyMock.verify(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
- EasyMock.reset(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
+ EasyMock.verify(mNetManager, mTime, mSettings, mConnManager);
+ EasyMock.reset(mNetManager, mTime, mSettings, mConnManager);
+ }
+
+ private void forcePollAndWaitForIdle() {
+ mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ // Send dummy message to make sure that any previous message has been handled
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+ }
+
+ static class LatchedHandler extends Handler {
+ private final ConditionVariable mCv;
+ int mLastMessageType = INVALID_TYPE;
+
+ LatchedHandler(Looper looper, ConditionVariable cv) {
+ super(looper);
+ mCv = cv;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ mLastMessageType = msg.what;
+ mCv.open();
+ super.handleMessage(msg);
+ }
+ }
+
+ /**
+ * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
+ * will return immediately if the handler is already idle.
+ */
+ static class IdleableHandlerThread extends HandlerThread {
+ private IdleHandler mIdleHandler;
+
+ public IdleableHandlerThread(String name) {
+ super(name);
+ }
+
+ public void waitForIdle(long 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() {
+ 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);
+ }
+ }
}
+
}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index 31182fcf46ae..32501ad88789 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -15,17 +15,10 @@
*/
package com.android.server.notification;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_LOW;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
-
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import android.app.Notification;
-import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.AndroidTestCase;
@@ -55,14 +48,13 @@ public class RankingHelperTest extends AndroidTestCase {
UserHandle user = UserHandle.ALL;
mHelper = new RankingHelper(getContext(), handler, mUsageStats,
- new String[] {TopicImportanceExtractor.class.getName()});
+ new String[] {ImportanceExtractor.class.getName()});
mNotiGroupGSortA = new Notification.Builder(getContext())
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
- .setTopic(new Notification.Topic("A", "a"))
.build();
mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user));
@@ -72,7 +64,6 @@ public class RankingHelperTest extends AndroidTestCase {
.setGroup("G")
.setSortKey("B")
.setWhen(1200)
- .setTopic(new Notification.Topic("A", "a"))
.build();
mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user));
@@ -80,7 +71,6 @@ public class RankingHelperTest extends AndroidTestCase {
mNotiNoGroup = new Notification.Builder(getContext())
.setContentTitle("C")
.setWhen(1201)
- .setTopic(new Notification.Topic("C", "c"))
.build();
mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user));
@@ -88,7 +78,6 @@ public class RankingHelperTest extends AndroidTestCase {
mNotiNoGroup2 = new Notification.Builder(getContext())
.setContentTitle("D")
.setWhen(1202)
- .setTopic(new Notification.Topic("D", "d"))
.build();
mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user));
@@ -97,7 +86,6 @@ public class RankingHelperTest extends AndroidTestCase {
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
- .setTopic(new Notification.Topic("E", "e"))
.build();
mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user));
@@ -152,26 +140,4 @@ public class RankingHelperTest extends AndroidTestCase {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
mHelper.sort(notificationList);
}
-
- @SmallTest
- public void testTopicImportanceExtractor() throws Exception {
- mHelper.setImportance("package", 0, new Notification.Topic("A", "a"), IMPORTANCE_MAX);
- // There is no B. There never was a b. Moving on...
- mHelper.setImportance("package", 0, new Notification.Topic("C", "c"), IMPORTANCE_HIGH);
- mHelper.setImportance("package", 0, new Notification.Topic("D", "d"), IMPORTANCE_LOW);
- // watch out: different package.
- mHelper.setImportance("package2", 0, new Notification.Topic("E", "e"), IMPORTANCE_NONE);
-
- TopicImportanceExtractor validator = mHelper.findExtractor(TopicImportanceExtractor.class);
- validator.process(mRecordGroupGSortA);
- validator.process(mRecordGroupGSortB);
- validator.process(mRecordNoGroup);
- validator.process(mRecordNoGroup2);
- validator.process(mRecordNoGroupSortA);
- assertTrue(mRecordGroupGSortA.getTopicImportance() == IMPORTANCE_MAX);
- assertTrue(mRecordGroupGSortB.getTopicImportance() == IMPORTANCE_MAX);
- assertTrue(mRecordNoGroup.getTopicImportance() == IMPORTANCE_HIGH);
- assertTrue(mRecordNoGroup2.getTopicImportance() == IMPORTANCE_LOW);
- assertTrue(mRecordNoGroupSortA.getTopicImportance() == IMPORTANCE_UNSPECIFIED);
- }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 46ad8a10534e..8b250f4c18d8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -74,6 +74,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
@@ -125,6 +126,7 @@ public class UsageStatsService extends SystemService implements
Handler mHandler;
AppOpsManager mAppOps;
UserManager mUserManager;
+ PackageManager mPackageManager;
AppWidgetManager mAppWidgetManager;
IDeviceIdleController mDeviceIdleController;
private DisplayManager mDisplayManager;
@@ -149,6 +151,8 @@ public class UsageStatsService extends SystemService implements
private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
mPackageAccessListeners = new ArrayList<>();
+ private List<String> mCarrierPrivilegedApps;
+
public UsageStatsService(Context context) {
super(context);
}
@@ -157,7 +161,7 @@ public class UsageStatsService extends SystemService implements
public void onStart() {
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
-
+ mPackageManager = getContext().getPackageManager();
mHandler = new H(BackgroundThread.get().getLooper());
File systemDataDir = new File(Environment.getDataDirectory(), "system");
@@ -168,10 +172,18 @@ public class UsageStatsService extends SystemService implements
+ mUsageStatsDir.getAbsolutePath());
}
- IntentFilter userActions = new IntentFilter(Intent.ACTION_USER_REMOVED);
- userActions.addAction(Intent.ACTION_USER_STARTED);
- getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, userActions,
- null, null);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_STARTED);
+ getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, filter,
+ null, mHandler);
+
+ IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addDataScheme("package");
+
+ getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
+ null, mHandler);
mAppIdleEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableAutoPowerModes);
@@ -230,15 +242,15 @@ public class UsageStatsService extends SystemService implements
}
private class UserActionsReceiver extends BroadcastReceiver {
-
@Override
public void onReceive(Context context, Intent intent) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_USER_REMOVED.equals(action)) {
if (userId >= 0) {
mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
}
- } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+ } else if (Intent.ACTION_USER_STARTED.equals(action)) {
if (userId >=0) {
postCheckIdleStates(userId);
}
@@ -246,6 +258,17 @@ public class UsageStatsService extends SystemService implements
}
}
+ private class PackageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)
+ || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ clearCarrierPrivilegedApps();
+ }
+ }
+ }
+
private class DeviceStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -296,9 +319,8 @@ public class UsageStatsService extends SystemService implements
private void initializeDefaultsForSystemApps(int userId) {
Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
final long elapsedRealtime = SystemClock.elapsedRealtime();
- List<PackageInfo> packages = getContext().getPackageManager().getInstalledPackagesAsUser(
- PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
+ PackageManager.MATCH_DISABLED_COMPONENTS,
userId);
final int packageCount = packages.size();
for (int i = 0; i < packageCount; i++) {
@@ -398,47 +420,59 @@ public class UsageStatsService extends SystemService implements
}
}
- /** Check all running users' or specified user's apps to see if they enter an idle state. */
- void checkIdleStates(int checkUserId) {
+ /**
+ * Check all running users' or specified user's apps to see if they enter an idle state.
+ * @return Returns whether checking should continue periodically.
+ */
+ boolean checkIdleStates(int checkUserId) {
if (!mAppIdleEnabled) {
- return;
+ return false;
}
- final int[] userIds;
+ final int[] runningUserIds;
try {
- if (checkUserId == UserHandle.USER_ALL) {
- userIds = ActivityManagerNative.getDefault().getRunningUserIds();
- } else {
- userIds = new int[] { checkUserId };
+ runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
+ if (checkUserId != UserHandle.USER_ALL
+ && !ArrayUtils.contains(runningUserIds, checkUserId)) {
+ return false;
}
} catch (RemoteException re) {
- return;
+ return false;
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
- for (int i = 0; i < userIds.length; i++) {
- final int userId = userIds[i];
- List<PackageInfo> packages =
- getContext().getPackageManager().getInstalledPackagesAsUser(
- PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_UNINSTALLED_PACKAGES,
- userId);
- synchronized (mLock) {
- final int packageCount = packages.size();
- for (int p = 0; p < packageCount; p++) {
- final PackageInfo pi = packages.get(p);
- final String packageName = pi.packageName;
- final boolean isIdle = isAppIdleFiltered(packageName,
- UserHandle.getAppId(pi.applicationInfo.uid),
- userId, elapsedRealtime);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
- userId, isIdle ? 1 : 0, packageName));
- if (isIdle) {
+ for (int i = 0; i < runningUserIds.length; i++) {
+ final int userId = runningUserIds[i];
+ if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
+ continue;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Checking idle state for user " + userId);
+ }
+ List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
+ PackageManager.MATCH_DISABLED_COMPONENTS,
+ userId);
+ final int packageCount = packages.size();
+ for (int p = 0; p < packageCount; p++) {
+ final PackageInfo pi = packages.get(p);
+ final String packageName = pi.packageName;
+ final boolean isIdle = isAppIdleFiltered(packageName,
+ UserHandle.getAppId(pi.applicationInfo.uid),
+ userId, elapsedRealtime);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
+ userId, isIdle ? 1 : 0, packageName));
+ if (isIdle) {
+ synchronized (mLock) {
mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
}
}
}
}
+ if (DEBUG) {
+ Slog.d(TAG, "checkIdleStates took "
+ + (SystemClock.elapsedRealtime() - elapsedRealtime));
+ }
+ return true;
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -459,7 +493,7 @@ public class UsageStatsService extends SystemService implements
private void notifyBatteryStats(String packageName, int userId, boolean idle) {
try {
- final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
+ final int uid = mPackageManager.getPackageUidAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
if (idle) {
mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
@@ -468,7 +502,7 @@ public class UsageStatsService extends SystemService implements
mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
packageName, uid);
}
- } catch (RemoteException re) {
+ } catch (NameNotFoundException | RemoteException e) {
}
}
@@ -592,7 +626,7 @@ public class UsageStatsService extends SystemService implements
// Only force the sync adapters to active if the provider is not in the same package and
// the sync adapter is a system package.
try {
- PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo(
+ PackageInfo pi = mPackageManager.getPackageInfoAsUser(
packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
if (pi == null || pi.applicationInfo == null) {
continue;
@@ -600,7 +634,7 @@ public class UsageStatsService extends SystemService implements
if (!packageName.equals(providerPkgName)) {
forceIdleState(packageName, userId, false);
}
- } catch (RemoteException re) {
+ } catch (NameNotFoundException e) {
// Shouldn't happen
}
}
@@ -725,7 +759,7 @@ public class UsageStatsService extends SystemService implements
int getAppId(String packageName) {
try {
- ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(packageName,
+ ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS);
return ai.uid;
@@ -772,12 +806,8 @@ public class UsageStatsService extends SystemService implements
}
} catch (RemoteException re) {
}
- // TODO: Optimize this check
- if (isActiveDeviceAdmin(packageName, userId)) {
- return false;
- }
- if (isCarrierApp(packageName)) {
+ if (isActiveDeviceAdmin(packageName, userId)) {
return false;
}
@@ -790,7 +820,17 @@ public class UsageStatsService extends SystemService implements
return false;
}
- return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
+ if (!isAppIdleUnfiltered(packageName, userId, elapsedRealtime)) {
+ return false;
+ }
+
+ // Check this last, as it is the most expensive check
+ // TODO: Optimize this by fetching the carrier privileged apps ahead of time
+ if (isCarrierApp(packageName)) {
+ return false;
+ }
+
+ return true;
}
int[] getIdleUidsForUser(int userId) {
@@ -803,7 +843,7 @@ public class UsageStatsService extends SystemService implements
List<ApplicationInfo> apps;
try {
ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
- .getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ .getInstalledApplications(/* flags= */ 0, userId);
if (slice == null) {
return new int[0];
}
@@ -833,7 +873,9 @@ public class UsageStatsService extends SystemService implements
uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
}
}
-
+ if (DEBUG) {
+ Slog.d(TAG, "getIdleUids took " + (SystemClock.elapsedRealtime() - elapsedRealtime));
+ }
int numIdle = 0;
for (int i = uidStates.size() - 1; i >= 0; i--) {
int value = uidStates.valueAt(i);
@@ -865,21 +907,34 @@ public class UsageStatsService extends SystemService implements
private boolean isActiveDeviceAdmin(String packageName, int userId) {
DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
if (dpm == null) return false;
- List<ComponentName> components = dpm.getActiveAdminsAsUser(userId);
- if (components == null) return false;
- final int size = components.size();
- for (int i = 0; i < size; i++) {
- if (components.get(i).getPackageName().equals(packageName)) {
- return true;
+ return dpm.packageHasActiveAdmins(packageName, userId);
+ }
+
+ private boolean isCarrierApp(String packageName) {
+ synchronized (mLock) {
+ if (mCarrierPrivilegedApps == null) {
+ fetchCarrierPrivilegedAppsLocked();
}
}
- return false;
+ return mCarrierPrivilegedApps.contains(packageName);
}
- private boolean isCarrierApp(String packageName) {
- TelephonyManager telephonyManager = getContext().getSystemService(TelephonyManager.class);
- return telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ void clearCarrierPrivilegedApps() {
+ if (DEBUG) {
+ Slog.i(TAG, "Clearing carrier privileged apps list");
+ }
+ synchronized (mLock) {
+ mCarrierPrivilegedApps = null; // Need to be refetched.
+ }
+ }
+
+ private void fetchCarrierPrivilegedAppsLocked() {
+ TelephonyManager telephonyManager =
+ getContext().getSystemService(TelephonyManager.class);
+ mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
+ if (DEBUG) {
+ Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
+ }
}
private boolean isActiveNetworkScorer(String packageName) {
@@ -950,6 +1005,9 @@ public class UsageStatsService extends SystemService implements
}
pw.println();
+ pw.println("Carrier privileged apps: " + mCarrierPrivilegedApps);
+
+ pw.println();
pw.println("Settings:");
pw.print(" mAppIdleDurationMillis=");
@@ -1011,10 +1069,11 @@ public class UsageStatsService extends SystemService implements
break;
case MSG_CHECK_IDLE_STATES:
- checkIdleStates(msg.arg1);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- MSG_CHECK_IDLE_STATES, msg.arg1, 0),
- mCheckIdleIntervalMillis);
+ if (checkIdleStates(msg.arg1)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+ mCheckIdleIntervalMillis);
+ }
break;
case MSG_ONE_TIME_CHECK_IDLE_STATES:
@@ -1243,6 +1302,17 @@ public class UsageStatsService extends SystemService implements
}
@Override
+ public void onCarrierPrivilegedAppsChanged() {
+ if (DEBUG) {
+ Slog.i(TAG, "Carrier privileged apps changed");
+ }
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_CARRIER_SERVICES,
+ "onCarrierPrivilegedAppsChanged can only be called by privileged apps.");
+ UsageStatsService.this.clearCarrierPrivilegedApps();
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
index 18a5d59543e4..f7cd6a3d2245 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
@@ -54,6 +54,7 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper {
private static final String CREATE_TABLE_ST_SOUND_MODEL = "CREATE TABLE "
+ GenericSoundModelContract.TABLE + "("
+ GenericSoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
+ + GenericSoundModelContract.KEY_VENDOR_UUID + " TEXT,"
+ GenericSoundModelContract.KEY_DATA + " BLOB" + " )";
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 354075ea1762..e05f00d646f0 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,12 +16,16 @@
package com.android.server.soundtrigger;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
@@ -29,6 +33,7 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.PowerManager;
@@ -40,9 +45,16 @@ import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.UUID;
/**
- * Helper for {@link SoundTrigger} APIs.
+ * Helper for {@link SoundTrigger} APIs. Supports two types of models:
+ * (i) A voice model which is exported via the {@link VoiceInteractionService}. There can only be
+ * a single voice model running on the DSP at any given time.
+ *
+ * (ii) Generic sound-trigger models: Supports multiple of these.
+ *
* Currently this just acts as an abstraction over all SoundTrigger API calls.
*
* @hide
@@ -62,7 +74,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private static final int INVALID_VALUE = Integer.MIN_VALUE;
/** The {@link ModuleProperties} for the system, or null if none exists. */
- final ModuleProperties moduleProperties;
+ final ModuleProperties mModuleProperties;
/** The properties for the DSP module */
private SoundTriggerModule mModule;
@@ -72,21 +84,36 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private final PhoneStateListener mPhoneStateListener;
private final PowerManager mPowerManager;
- // TODO: Since many layers currently only deal with one recognition
+ // TODO: Since the voice layer currently only handles one recognition
// we simplify things by assuming one listener here too.
- private IRecognitionStatusCallback mActiveListener;
+ private IRecognitionStatusCallback mKeyphraseListener;
+
+ // The SoundTriggerManager layer handles multiple generic recognition models. We store the
+ // ModelData here in a hashmap.
+ private final HashMap<UUID, ModelData> mGenericModelDataMap;
+
+ // Note: KeyphraseId is not really used.
private int mKeyphraseId = INVALID_VALUE;
- private int mCurrentSoundModelHandle = INVALID_VALUE;
+
+ // Current voice sound model handle. We only allow one voice model to run at any given time.
+ private int mCurrentKeyphraseModelHandle = INVALID_VALUE;
private KeyphraseSoundModel mCurrentSoundModel = null;
// FIXME: Ideally this should not be stored if allowMultipleTriggers happens at a lower layer.
private RecognitionConfig mRecognitionConfig = null;
+
+ // Whether we are requesting recognition to start.
private boolean mRequested = false;
private boolean mCallActive = false;
private boolean mIsPowerSaveMode = false;
// Indicates if the native sound trigger service is disabled or not.
// This is an indirect indication of the microphone being open in some other application.
private boolean mServiceDisabled = false;
- private boolean mStarted = false;
+
+ // Whether we have ANY recognition (keyphrase or generic) running.
+ private boolean mRecognitionRunning = false;
+
+ // Keeps track of whether the keyphrase recognition is running.
+ private boolean mKeyphraseStarted = false;
private boolean mRecognitionAborted = false;
private PowerSaveModeListener mPowerSaveModeListener;
@@ -96,14 +123,89 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mContext = context;
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mGenericModelDataMap = new HashMap<UUID, ModelData>();
mPhoneStateListener = new MyCallStateListener();
if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
- moduleProperties = null;
+ mModuleProperties = null;
mModule = null;
} else {
// TODO: Figure out how to determine which module corresponds to the DSP hardware.
- moduleProperties = modules.get(0);
+ mModuleProperties = modules.get(0);
+ }
+ }
+
+ /**
+ * Starts recognition for the given generic sound model ID.
+ *
+ * @param soundModel The sound model to use for recognition.
+ * @param listener The listener for the recognition events related to the given keyphrase.
+ * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+ */
+ int startGenericRecognition(UUID modelId, GenericSoundModel soundModel,
+ IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
+ if (soundModel == null || callback == null || recognitionConfig == null) {
+ Slog.w(TAG, "Passed in bad data to startGenericRecognition().");
+ return STATUS_ERROR;
+ }
+
+ synchronized (mLock) {
+
+ if (mModuleProperties == null) {
+ Slog.w(TAG, "Attempting startRecognition without the capability");
+ return STATUS_ERROR;
+ }
+
+ if (mModule == null) {
+ mModule = SoundTrigger.attachModule(mModuleProperties.id, this, null);
+ if (mModule == null) {
+ Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
+ return STATUS_ERROR;
+ }
+ }
+
+ // Initialize power save, call active state monitoring logic.
+ if (!mRecognitionRunning) {
+ initializeTelephonyAndPowerStateListeners();
+ }
+
+ // Fetch a ModelData instance from the hash map. Creates a new one if none
+ // exists.
+ ModelData modelData = getOrCreateGenericModelData(modelId);
+
+ IRecognitionStatusCallback oldCallback = modelData.getCallback();
+ if (oldCallback != null) {
+ Slog.w(TAG, "Canceling previous recognition for model id: " + modelId);
+ try {
+ oldCallback.onError(STATUS_ERROR);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onDetectionStopped", e);
+ }
+ modelData.clearCallback();
+ }
+
+ // Load the model if its not loaded.
+ if (!modelData.isModelLoaded()) {
+ // Load the model
+ int[] handle = new int[] { INVALID_VALUE };
+ int status = mModule.loadSoundModel(soundModel, handle);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "loadSoundModel call failed with " + status);
+ return status;
+ }
+ if (handle[0] == INVALID_VALUE) {
+ Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
+ return STATUS_ERROR;
+ }
+ modelData.setHandle(handle[0]);
+ modelData.setLoaded();
+ Slog.d(TAG, "Generic sound model loaded with handle:" + handle[0]);
+ }
+ modelData.setCallback(callback);
+ modelData.setRecognitionConfig(recognitionConfig);
+
+ // Don't notify for synchronous calls.
+ return startGenericRecognitionLocked(modelData, false);
}
}
@@ -116,7 +218,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
* @param listener The listener for the recognition events related to the given keyphrase.
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int startRecognition(int keyphraseId,
+ int startKeyphraseRecognition(int keyphraseId,
KeyphraseSoundModel soundModel,
IRecognitionStatusCallback listener,
RecognitionConfig recognitionConfig) {
@@ -126,41 +228,29 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
synchronized (mLock) {
if (DBG) {
- Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
+ Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
+ " soundModel=" + soundModel + ", listener=" + listener.asBinder()
+ ", recognitionConfig=" + recognitionConfig);
- Slog.d(TAG, "moduleProperties=" + moduleProperties);
+ Slog.d(TAG, "moduleProperties=" + mModuleProperties);
Slog.d(TAG, "current listener="
- + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
- Slog.d(TAG, "current SoundModel handle=" + mCurrentSoundModelHandle);
+ + (mKeyphraseListener == null ? "null" : mKeyphraseListener.asBinder()));
+ Slog.d(TAG, "current SoundModel handle=" + mCurrentKeyphraseModelHandle);
Slog.d(TAG, "current SoundModel UUID="
+ (mCurrentSoundModel == null ? null : mCurrentSoundModel.uuid));
}
- if (!mStarted) {
- // Get the current call state synchronously for the first recognition.
- mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
- // Register for call state changes when the first call to start recognition occurs.
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
- // Register for power saver mode changes when the first call to start recognition
- // occurs.
- if (mPowerSaveModeListener == null) {
- mPowerSaveModeListener = new PowerSaveModeListener();
- mContext.registerReceiver(mPowerSaveModeListener,
- new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
- }
- mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
+ if (!mRecognitionRunning) {
+ initializeTelephonyAndPowerStateListeners();
}
- if (moduleProperties == null) {
- Slog.w(TAG, "Attempting startRecognition without the capability");
+ if (mModuleProperties == null) {
+ Slog.w(TAG, "Attempting startKeyphraseRecognition without the capability");
return STATUS_ERROR;
}
if (mModule == null) {
- mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
+ mModule = SoundTrigger.attachModule(mModuleProperties.id, this, null);
if (mModule == null) {
- Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
+ Slog.w(TAG, "startKeyphraseRecognition cannot attach to sound trigger module");
return STATUS_ERROR;
}
}
@@ -168,32 +258,32 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Unload the previous model if the current one isn't invalid
// and, it's not the same as the new one.
// This helps use cache and reuse the model and just start/stop it when necessary.
- if (mCurrentSoundModelHandle != INVALID_VALUE
+ if (mCurrentKeyphraseModelHandle != INVALID_VALUE
&& !soundModel.equals(mCurrentSoundModel)) {
Slog.w(TAG, "Unloading previous sound model");
- int status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
+ int status = mModule.unloadSoundModel(mCurrentKeyphraseModelHandle);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "unloadSoundModel call failed with " + status);
}
- internalClearSoundModelLocked();
- mStarted = false;
+ internalClearKeyphraseSoundModelLocked();
+ mKeyphraseStarted = false;
}
// If the previous recognition was by a different listener,
// Notify them that it was stopped.
- if (mActiveListener != null && mActiveListener.asBinder() != listener.asBinder()) {
+ if (mKeyphraseListener != null && mKeyphraseListener.asBinder() != listener.asBinder()) {
Slog.w(TAG, "Canceling previous recognition");
try {
- mActiveListener.onError(STATUS_ERROR);
+ mKeyphraseListener.onError(STATUS_ERROR);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onDetectionStopped", e);
}
- mActiveListener = null;
+ mKeyphraseListener = null;
}
// Load the sound model if the current one is null.
- int soundModelHandle = mCurrentSoundModelHandle;
- if (mCurrentSoundModelHandle == INVALID_VALUE
+ int soundModelHandle = mCurrentKeyphraseModelHandle;
+ if (mCurrentKeyphraseModelHandle == INVALID_VALUE
|| mCurrentSoundModel == null) {
int[] handle = new int[] { INVALID_VALUE };
int status = mModule.loadSoundModel(soundModel, handle);
@@ -213,18 +303,84 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Start the recognition.
mRequested = true;
mKeyphraseId = keyphraseId;
- mCurrentSoundModelHandle = soundModelHandle;
+ mCurrentKeyphraseModelHandle = soundModelHandle;
mCurrentSoundModel = soundModel;
mRecognitionConfig = recognitionConfig;
// Register the new listener. This replaces the old one.
// There can only be a maximum of one active listener at any given time.
- mActiveListener = listener;
+ mKeyphraseListener = listener;
return updateRecognitionLocked(false /* don't notify for synchronous calls */);
}
}
/**
+ * Stops recognition for the given generic sound model.
+ *
+ * @param modelId The identifier of the generic sound model for which
+ * the recognition is to be stopped.
+ * @param listener The listener for the recognition events related to the given sound model.
+ *
+ * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+ */
+ int stopGenericRecognition(UUID modelId, IRecognitionStatusCallback listener) {
+ if (listener == null) {
+ return STATUS_ERROR;
+ }
+
+ synchronized (mLock) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "Attempting stopRecognition on invalid model with id:" + modelId);
+ return STATUS_ERROR;
+ }
+
+ IRecognitionStatusCallback currentCallback = modelData.getCallback();
+ if (DBG) {
+ Slog.d(TAG, "stopRecognition for modelId=" + modelId
+ + ", listener=" + listener.asBinder());
+ Slog.d(TAG, "current callback ="
+ + (currentCallback == null ? "null" : currentCallback.asBinder()));
+ }
+
+ if (mModuleProperties == null || mModule == null) {
+ Slog.w(TAG, "Attempting stopRecognition without the capability");
+ return STATUS_ERROR;
+ }
+
+ if (currentCallback == null || !modelData.isModelStarted()) {
+ // startGenericRecognition hasn't been called or it failed.
+ Slog.w(TAG, "Attempting stopGenericRecognition without a successful" +
+ " startGenericRecognition");
+ return STATUS_ERROR;
+ }
+ if (currentCallback.asBinder() != listener.asBinder()) {
+ // We don't allow a different listener to stop the recognition than the one
+ // that started it.
+ Slog.w(TAG, "Attempting stopGenericRecognition for another recognition");
+ return STATUS_ERROR;
+ }
+
+ int status = stopGenericRecognitionLocked(modelData,
+ false /* don't notify for synchronous calls */);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "stopGenericRecognition failed: " + status);
+ return status;
+ }
+
+ // We leave the sound model loaded but not started, this helps us when we start
+ // back.
+ // Also clear the internal state once the recognition has been stopped.
+ modelData.setLoaded();
+ modelData.clearCallback();
+ if (!computeRecognitionRunning()) {
+ internalClearGlobalStateLocked();
+ }
+ return status;
+ }
+ }
+
+ /**
* Stops recognition for the given {@link Keyphrase} if a recognition is
* currently active.
*
@@ -234,7 +390,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
*
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
- int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
+ int stopKeyphraseRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
if (listener == null) {
return STATUS_ERROR;
}
@@ -244,20 +400,20 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId
+ ", listener=" + listener.asBinder());
Slog.d(TAG, "current listener="
- + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
+ + (mKeyphraseListener == null ? "null" : mKeyphraseListener.asBinder()));
}
- if (moduleProperties == null || mModule == null) {
+ if (mModuleProperties == null || mModule == null) {
Slog.w(TAG, "Attempting stopRecognition without the capability");
return STATUS_ERROR;
}
- if (mActiveListener == null) {
+ if (mKeyphraseListener == null) {
// startRecognition hasn't been called or it failed.
Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
return STATUS_ERROR;
}
- if (mActiveListener.asBinder() != listener.asBinder()) {
+ if (mKeyphraseListener.asBinder() != listener.asBinder()) {
// We don't allow a different listener to stop the recognition than the one
// that started it.
Slog.w(TAG, "Attempting stopRecognition for another recognition");
@@ -274,7 +430,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// We leave the sound model loaded but not started, this helps us when we start
// back.
// Also clear the internal state once the recognition has been stopped.
- internalClearStateLocked();
+ internalClearKeyphraseStateLocked();
+ internalClearGlobalStateLocked();
return status;
}
}
@@ -284,38 +441,116 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
*/
void stopAllRecognitions() {
synchronized (mLock) {
- if (moduleProperties == null || mModule == null) {
+ if (mModuleProperties == null || mModule == null) {
return;
}
- if (mCurrentSoundModelHandle == INVALID_VALUE) {
- return;
+ // Stop Keyphrase recognition if one exists.
+ if (mCurrentKeyphraseModelHandle != INVALID_VALUE) {
+
+ mRequested = false;
+ int status = updateRecognitionLocked(
+ false /* don't notify for synchronous calls */);
+ internalClearKeyphraseStateLocked();
}
- mRequested = false;
- int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
- internalClearStateLocked();
+ // Stop all generic recognition models.
+ for (ModelData model : mGenericModelDataMap.values()) {
+ if (model.isModelStarted()) {
+ int status = stopGenericRecognitionLocked(model,
+ false /* do not notify for synchronous calls */);
+ if (status != STATUS_OK) {
+ // What else can we do if there is an error here.
+ Slog.w(TAG, "Error stopping generic model: " + model.getHandle());
+ }
+ model.clearState();
+ model.clearCallback();
+ }
+ }
+ internalClearGlobalStateLocked();
}
}
public ModuleProperties getModuleProperties() {
- return moduleProperties;
+ return mModuleProperties;
+ }
+
+ int unloadKeyphraseSoundModel(int keyphraseId) {
+ if (mModule == null || mCurrentKeyphraseModelHandle == INVALID_VALUE) {
+ return STATUS_ERROR;
+ }
+ if (mKeyphraseId != keyphraseId) {
+ Slog.w(TAG, "Given sound model is not the one loaded.");
+ return STATUS_ERROR;
+ }
+
+ synchronized (mLock) {
+ // Stop recognition if it's the current one.
+ mRequested = false;
+ int status = updateRecognitionLocked(false /* don't notify */);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
+ }
+
+ status = mModule.unloadSoundModel(mCurrentKeyphraseModelHandle);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status);
+ }
+ internalClearKeyphraseSoundModelLocked();
+ return status;
+ }
+ }
+
+ int unloadGenericSoundModel(UUID modelId) {
+ if (modelId == null || mModule == null) {
+ return STATUS_ERROR;
+ }
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" + modelId);
+ return STATUS_ERROR;
+ }
+ synchronized (mLock) {
+ if (!modelData.isModelLoaded()) {
+ // Nothing to do here.
+ Slog.i(TAG, "Unload: Given generic model is not loaded:" + modelId);
+ return STATUS_OK;
+ }
+ if (modelData.isModelStarted()) {
+ int status = stopGenericRecognitionLocked(modelData,
+ false /* don't notify for synchronous calls */);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "stopGenericRecognition failed: " + status);
+ }
+ }
+
+ int status = mModule.unloadSoundModel(modelData.getHandle());
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
+ Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
+ }
+ mGenericModelDataMap.remove(modelId);
+ if (DBG) dumpGenericModelState();
+ return status;
+ }
}
//---- SoundTrigger.StatusListener methods
@Override
public void onRecognition(RecognitionEvent event) {
- if (event == null || !(event instanceof KeyphraseRecognitionEvent)) {
- Slog.w(TAG, "Invalid recognition event!");
+ if (event == null) {
+ Slog.w(TAG, "Null recognition event!");
+ return;
+ }
+
+ if (!(event instanceof KeyphraseRecognitionEvent) &&
+ !(event instanceof GenericRecognitionEvent)) {
+ Slog.w(TAG, "Invalid recognition event type (not one of generic or keyphrase) !");
return;
}
if (DBG) Slog.d(TAG, "onRecognition: " + event);
synchronized (mLock) {
- if (mActiveListener == null) {
- Slog.w(TAG, "received onRecognition event without any listener for it");
- return;
- }
switch (event.status) {
// Fire aborts/failures to all listeners since it's not tied to a keyphrase.
case SoundTrigger.RECOGNITION_STATUS_ABORT:
@@ -325,12 +560,60 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
onRecognitionFailureLocked();
break;
case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
- onRecognitionSuccessLocked((KeyphraseRecognitionEvent) event);
+
+ if (isKeyphraseRecognitionEvent(event)) {
+ onKeyphraseRecognitionSuccessLocked((KeyphraseRecognitionEvent) event);
+ } else {
+ onGenericRecognitionSuccessLocked((GenericRecognitionEvent) event);
+ }
+
break;
}
}
}
+ private boolean isKeyphraseRecognitionEvent(RecognitionEvent event) {
+ return event instanceof KeyphraseRecognitionEvent;
+ }
+
+ private void onGenericRecognitionSuccessLocked(GenericRecognitionEvent event) {
+ if (event.status != SoundTrigger.RECOGNITION_STATUS_SUCCESS) {
+ return;
+ }
+ ModelData model = getModelDataFor(event.soundModelHandle);
+ if (model == null) {
+ Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
+ event.soundModelHandle);
+ return;
+ }
+
+ IRecognitionStatusCallback callback = model.getCallback();
+ if (callback == null) {
+ Slog.w(TAG, "Generic recognition event: Null callback for model handle: " +
+ event.soundModelHandle);
+ return;
+ }
+
+ try {
+ callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onGenericSoundTriggerDetected", e);
+ }
+
+ model.setStopped();
+ RecognitionConfig config = model.getRecognitionConfig();
+ if (config == null) {
+ Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: " +
+ event.soundModelHandle);
+ return;
+ }
+
+ // TODO: Remove this block if the lower layer supports multiple triggers.
+ if (config.allowMultipleTriggers) {
+ startGenericRecognitionLocked(model, true /* notify */);
+ }
+ }
+
@Override
public void onSoundModelUpdate(SoundModelEvent event) {
if (event == null) {
@@ -399,18 +682,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private void onRecognitionFailureLocked() {
Slog.w(TAG, "Recognition failure");
try {
- if (mActiveListener != null) {
- mActiveListener.onError(STATUS_ERROR);
+ if (mKeyphraseListener != null) {
+ mKeyphraseListener.onError(STATUS_ERROR);
}
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onError", e);
} finally {
- internalClearStateLocked();
+ internalClearKeyphraseStateLocked();
+ internalClearGlobalStateLocked();
}
}
- private void onRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
+ private void onKeyphraseRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
Slog.i(TAG, "Recognition success");
+
+ if (mKeyphraseListener == null) {
+ Slog.w(TAG, "received onRecognition event without any listener for it");
+ return;
+ }
+
KeyphraseRecognitionExtra[] keyphraseExtras =
((KeyphraseRecognitionEvent) event).keyphraseExtras;
if (keyphraseExtras == null || keyphraseExtras.length == 0) {
@@ -424,14 +714,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
try {
- if (mActiveListener != null) {
- mActiveListener.onDetected((KeyphraseRecognitionEvent) event);
+ if (mKeyphraseListener != null) {
+ mKeyphraseListener.onKeyphraseDetected((KeyphraseRecognitionEvent) event);
}
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onDetected", e);
+ Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
}
- mStarted = false;
+ mKeyphraseStarted = false;
mRequested = mRecognitionConfig.allowMultipleTriggers;
// TODO: Remove this block if the lower layer supports multiple triggers.
if (mRequested) {
@@ -441,14 +731,16 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private void onServiceDiedLocked() {
try {
- if (mActiveListener != null) {
- mActiveListener.onError(SoundTrigger.STATUS_DEAD_OBJECT);
+ if (mKeyphraseListener != null) {
+ mKeyphraseListener.onError(SoundTrigger.STATUS_DEAD_OBJECT);
}
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onError", e);
} finally {
- internalClearSoundModelLocked();
- internalClearStateLocked();
+ internalClearKeyphraseSoundModelLocked();
+ internalClearKeyphraseStateLocked();
+ internalClearGenericModelStateLocked();
+ internalClearGlobalStateLocked();
if (mModule != null) {
mModule.detach();
mModule = null;
@@ -457,14 +749,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
private int updateRecognitionLocked(boolean notify) {
- if (mModule == null || moduleProperties == null
- || mCurrentSoundModelHandle == INVALID_VALUE || mActiveListener == null) {
+ if (mModule == null || mModuleProperties == null
+ || mCurrentKeyphraseModelHandle == INVALID_VALUE || mKeyphraseListener == null) {
// Nothing to do here.
return STATUS_OK;
}
boolean start = mRequested && !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
- if (start == mStarted) {
+ if (start == mKeyphraseStarted) {
// No-op.
return STATUS_OK;
}
@@ -472,23 +764,24 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// See if the recognition needs to be started.
if (start) {
// Start recognition.
- int status = mModule.startRecognition(mCurrentSoundModelHandle, mRecognitionConfig);
+ int status = mModule.startRecognition(mCurrentKeyphraseModelHandle,
+ mRecognitionConfig);
if (status != SoundTrigger.STATUS_OK) {
- Slog.w(TAG, "startRecognition failed with " + status);
+ Slog.w(TAG, "startKeyphraseRecognition failed with " + status);
// Notify of error if needed.
if (notify) {
try {
- mActiveListener.onError(status);
+ mKeyphraseListener.onError(status);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onError", e);
}
}
} else {
- mStarted = true;
+ mKeyphraseStarted = true;
// Notify of resume if needed.
if (notify) {
try {
- mActiveListener.onRecognitionResumed();
+ mKeyphraseListener.onRecognitionResumed();
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
}
@@ -499,7 +792,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Stop recognition (only if we haven't been aborted).
int status = STATUS_OK;
if (!mRecognitionAborted) {
- status = mModule.stopRecognition(mCurrentSoundModelHandle);
+ status = mModule.stopRecognition(mCurrentKeyphraseModelHandle);
} else {
mRecognitionAborted = false;
}
@@ -507,17 +800,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
Slog.w(TAG, "stopRecognition call failed with " + status);
if (notify) {
try {
- mActiveListener.onError(status);
+ mKeyphraseListener.onError(status);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onError", e);
}
}
} else {
- mStarted = false;
+ mKeyphraseStarted = false;
// Notify of pause if needed.
if (notify) {
try {
- mActiveListener.onRecognitionPaused();
+ mKeyphraseListener.onRecognitionPaused();
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
}
@@ -527,14 +820,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
- private void internalClearStateLocked() {
- mStarted = false;
- mRequested = false;
-
- mKeyphraseId = INVALID_VALUE;
- mRecognitionConfig = null;
- mActiveListener = null;
-
+ // internalClearGlobalStateLocked() gets split into two routines. Cleanup that is
+ // specific to keyphrase sound models named as internalClearKeyphraseStateLocked() and
+ // internalClearGlobalStateLocked() for global state. The global cleanup routine will be used
+ // by the cleanup happening with the generic sound models.
+ private void internalClearGlobalStateLocked() {
// Unregister from call state changes.
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
@@ -545,8 +835,27 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
- private void internalClearSoundModelLocked() {
- mCurrentSoundModelHandle = INVALID_VALUE;
+ private void internalClearKeyphraseStateLocked() {
+ mKeyphraseStarted = false;
+ mRequested = false;
+
+ mKeyphraseId = INVALID_VALUE;
+ mRecognitionConfig = null;
+ mKeyphraseListener = null;
+ }
+
+ private void internalClearGenericModelStateLocked() {
+ for (UUID modelId : mGenericModelDataMap.keySet()) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ modelData.clearState();
+ modelData.clearCallback();
+ }
+ }
+
+ // This routine is a replacement for internalClearSoundModelLocked(). However, we
+ // should see why this should be different from internalClearKeyphraseStateLocked().
+ private void internalClearKeyphraseSoundModelLocked() {
+ mCurrentKeyphraseModelHandle = INVALID_VALUE;
mCurrentSoundModel = null;
}
@@ -577,19 +886,275 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mLock) {
pw.print(" module properties=");
- pw.println(moduleProperties == null ? "null" : moduleProperties);
+ pw.println(mModuleProperties == null ? "null" : mModuleProperties);
pw.print(" keyphrase ID="); pw.println(mKeyphraseId);
- pw.print(" sound model handle="); pw.println(mCurrentSoundModelHandle);
+ pw.print(" sound model handle="); pw.println(mCurrentKeyphraseModelHandle);
pw.print(" sound model UUID=");
pw.println(mCurrentSoundModel == null ? "null" : mCurrentSoundModel.uuid);
pw.print(" current listener=");
- pw.println(mActiveListener == null ? "null" : mActiveListener.asBinder());
+ pw.println(mKeyphraseListener == null ? "null" : mKeyphraseListener.asBinder());
pw.print(" requested="); pw.println(mRequested);
- pw.print(" started="); pw.println(mStarted);
+ pw.print(" started="); pw.println(mKeyphraseStarted);
pw.print(" call active="); pw.println(mCallActive);
pw.print(" power save mode active="); pw.println(mIsPowerSaveMode);
pw.print(" service disabled="); pw.println(mServiceDisabled);
}
}
+
+ private void initializeTelephonyAndPowerStateListeners() {
+ // Get the current call state synchronously for the first recognition.
+ mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
+
+ // Register for call state changes when the first call to start recognition occurs.
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+ // Register for power saver mode changes when the first call to start recognition
+ // occurs.
+ if (mPowerSaveModeListener == null) {
+ mPowerSaveModeListener = new PowerSaveModeListener();
+ mContext.registerReceiver(mPowerSaveModeListener,
+ new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+ }
+ mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
+ }
+
+ private ModelData getOrCreateGenericModelData(UUID modelId) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ if (modelData == null) {
+ modelData = new ModelData(modelId);
+ modelData.setTypeGeneric();
+ mGenericModelDataMap.put(modelId, modelData);
+ }
+ return modelData;
+ }
+
+ // Instead of maintaining a second hashmap of modelHandle -> ModelData, we just
+ // iterate through to find the right object (since we don't expect 100s of models
+ // to be stored).
+ private ModelData getModelDataFor(int modelHandle) {
+ // Fetch ModelData object corresponding to the model handle.
+ for (ModelData model : mGenericModelDataMap.values()) {
+ if (model.getHandle() == modelHandle) {
+ return model;
+ }
+ }
+ return null;
+ }
+
+ // Whether we are allowed to run any recognition at all. The conditions that let us run
+ // a recognition include: no active phone call or not being in a power save mode. Also,
+ // the native service should be enabled.
+ private boolean isRecognitionAllowed() {
+ return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
+ }
+
+ private int startGenericRecognitionLocked(ModelData modelData, boolean notify) {
+ IRecognitionStatusCallback callback = modelData.getCallback();
+ int handle = modelData.getHandle();
+ RecognitionConfig config = modelData.getRecognitionConfig();
+ if (callback == null || handle == INVALID_VALUE || config == null) {
+ // Nothing to do here.
+ Slog.w(TAG, "startGenericRecognition: Bad data passed in.");
+ return STATUS_ERROR;
+ }
+
+ if (!isRecognitionAllowed()) {
+ // Nothing to do here.
+ Slog.w(TAG, "startGenericRecognition requested but not allowed.");
+ return STATUS_OK;
+ }
+
+ int status = mModule.startRecognition(handle, config);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "startGenericRecognition failed with " + status);
+ // Notify of error if needed.
+ if (notify) {
+ try {
+ callback.onError(status);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onError", e);
+ }
+ }
+ } else {
+ Slog.i(TAG, "startRecognition successful.");
+ modelData.setStarted();
+ // Notify of resume if needed.
+ if (notify) {
+ try {
+ callback.onRecognitionResumed();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
+ }
+ }
+ }
+ if (DBG) dumpGenericModelState();
+ return status;
+ }
+
+ private int stopGenericRecognitionLocked(ModelData modelData, boolean notify) {
+ IRecognitionStatusCallback callback = modelData.getCallback();
+
+ // Stop recognition (only if we haven't been aborted).
+ int status = mModule.stopRecognition(modelData.getHandle());
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "stopRecognition call failed with " + status);
+ if (notify) {
+ try {
+ callback.onError(status);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onError", e);
+ }
+ }
+ } else {
+ modelData.setStopped();
+ // Notify of pause if needed.
+ if (notify) {
+ try {
+ callback.onRecognitionPaused();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
+ }
+ }
+ }
+ if (DBG) dumpGenericModelState();
+ return status;
+ }
+
+ private void dumpGenericModelState() {
+ for (UUID modelId : mGenericModelDataMap.keySet()) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ Slog.i(TAG, "Model :" + modelData.toString());
+ }
+ }
+
+ // Computes whether we have any recognition running at all (voice or generic). Sets
+ // the mRecognitionRunning variable with the result.
+ private boolean computeRecognitionRunning() {
+ synchronized (mLock) {
+ if (mModuleProperties == null || mModule == null) {
+ mRecognitionRunning = false;
+ return mRecognitionRunning;
+ }
+ if (mKeyphraseListener != null &&
+ mKeyphraseStarted &&
+ mCurrentKeyphraseModelHandle != INVALID_VALUE &&
+ mCurrentSoundModel != null) {
+ mRecognitionRunning = true;
+ return mRecognitionRunning;
+ }
+ for (UUID modelId : mGenericModelDataMap.keySet()) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ if (modelData.isModelStarted()) {
+ mRecognitionRunning = true;
+ return mRecognitionRunning;
+ }
+ }
+ mRecognitionRunning = false;
+ }
+ return mRecognitionRunning;
+ }
+
+ // This class encapsulates the callbacks, state, handles and any other information that
+ // represents a model.
+ private static class ModelData {
+ // Model not loaded (and hence not started).
+ static final int MODEL_NOTLOADED = 0;
+
+ // Loaded implies model was successfully loaded. Model not started yet.
+ static final int MODEL_LOADED = 1;
+
+ // Started implies model was successfully loaded and start was called.
+ static final int MODEL_STARTED = 2;
+
+ // One of MODEL_NOTLOADED, MODEL_LOADED, MODEL_STARTED (which implies loaded).
+ private int mModelState;
+
+ private UUID mModelId;
+
+ // One of SoundModel.TYPE_GENERIC or SoundModel.TYPE_KEYPHRASE. Initially set
+ // to SoundModel.TYPE_UNKNOWN;
+ private int mModelType = SoundModel.TYPE_UNKNOWN;
+ private IRecognitionStatusCallback mCallback = null;
+ private RecognitionConfig mRecognitionConfig = null;
+
+
+ // Model handle is an integer used by the HAL as an identifier for sound
+ // models.
+ private int mModelHandle = INVALID_VALUE;
+
+ ModelData(UUID modelId) {
+ mModelId = modelId;
+ }
+
+ synchronized void setTypeGeneric() {
+ mModelType = SoundModel.TYPE_GENERIC_SOUND;
+ }
+
+ synchronized void setCallback(IRecognitionStatusCallback callback) {
+ mCallback = callback;
+ }
+
+ synchronized IRecognitionStatusCallback getCallback() {
+ return mCallback;
+ }
+
+ synchronized boolean isModelLoaded() {
+ return (mModelState == MODEL_LOADED || mModelState == MODEL_STARTED);
+ }
+
+ synchronized void setStarted() {
+ mModelState = MODEL_STARTED;
+ }
+
+ synchronized void setStopped() {
+ mModelState = MODEL_LOADED;
+ }
+
+ synchronized void setLoaded() {
+ mModelState = MODEL_LOADED;
+ }
+
+ synchronized boolean isModelStarted() {
+ return mModelState == MODEL_STARTED;
+ }
+
+ synchronized void clearState() {
+ mModelState = MODEL_NOTLOADED;
+ mModelHandle = INVALID_VALUE;
+ }
+
+ synchronized void clearCallback() {
+ mCallback = null;
+ }
+
+ synchronized void setHandle(int handle) {
+ mModelHandle = handle;
+ }
+
+ synchronized void setRecognitionConfig(RecognitionConfig config) {
+ mRecognitionConfig = config;
+ }
+
+ synchronized int getHandle() {
+ return mModelHandle;
+ }
+
+ synchronized RecognitionConfig getRecognitionConfig() {
+ return mRecognitionConfig;
+ }
+
+ String stateToString() {
+ switch(mModelState) {
+ case MODEL_NOTLOADED: return "NOT_LOADED";
+ case MODEL_LOADED: return "LOADED";
+ case MODEL_STARTED: return "STARTED";
+ }
+ return "Unknown state";
+ }
+
+ public String toString() {
+ return "Handle: " + mModelHandle + "ModelState: " + stateToString();
+ }
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index 772287624f6a..113431f2de7e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -75,5 +75,7 @@ public abstract class SoundTriggerInternal {
public abstract ModuleProperties getModuleProperties();
+ public abstract int unloadKeyphraseModel(int keyphaseId);
+
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 682f4a412f0e..a4c1210ba188 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.soundtrigger;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -47,13 +48,14 @@ import java.util.UUID;
* @hide
*/
public class SoundTriggerService extends SystemService {
- static final String TAG = "SoundTriggerService";
- static final boolean DEBUG = false;
+ private static final String TAG = "SoundTriggerService";
+ private static final boolean DEBUG = true;
final Context mContext;
private final SoundTriggerServiceStub mServiceStub;
private final LocalSoundTriggerService mLocalSoundTriggerService;
private SoundTriggerDbHelper mDbHelper;
+ private SoundTriggerHelper mSoundTriggerHelper;
public SoundTriggerService(Context context) {
super(context);
@@ -71,7 +73,8 @@ public class SoundTriggerService extends SystemService {
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- mLocalSoundTriggerService.initSoundTriggerHelper();
+ initSoundTriggerHelper();
+ mLocalSoundTriggerService.setSoundTriggerHelper(mSoundTriggerHelper);
} else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
mDbHelper = new SoundTriggerDbHelper(mContext);
}
@@ -85,6 +88,20 @@ public class SoundTriggerService extends SystemService {
public void onSwitchUser(int userHandle) {
}
+ private synchronized void initSoundTriggerHelper() {
+ if (mSoundTriggerHelper == null) {
+ mSoundTriggerHelper = new SoundTriggerHelper(mContext);
+ }
+ }
+
+ private synchronized boolean isInitialized() {
+ if (mSoundTriggerHelper == null ) {
+ Slog.e(TAG, "SoundTriggerHelper not initialized.");
+ return false;
+ }
+ return true;
+ }
+
class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
@@ -102,19 +119,32 @@ public class SoundTriggerService extends SystemService {
}
@Override
- public void startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+ public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback,
+ RecognitionConfig config) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_ERROR;
if (DEBUG) {
Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
}
+
+ GenericSoundModel model = getSoundModel(parcelUuid);
+ if (model == null) {
+ Slog.e(TAG, "Null model in database for id: " + parcelUuid);
+ return STATUS_ERROR;
+ }
+
+ return mSoundTriggerHelper.startGenericRecognition(parcelUuid.getUuid(), model,
+ callback, config);
}
@Override
- public void stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+ public int stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
if (DEBUG) {
Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
}
+ if (!isInitialized()) return STATUS_ERROR;
+ return mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(), callback);
}
@Override
@@ -123,10 +153,8 @@ public class SoundTriggerService extends SystemService {
if (DEBUG) {
Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
}
- SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(soundModelId.getUuid());
- if (model == null) {
- Slog.e(TAG, "Null model in database.");
- }
+ SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(
+ soundModelId.getUuid());
return model;
}
@@ -145,6 +173,8 @@ public class SoundTriggerService extends SystemService {
if (DEBUG) {
Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
}
+ // Unload the model if it is loaded.
+ mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
}
}
@@ -157,38 +187,55 @@ public class SoundTriggerService extends SystemService {
mContext = context;
}
- void initSoundTriggerHelper() {
- if (mSoundTriggerHelper == null) {
- mSoundTriggerHelper = new SoundTriggerHelper(mContext);
- }
+ synchronized void setSoundTriggerHelper(SoundTriggerHelper helper) {
+ mSoundTriggerHelper = helper;
}
@Override
public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
- return mSoundTriggerHelper.startRecognition(keyphraseId, soundModel, listener,
+ if (!isInitialized()) return STATUS_ERROR;
+ return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel, listener,
recognitionConfig);
}
@Override
- public int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
- return mSoundTriggerHelper.stopRecognition(keyphraseId, listener);
+ public synchronized int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
+ if (!isInitialized()) return STATUS_ERROR;
+ return mSoundTriggerHelper.stopKeyphraseRecognition(keyphraseId, listener);
}
@Override
public void stopAllRecognitions() {
+ if (!isInitialized()) return;
mSoundTriggerHelper.stopAllRecognitions();
}
@Override
public ModuleProperties getModuleProperties() {
+ if (!isInitialized()) return null;
return mSoundTriggerHelper.getModuleProperties();
}
@Override
+ public int unloadKeyphraseModel(int keyphraseId) {
+ if (!isInitialized()) return STATUS_ERROR;
+ return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!isInitialized()) return;
mSoundTriggerHelper.dump(fd, pw, args);
}
+
+ private synchronized boolean isInitialized() {
+ if (mSoundTriggerHelper == null ) {
+ Slog.e(TAG, "SoundTriggerHelper not initialized.");
+ return false;
+ }
+ return true;
+ }
}
private void enforceCallingPermission(String permission) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4a54643b3cf5..6ab0b998bd6c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -760,6 +760,10 @@ public class VoiceInteractionManagerService extends SystemService {
final long caller = Binder.clearCallingIdentity();
boolean deleted = false;
try {
+ int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
+ if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
+ Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
+ }
deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
} finally {
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 094b3a94bd7b..1b70d651aabc 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -181,7 +181,10 @@ public abstract class Conference extends Conferenceable {
* @hide
*/
public void removeCapability(int capability) {
- mConnectionCapabilities &= ~capability;
+ int newCapabilities = mConnectionCapabilities;
+ newCapabilities &= ~capability;
+
+ setConnectionCapabilities(newCapabilities);
}
/**
@@ -191,7 +194,10 @@ public abstract class Conference extends Conferenceable {
* @hide
*/
public void addCapability(int capability) {
- mConnectionCapabilities |= capability;
+ int newCapabilities = mConnectionCapabilities;
+ newCapabilities |= capability;
+
+ setConnectionCapabilities(newCapabilities);
}
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa7a59d76f09..4547c6a6c153 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -297,6 +297,24 @@ public abstract class Connection extends Conferenceable {
*/
public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
+ /**
+ * Connection event used to inform Telecom that it should play the on hold tone. This is used
+ * to play a tone when the peer puts the current call on hold. Sent to Telecom via
+ * {@link #sendConnectionEvent(String)}.
+ * @hide
+ */
+ public static final String EVENT_ON_HOLD_TONE_START =
+ "android.telecom.event.ON_HOLD_TONE_START";
+
+ /**
+ * Connection event used to inform Telecom that it should stop the on hold tone. This is used
+ * to stop a tone when the peer puts the current call on hold. Sent to Telecom via
+ * {@link #sendConnectionEvent(String)}.
+ * @hide
+ */
+ public static final String EVENT_ON_HOLD_TONE_END =
+ "android.telecom.event.ON_HOLD_TONE_END";
+
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
@@ -447,6 +465,8 @@ public abstract class Connection extends Conferenceable {
public void onConferenceStarted() {}
public void onConferenceMergeFailed(Connection c) {}
public void onExtrasChanged(Connection c, Bundle extras) {}
+ /** @hide */
+ public void onConnectionEvent(Connection c, String event) {}
}
/**
@@ -1986,4 +2006,16 @@ public abstract class Connection extends Conferenceable {
l.onConferenceStarted();
}
}
+
+ /**
+ * Sends a connection event to Telecom.
+ *
+ * @param event The connection event.
+ * @hide
+ */
+ protected void sendConnectionEvent(String event) {
+ for (Listener l : mListeners) {
+ l.onConnectionEvent(this, event);
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index b4a7ce0f56b1..5b62e03350b1 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -613,6 +613,14 @@ public abstract class ConnectionService extends Service {
mAdapter.setExtras(id, extras);
}
}
+
+ @Override
+ public void onConnectionEvent(Connection connection, String event) {
+ String id = mIdByConnection.get(connection);
+ if (id != null) {
+ mAdapter.onConnectionEvent(id, event);
+ }
+ }
};
/** {@inheritDoc} */
@@ -1045,6 +1053,16 @@ public abstract class ConnectionService extends Service {
}
/**
+ * Returns all the active {@code Conference}s for which this {@code ConnectionService}
+ * has taken responsibility.
+ *
+ * @return A collection of {@code Conference}s created by this {@code ConnectionService}.
+ */
+ public final Collection<Conference> getAllConferences() {
+ return mConferenceById.values();
+ }
+
+ /**
* Create a {@code Connection} given an incoming request. This is used to attach to existing
* incoming calls.
*
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 456251476862..30fc5ad1e4b6 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -412,4 +412,20 @@ final class ConnectionServiceAdapter implements DeathRecipient {
}
}
}
+
+ /**
+ * Informs Telecom of a connection level event.
+ *
+ * @param callId The unique ID of the call.
+ * @param event The event.
+ */
+ void onConnectionEvent(String callId, String event) {
+ Log.v(this, "onConnectionEvent: %s", event);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.onConnectionEvent(callId, event);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 293dc1199923..6a8c1cb281ba 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -62,6 +62,7 @@ final class ConnectionServiceAdapterServant {
private static final int MSG_ON_POST_DIAL_CHAR = 22;
private static final int MSG_SET_CONFERENCE_MERGE_FAILED = 23;
private static final int MSG_SET_EXTRAS = 24;
+ private static final int MSG_ON_CONNECTION_EVENT = 25;
private final IConnectionServiceAdapter mDelegate;
@@ -239,6 +240,16 @@ final class ConnectionServiceAdapterServant {
} finally {
args.recycle();
}
+ break;
+ }
+ case MSG_ON_CONNECTION_EVENT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ mDelegate.onConnectionEvent((String) args.arg1, (String) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
}
}
}
@@ -419,6 +430,14 @@ final class ConnectionServiceAdapterServant {
args.arg2 = extras;
mHandler.obtainMessage(MSG_SET_EXTRAS, args).sendToTarget();
}
+
+ @Override
+ public final void onConnectionEvent(String connectionId, String event) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = connectionId;
+ args.arg2 = event;
+ mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
+ }
};
public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 3a7faf645a8c..2eef7eeb6bd8 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -92,8 +92,8 @@ public final class DisconnectCause implements Parcelable {
/**
* Creates a new DisconnectCause.
*
- * @param label The localized label to show to the user to explain the disconnect.
* @param code The code for the disconnect cause.
+ * @param label The localized label to show to the user to explain the disconnect.
* @param description The localized description to show to the user to explain the disconnect.
* @param reason The reason for the disconnect.
*/
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 73cc4a5f6138..3f32dbe0fdbe 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,6 +16,8 @@
package android.telecom;
+import android.os.AsyncTask;
+
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.IllegalFormatException;
@@ -38,8 +40,26 @@ final public class Log {
public static final boolean WARN = isLoggable(android.util.Log.WARN);
public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
+ private static MessageDigest sMessageDigest;
+
private Log() {}
+ public static void initMd5Sum() {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... args) {
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ md = null;
+ }
+ sMessageDigest = md;
+ return null;
+ }
+ }.execute();
+ }
+
public static boolean isLoggable(int level) {
return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
}
@@ -137,15 +157,14 @@ final public class Log {
}
private static String secureHash(byte[] input) {
- MessageDigest messageDigest;
- try {
- messageDigest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- return null;
+ if (sMessageDigest != null) {
+ sMessageDigest.reset();
+ sMessageDigest.update(input);
+ byte[] result = sMessageDigest.digest();
+ return encodeHex(result);
+ } else {
+ return "Uninitialized SHA1";
}
- messageDigest.update(input);
- byte[] result = messageDigest.digest();
- return encodeHex(result);
}
private static String encodeHex(byte[] bytes) {
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index f9609590a697..01858080d7d7 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -209,6 +209,15 @@ public final class RemoteConnection {
* @param extras The extras containing other information associated with the connection.
*/
public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {}
+
+ /**
+ * Handles a connection event propagated to this {@link RemoteConnection}.
+ *
+ * @param connection The {@code RemoteConnection} invoking this method.
+ * @param event The connection event.
+ * @hide
+ */
+ public void onConnectionEvent(RemoteConnection connection, String event) {}
}
/**
@@ -1291,6 +1300,20 @@ public final class RemoteConnection {
}
}
+ /** @hide */
+ void onConnectionEvent(final String event) {
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onConnectionEvent(connection, event);
+ }
+ });
+ }
+ }
+
/**
* Create a RemoteConnection represents a failure, and which will be in
* {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index dc0de0c462cf..b85382feae60 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -330,6 +330,13 @@ final class RemoteConnectionService {
.setExtras(extras);
}
}
+
+ @Override
+ public void onConnectionEvent(String callId, String event) {
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "onConnectionEvent").onConnectionEvent(event);
+ }
+ }
};
private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index c122c5a365fc..857d2df9b73c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -498,6 +498,7 @@ public class TelecomManager {
mContext = context;
}
mTelecomServiceOverride = telecomServiceImpl;
+ android.telecom.Log.initMd5Sum();
}
/**
@@ -774,9 +775,9 @@ public class TelecomManager {
}
/**
- * Register a {@link PhoneAccount} for use by the system. When registering
- * {@link PhoneAccount}s, existing registrations will be overwritten if the
- * {@link PhoneAccountHandle} matches that of a {@link PhoneAccount} which is already
+ * Register a {@link PhoneAccount} for use by the system that will be stored in Device Encrypted
+ * storage. When registering {@link PhoneAccount}s, existing registrations will be overwritten
+ * if the {@link PhoneAccountHandle} matches that of a {@link PhoneAccount} which is already
* registered. Once registered, the {@link PhoneAccount} is listed to the user as an option
* when placing calls. The user may still need to enable the {@link PhoneAccount} within
* the phone app settings before the account is usable.
@@ -1166,11 +1167,16 @@ public class TelecomManager {
/**
* Registers a new incoming call. A {@link ConnectionService} should invoke this method when it
* has an incoming call. The specified {@link PhoneAccountHandle} must have been registered
- * with {@link #registerPhoneAccount}. Once invoked, this method will cause the system to bind
- * to the {@link ConnectionService} associated with the {@link PhoneAccountHandle} and request
- * additional information about the call (See
- * {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming call UI.
- *
+ * with {@link #registerPhoneAccount} and the user must have enabled the corresponding
+ * {@link PhoneAccount}. This can be checked using {@link #getPhoneAccount}. Once invoked, this
+ * method will cause the system to bind to the {@link ConnectionService} associated with the
+ * {@link PhoneAccountHandle} and request additional information about the call
+ * (See {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming
+ * call UI.
+ * <p>
+ * A {@link SecurityException} will be thrown if either the {@link PhoneAccountHandle} does not
+ * correspond to a registered {@link PhoneAccount} or the associated {@link PhoneAccount} is not
+ * currently enabled by the user.
* @param phoneAccount A {@link PhoneAccountHandle} registered with
* {@link #registerPhoneAccount}.
* @param extras A bundle that will be passed through to
@@ -1420,6 +1426,7 @@ public class TelecomManager {
* {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns
* {@code true} for the current user.
*/
+ // TODO: Delete this.
public void launchManageBlockedNumbersActivity() {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -1431,6 +1438,26 @@ public class TelecomManager {
}
}
+ /**
+ * Creates the {@link Intent} which can be used with {@link Context#startActivity(Intent)} to
+ * launch the activity to manage blocked numbers.
+ * <p> This method displays the UI to manage blocked numbers only if
+ * {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns
+ * {@code true} for the current user.
+ */
+ public Intent createManageBlockedNumbersIntent() {
+ ITelecomService service = getTelecomService();
+ Intent result = null;
+ if (service != null) {
+ try {
+ result = service.createManageBlockedNumbersIntent();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecomService#createManageBlockedNumbersIntent", e);
+ }
+ }
+ return result;
+ }
+
private ITelecomService getTelecomService() {
if (mTelecomServiceOverride != null) {
return mTelecomServiceOverride;
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 76474447d191..569c24469368 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -86,4 +86,6 @@ oneway interface IConnectionServiceAdapter {
void addExistingConnection(String callId, in ParcelableConnection connection);
void setExtras(String callId, in Bundle extras);
+
+ void onConnectionEvent(String callId, String event);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 95c8db54498c..3c250f1b54fd 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telecom;
import android.content.ComponentName;
+import android.content.Intent;
import android.telecom.ParcelableCallAnalytics;
import android.telecom.PhoneAccountHandle;
import android.net.Uri;
@@ -247,5 +248,11 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#launchManageBlockedNumbersActivity
**/
+ // TODO: Delete this.
void launchManageBlockedNumbersActivity(in String callingPackageName);
+
+ /**
+ * @see TelecomServiceImpl#createManageBlockedNumbersIntent
+ **/
+ Intent createManageBlockedNumbersIntent();
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3ad7d34f6ff1..1278c07897f5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -733,9 +733,28 @@ public class CarrierConfigManager {
* @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
* @return A {@link PersistableBundle} containing the config for the given subId, or default
* values for an invalid subId.
+ *
+ * @deprecated use getConfig.
*/
@Nullable
public PersistableBundle getConfigForSubId(int subId) {
+ return getConfig(subId);
+ }
+
+ /**
+ * Gets the configuration values for a particular subscription, which is associated with a
+ * specific SIM card. If an invalid subId is used, the returned config will contain default
+ * values.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+ * @return A {@link PersistableBundle} containing the config for the given subId, or default
+ * values for an invalid subId.
+ */
+ @Nullable
+ public PersistableBundle getConfig(int subId) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
if (loader == null) {
@@ -757,11 +776,11 @@ public class CarrierConfigManager {
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
- * @see #getConfigForSubId
+ * @return A {@link PersistableBundle} containing the config for the default subscription.
*/
@Nullable
public PersistableBundle getConfig() {
- return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
+ return getConfig(SubscriptionManager.getDefaultSubscriptionId());
}
/**
@@ -778,8 +797,29 @@ public class CarrierConfigManager {
* {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an
* arbitrary thread.
* </p>
+ *
+ * @deprecated use notifyConfigChanged.
*/
public void notifyConfigChangedForSubId(int subId) {
+ notifyConfigChanged(subId);
+ }
+
+ /**
+ * Calling this method triggers telephony services to fetch the current carrier configuration.
+ * <p>
+ * Normally this does not need to be called because the platform reloads config on its own.
+ * This should be called by a carrier service app if it wants to update config at an arbitrary
+ * 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>
+ */
+ public void notifyConfigChanged(int subId) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
if (loader == null) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fcb42a48048f..e90be91e3248 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -47,6 +47,7 @@ import com.android.internal.telephony.TelephonyProperties;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -2931,10 +2932,27 @@ public class TelephonyManager {
* @return an IccOpenLogicalChannelResponse object.
*/
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
+ return iccOpenLogicalChannel(getDefaultSubscription(), AID);
+ }
+
+ /**
+ * Opens a logical channel to the ICC card.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CCHO command.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param AID Application id. See ETSI 102.221 and 101.220.
+ * @return an IccOpenLogicalChannelResponse object.
+ */
+ public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.iccOpenLogicalChannel(AID);
+ return telephony.iccOpenLogicalChannel(subId, AID);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -2955,10 +2973,28 @@ public class TelephonyManager {
* @return true if the channel was closed successfully.
*/
public boolean iccCloseLogicalChannel(int channel) {
+ return iccCloseLogicalChannel(getDefaultSubscription(), channel);
+ }
+
+ /**
+ * Closes a previously opened logical channel to the ICC card.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CCHC command.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param channel is the channel id to be closed as retruned by a successful
+ * iccOpenLogicalChannel.
+ * @return true if the channel was closed successfully.
+ */
+ public boolean iccCloseLogicalChannel(int subId, int channel) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.iccCloseLogicalChannel(channel);
+ return telephony.iccCloseLogicalChannel(subId, channel);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -2988,10 +3024,38 @@ public class TelephonyManager {
*/
public String iccTransmitApduLogicalChannel(int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
+ return iccTransmitApduLogicalChannel(getDefaultSubscription(), channel, cla,
+ instruction, p1, p2, p3, data);
+ }
+
+ /**
+ * Transmit an APDU to the ICC card over a logical channel.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CGLA command.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param channel is the channel id to be closed as returned by a successful
+ * iccOpenLogicalChannel.
+ * @param cla Class of the APDU command.
+ * @param instruction Instruction of the APDU command.
+ * @param p1 P1 value of the APDU command.
+ * @param p2 P2 value of the APDU command.
+ * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+ * is sent to the SIM.
+ * @param data Data to be sent with the APDU.
+ * @return The APDU response from the ICC card with the status appended at
+ * the end.
+ */
+ public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
+ int instruction, int p1, int p2, int p3, String data) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.iccTransmitApduLogicalChannel(channel, cla,
+ return telephony.iccTransmitApduLogicalChannel(subId, channel, cla,
instruction, p1, p2, p3, data);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
@@ -3020,10 +3084,36 @@ public class TelephonyManager {
*/
public String iccTransmitApduBasicChannel(int cla,
int instruction, int p1, int p2, int p3, String data) {
+ return iccTransmitApduBasicChannel(getDefaultSubscription(), cla,
+ instruction, p1, p2, p3, data);
+ }
+
+ /**
+ * Transmit an APDU to the ICC card over the basic channel.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CSIM command.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param cla Class of the APDU command.
+ * @param instruction Instruction of the APDU command.
+ * @param p1 P1 value of the APDU command.
+ * @param p2 P2 value of the APDU command.
+ * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+ * is sent to the SIM.
+ * @param data Data to be sent with the APDU.
+ * @return The APDU response from the ICC card with the status appended at
+ * the end.
+ */
+ public String iccTransmitApduBasicChannel(int subId, int cla,
+ int instruction, int p1, int p2, int p3, String data) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.iccTransmitApduBasicChannel(cla,
+ return telephony.iccTransmitApduBasicChannel(subId, cla,
instruction, p1, p2, p3, data);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
@@ -3048,10 +3138,31 @@ public class TelephonyManager {
*/
public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
String filePath) {
+ return iccExchangeSimIO(getDefaultSubscription(), fileID, command, p1, p2, p3, filePath);
+ }
+
+ /**
+ * Returns the response APDU for a command APDU sent through SIM_IO.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param fileID
+ * @param command
+ * @param p1 P1 value of the APDU command.
+ * @param p2 P2 value of the APDU command.
+ * @param p3 P3 value of the APDU command.
+ * @param filePath
+ * @return The APDU response.
+ */
+ public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
+ int p3, String filePath) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.iccExchangeSimIO(fileID, command, p1, p2, p3, filePath);
+ return telephony.iccExchangeSimIO(subId, fileID, command, p1, p2, p3, filePath);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -3073,10 +3184,29 @@ public class TelephonyManager {
* returns an empty string.
*/
public String sendEnvelopeWithStatus(String content) {
+ return sendEnvelopeWithStatus(getDefaultSubscription(), content);
+ }
+
+ /**
+ * Send ENVELOPE to the SIM and return the response.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param content String containing SAT/USAT response in hexadecimal
+ * format starting with command tag. See TS 102 223 for
+ * details.
+ * @return The APDU response from the ICC card in hexadecimal format
+ * with the last 4 bytes being the status word. If the command fails,
+ * returns an empty string.
+ */
+ public String sendEnvelopeWithStatus(int subId, String content) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.sendEnvelopeWithStatus(content);
+ return telephony.sendEnvelopeWithStatus(subId, content);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -3637,8 +3767,20 @@ public class TelephonyManager {
* @return true on success; false on any failure.
*/
public boolean setPreferredNetworkTypeToGlobal() {
- return setPreferredNetworkType(getDefaultSubscription(),
- RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
+ return setPreferredNetworkTypeToGlobal(getDefaultSubscription());
+ }
+
+ /**
+ * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
+ *
+ * <p>
+ * Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
+ *
+ * @return true on success; false on any failure.
+ */
+ public boolean setPreferredNetworkTypeToGlobal(int subId) {
+ return setPreferredNetworkType(subId, RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
}
/**
@@ -3685,10 +3827,26 @@ public class TelephonyManager {
* @return true if the app has carrier privileges.
*/
public boolean hasCarrierPrivileges() {
+ return hasCarrierPrivileges(getDefaultSubscription());
+ }
+
+ /**
+ * Has the calling application been granted carrier privileges by the carrier.
+ *
+ * If any of the packages in the calling UID has carrier privileges, the
+ * call will return true. This access is granted by the owner of the UICC
+ * card and does not depend on the registered carrier.
+ *
+ * @param subId The subscription to use.
+ * @return true if the app has carrier privileges.
+ */
+ public boolean hasCarrierPrivileges(int subId) {
try {
ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.getCarrierPrivilegeStatus() == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ if (telephony != null) {
+ return telephony.getCarrierPrivilegeStatus(subId) ==
+ CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ }
} catch (RemoteException ex) {
Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
} catch (NullPointerException ex) {
@@ -3712,10 +3870,29 @@ public class TelephonyManager {
* @return true if the operation was executed correctly.
*/
public boolean setOperatorBrandOverride(String brand) {
+ return setOperatorBrandOverride(getDefaultSubscription(), brand);
+ }
+
+ /**
+ * Override the branding for the current ICCID.
+ *
+ * Once set, whenever the SIM is present in the device, the service
+ * provider name (SPN) and the operator name will both be replaced by the
+ * brand value input. To unset the value, the same function should be
+ * called with a null brand value.
+ *
+ * <p>Requires that the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription to use.
+ * @param brand The brand name to display/set.
+ * @return true if the operation was executed correctly.
+ */
+ public boolean setOperatorBrandOverride(int subId, String brand) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.setOperatorBrandOverride(brand);
+ return telephony.setOperatorBrandOverride(subId, brand);
} catch (RemoteException ex) {
Rlog.e(TAG, "setOperatorBrandOverride RemoteException", ex);
} catch (NullPointerException ex) {
@@ -3746,10 +3923,37 @@ public class TelephonyManager {
public boolean setRoamingOverride(List<String> gsmRoamingList,
List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
List<String> cdmaNonRoamingList) {
+ return setRoamingOverride(getDefaultSubscription(), gsmRoamingList, gsmNonRoamingList,
+ cdmaRoamingList, cdmaNonRoamingList);
+ }
+
+ /**
+ * Override the roaming preference for the current ICCID.
+ *
+ * Using this call, the carrier app (see #hasCarrierPrivileges) can override
+ * the platform's notion of a network operator being considered roaming or not.
+ * The change only affects the ICCID that was active when this call was made.
+ *
+ * If null is passed as any of the input, the corresponding value is deleted.
+ *
+ * <p>Requires that the caller have carrier privilege. See #hasCarrierPrivileges.
+ *
+ * @param subId for which the roaming overrides apply.
+ * @param gsmRoamingList - List of MCCMNCs to be considered roaming for 3GPP RATs.
+ * @param gsmNonRoamingList - List of MCCMNCs to be considered not roaming for 3GPP RATs.
+ * @param cdmaRoamingList - List of SIDs to be considered roaming for 3GPP2 RATs.
+ * @param cdmaNonRoamingList - List of SIDs to be considered not roaming for 3GPP2 RATs.
+ * @return true if the operation was executed correctly.
+ *
+ * @hide
+ */
+ public boolean setRoamingOverride(int subId, List<String> gsmRoamingList,
+ List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
+ List<String> cdmaNonRoamingList) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.setRoamingOverride(gsmRoamingList, gsmNonRoamingList,
+ return telephony.setRoamingOverride(subId, gsmRoamingList, gsmNonRoamingList,
cdmaRoamingList, cdmaNonRoamingList);
} catch (RemoteException ex) {
Rlog.e(TAG, "setRoamingOverride RemoteException", ex);
@@ -3857,6 +4061,21 @@ public class TelephonyManager {
}
/** @hide */
+ public List<String> getPackagesWithCarrierPrivileges() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getPackagesWithCarrierPrivileges();
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getPackagesWithCarrierPrivileges RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "getPackagesWithCarrierPrivileges NPE", ex);
+ }
+ return Collections.EMPTY_LIST;
+ }
+
+ /** @hide */
@SystemApi
public void dial(String number) {
try {
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 5f84e0ce353a..96c624345d5e 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -178,7 +178,7 @@ public class ImsCallProfile implements Parcelable {
* Codec: Codec info.
* DisplayText: Display text for the call.
* AdditionalCallInfo: Additional call info.
- * CallRadioTech: The radio tech on which the call is placed.
+ * CallPull: Boolean value specifying if the call is a pulled call.
*/
public static final String EXTRA_OI = "oi";
public static final String EXTRA_CNA = "cna";
@@ -188,6 +188,7 @@ public class ImsCallProfile implements Parcelable {
public static final String EXTRA_CODEC = "Codec";
public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+ public static final String EXTRA_IS_CALL_PULL = "CallPull";
/**
* Extra key which the RIL can use to indicate the radio technology used for a call.
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index c909c6dc518e..558c1dc1866c 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -241,6 +241,16 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_ANSWERED_ELSEWHERE = 1014;
/**
+ * Call pull request failure from the network.
+ */
+ public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015;
+
+ /**
+ * Call ended due to being pulled onto another device.
+ */
+ public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016;
+
+ /**
* Supplementary services (HOLD/RESUME) failure error codes.
* Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
*/
@@ -249,12 +259,33 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203;
/**
+ * DPD Procedure received no response or send failed
+ */
+ public static final int CODE_IWLAN_DPD_FAILURE = 1300;
+
+ /**
+ * Establishment of the ePDG Tunnel Failed
+ */
+ public static final int CODE_EPDG_TUNNEL_ESTABLISH_FAILURE = 1400;
+
+ /**
+ * Re-keying of the ePDG Tunnel Failed; may not always result in teardown
+ */
+ public static final int CODE_EPDG_TUNNEL_REKEY_FAILURE = 1401;
+
+ /**
+ * Connection to the packet gateway is lost
+ */
+ public static final int CODE_EPDG_TUNNEL_LOST_CONNECTION = 1402;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED
= "Forbidden. Not Authorized for Service";
+
// For main reason code
public int mCode;
// For the extra code value; it depends on the code value.
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 23a69d10aa7a..04cb1f278792 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -17,6 +17,9 @@
package com.android.ims.internal;
import com.android.ims.ImsReasonInfo;
+
+import android.net.Uri;
+
/**
* A listener type for receiving notifications about the changes to
* the IMS connection(registration).
@@ -26,15 +29,36 @@ import com.android.ims.ImsReasonInfo;
interface IImsRegistrationListener {
/**
* Notifies the application when the device is connected to the IMS network.
+ *
+ * @deprecated see {@link registrationConnectedWithRadioTech}
*/
void registrationConnected();
/**
* Notifies the application when the device is trying to connect the IMS network.
+ *
+ * @deprecated see {@link registrationProgressingWithRadioTech}
*/
void registrationProgressing();
/**
+ * Notifies the application when the device is connected to the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are {@code
+ * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+ */
+ void registrationConnectedWithRadioTech(int imsRadioTech);
+
+ /**
+ * Notifies the application when the device is trying to connect the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are {@code
+ * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+ */
+ void registrationProgressingWithRadioTech(int imsRadioTech);
+
+
+ /**
* Notifies the application when the device is disconnected from the IMS network.
*/
void registrationDisconnected(in ImsReasonInfo imsReasonInfo);
@@ -78,4 +102,9 @@ interface IImsRegistrationListener {
* @param count The number of waiting voice messages.
*/
void voiceMessageCountUpdate(int count);
+
+ /**
+ * Notifies the application when the list of URIs associated with IMS client is updated.
+ */
+ void registrationAssociatedUriChanged(in Uri[] uris);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62f294c3a197..2727319ad0a6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -538,27 +538,30 @@ interface ITelephony {
*
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
+ * @param subId The subscription to use.
* @param AID Application id. See ETSI 102.221 and 101.220.
* @return an IccOpenLogicalChannelResponse object.
*/
- IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID);
+ IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID);
/**
* Closes a previously opened logical channel to the ICC card.
*
* Input parameters equivalent to TS 27.007 AT+CCHC command.
*
+ * @param subId The subscription to use.
* @param channel is the channel id to be closed as retruned by a
* successful iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
*/
- boolean iccCloseLogicalChannel(int channel);
+ boolean iccCloseLogicalChannel(int subId, int channel);
/**
* Transmit an APDU to the ICC card over a logical channel.
*
* Input parameters equivalent to TS 27.007 AT+CGLA command.
*
+ * @param subId The subscription to use.
* @param channel is the channel id to be closed as retruned by a
* successful iccOpenLogicalChannel.
* @param cla Class of the APDU command.
@@ -571,7 +574,7 @@ interface ITelephony {
* @return The APDU response from the ICC card with the status appended at
* the end.
*/
- String iccTransmitApduLogicalChannel(int channel, int cla, int instruction,
+ String iccTransmitApduLogicalChannel(int subId, int channel, int cla, int instruction,
int p1, int p2, int p3, String data);
/**
@@ -579,6 +582,7 @@ interface ITelephony {
*
* Input parameters equivalent to TS 27.007 AT+CSIM command.
*
+ * @param subId The subscription to use.
* @param cla Class of the APDU command.
* @param instruction Instruction of the APDU command.
* @param p1 P1 value of the APDU command.
@@ -589,12 +593,13 @@ interface ITelephony {
* @return The APDU response from the ICC card with the status appended at
* the end.
*/
- String iccTransmitApduBasicChannel(int cla, int instruction,
+ String iccTransmitApduBasicChannel(int subId, int cla, int instruction,
int p1, int p2, int p3, String data);
/**
* Returns the response APDU for a command APDU sent through SIM_IO.
*
+ * @param subId The subscription to use.
* @param fileID
* @param command
* @param p1 P1 value of the APDU command.
@@ -603,12 +608,13 @@ interface ITelephony {
* @param filePath
* @return The APDU response.
*/
- byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
+ byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2, int p3,
String filePath);
/**
* Send ENVELOPE to the SIM and returns the response.
*
+ * @param subId The subscription to use.
* @param contents String containing SAT/USAT response in hexadecimal
* format starting with command tag. See TS 102 223 for
* details.
@@ -616,7 +622,7 @@ interface ITelephony {
* being the status word. If the command fails, returns an empty
* string.
*/
- String sendEnvelopeWithStatus(String content);
+ String sendEnvelopeWithStatus(int subId, String content);
/**
* Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
@@ -768,9 +774,10 @@ interface ITelephony {
*
* TODO: Add a link to documentation.
*
+ * @param subId The subscription to use.
* @return carrier privilege status defined in TelephonyManager.
*/
- int getCarrierPrivilegeStatus();
+ int getCarrierPrivilegeStatus(int subId);
/**
* Similar to above, but check for the package whose name is pkgName.
@@ -842,10 +849,11 @@ interface ITelephony {
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* or has to be carrier app - see #hasCarrierPrivileges.
*
+ * @param subId The subscription to use.
* @param brand The brand name to display/set.
* @return true if the operation was executed correctly.
*/
- boolean setOperatorBrandOverride(String brand);
+ boolean setOperatorBrandOverride(int subId, String brand);
/**
* Override the roaming indicator for the current ICCID.
@@ -858,13 +866,14 @@ interface ITelephony {
*
* <p>Requires that the caller have carrier privilege. See #hasCarrierPrivileges.
*
+ * @param subId for which the roaming overrides apply.
* @param gsmRoamingList - List of MCCMNCs to be considered roaming for 3GPP RATs.
* @param gsmNonRoamingList - List of MCCMNCs to be considered not roaming for 3GPP RATs.
* @param cdmaRoamingList - List of SIDs to be considered roaming for 3GPP2 RATs.
* @param cdmaNonRoamingList - List of SIDs to be considered not roaming for 3GPP2 RATs.
* @return true if the operation was executed correctly.
*/
- boolean setRoamingOverride(in List<String> gsmRoamingList,
+ boolean setRoamingOverride(int subId, in List<String> gsmRoamingList,
in List<String> gsmNonRoamingList, in List<String> cdmaRoamingList,
in List<String> cdmaNonRoamingList);
@@ -1028,4 +1037,9 @@ interface ITelephony {
* @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
*/
boolean isVoicemailVibrationEnabled(in PhoneAccountHandle accountHandle);
+
+ /**
+ * Returns a list of packages that have carrier privileges.
+ */
+ List<String> getPackagesWithCarrierPrivileges();
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 429839f6f6f9..bba357e07147 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -92,7 +92,33 @@ public interface RILConstants {
int NO_SMS_TO_ACK = 48; /* ACK received when there is no SMS to ack */
int NETWORK_ERR = 49; /* Received error from network */
int REQUEST_RATE_LIMITED = 50; /* Operation denied due to overly-frequent requests */
-
+ // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
+ // reveal particular replacement for Generic failure
+ int OEM_ERROR_1 = 501;
+ int OEM_ERROR_2 = 502;
+ int OEM_ERROR_3 = 503;
+ int OEM_ERROR_4 = 504;
+ int OEM_ERROR_5 = 505;
+ int OEM_ERROR_6 = 506;
+ int OEM_ERROR_7 = 507;
+ int OEM_ERROR_8 = 508;
+ int OEM_ERROR_9 = 509;
+ int OEM_ERROR_10 = 510;
+ int OEM_ERROR_11 = 511;
+ int OEM_ERROR_12 = 512;
+ int OEM_ERROR_13 = 513;
+ int OEM_ERROR_14 = 514;
+ int OEM_ERROR_15 = 515;
+ int OEM_ERROR_16 = 516;
+ int OEM_ERROR_17 = 517;
+ int OEM_ERROR_18 = 518;
+ int OEM_ERROR_19 = 519;
+ int OEM_ERROR_20 = 520;
+ int OEM_ERROR_21 = 521;
+ int OEM_ERROR_22 = 522;
+ int OEM_ERROR_23 = 523;
+ int OEM_ERROR_24 = 524;
+ int OEM_ERROR_25 = 525;
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -124,6 +150,26 @@ public interface RILConstants {
int PREFERRED_NETWORK_MODE = SystemProperties.getInt("ro.telephony.default_network",
NETWORK_MODE_WCDMA_PREF);
+ int BAND_MODE_UNSPECIFIED = 0; //"unspecified" (selected by baseband automatically)
+ int BAND_MODE_EURO = 1; //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+ int BAND_MODE_USA = 2; //"US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+ int BAND_MODE_JPN = 3; //"JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+ int BAND_MODE_AUS = 4; //"AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+ int BAND_MODE_AUS_2 = 5; //"AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+ int BAND_MODE_CELL_800 = 6; //"Cellular" (800-MHz Band)
+ int BAND_MODE_PCS = 7; //"PCS" (1900-MHz Band)
+ int BAND_MODE_JTACS = 8; //"Band Class 3" (JTACS Band)
+ int BAND_MODE_KOREA_PCS = 9; //"Band Class 4" (Korean PCS Band)
+ int BAND_MODE_5_450M = 10; //"Band Class 5" (450-MHz Band)
+ int BAND_MODE_IMT2000 = 11; //"Band Class 6" (2-GMHz IMT2000 Band)
+ int BAND_MODE_7_700M_2 = 12; //"Band Class 7" (Upper 700-MHz Band)
+ int BAND_MODE_8_1800M = 13; //"Band Class 8" (1800-MHz Band)
+ int BAND_MODE_9_900M = 14; //"Band Class 9" (900-MHz Band)
+ int BAND_MODE_10_800M_2 = 15; //"Band Class 10" (Secondary 800-MHz Band)
+ int BAND_MODE_EURO_PAMR_400M = 16; //"Band Class 11" (400-MHz European PAMR Band)
+ int BAND_MODE_AWS = 17; //"Band Class 15" (AWS Band)
+ int BAND_MODE_USA_2500M = 18; //"Band Class 16" (US 2.5-GHz Band)
+
int CDMA_CELL_BROADCAST_SMS_DISABLED = 1;
int CDMA_CELL_BROADCAST_SMS_ENABLED = 0;
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index bec1e4f76b9b..84cffe17d1d2 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -191,6 +191,11 @@ public class MockContext extends Context {
}
@Override
+ public File getDataDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public File getFilesDir() {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index ffb73f63230c..da4346002110 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -17,6 +17,7 @@
package android.test.mock;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Intent;
@@ -806,6 +807,12 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public @Nullable String getServicesSystemSharedLibraryPackageName() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
throw new UnsupportedOperationException();
@@ -817,6 +824,11 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public boolean hasSystemFeature(String name, int version) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean isSafeMode() {
throw new UnsupportedOperationException();
}
@@ -847,8 +859,14 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public boolean setPackageSuspendedAsUser(String packageName, boolean hidden, int userId) {
- return false;
+ public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean hidden, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public boolean isPackageSuspendedForUser(String packageName, int userId) {
+ throw new UnsupportedOperationException();
}
/**
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 8b8d604b4fc9..4bed94148599 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -60,6 +60,8 @@ public class AppLaunch extends InstrumentationTestCase {
// optional parameter: comma separated list of required account types before proceeding
// with the app launch
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
+ private static final String WEARABLE_ACTION_GOOGLE =
+ "com.google.android.wearable.action.GOOGLE";
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
@@ -183,6 +185,13 @@ public class AppLaunch extends InstrumentationTestCase {
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
+ ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ }
+
+ private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
if (ris == null || ris.isEmpty()) {
Log.i(TAG, "Could not find any apps");
} else {
diff --git a/tests/BatteryWaster/res/layout/battery_waster.xml b/tests/BatteryWaster/res/layout/battery_waster.xml
index 57a5b551fe21..ea7648708e75 100644
--- a/tests/BatteryWaster/res/layout/battery_waster.xml
+++ b/tests/BatteryWaster/res/layout/battery_waster.xml
@@ -27,7 +27,6 @@
android:layout_marginTop="25dp"
android:saveEnabled="false"
android:textSize="18sp"
- android:textColor="#ffffffff"
android:text="@string/waste_away"
/>
@@ -38,7 +37,6 @@
android:layout_marginTop="25dp"
android:saveEnabled="false"
android:textSize="18sp"
- android:textColor="#ffffffff"
android:text="@string/wake_away"
/>
@@ -52,7 +50,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:textSize="12sp"
- android:textColor="#ffffffff"
/>
</ScrollView>
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk
index 616a11b36616..39ad0ac4bcdb 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk
@@ -38,6 +38,8 @@ LOCAL_SRC_FILES := contrast.cpp \
sobeloperator.cpp \
stats_scorer.cpp
+LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter
+
LOCAL_STATIC_LIBRARIES += \
libcutils
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp
index 63e2ebf2f3e7..ffb8003d4c50 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp
@@ -65,9 +65,6 @@ void JNI_COLORSPACE_METHOD(nativeYuv420pToRgba8888)(
uint8* pInV = pInput + size + size / 4;
Rgba* pOutColor = pOutput;
- const int u_offset = size;
- const int v_offset = u_offset + size / 4;
-
for (int y = 0; y < height; y += 2) {
for (int x = 0; x < width; x += 2) {
int u, v, y1, y2, y3, y4;
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp
index dc5c305ea23f..808b90da372b 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp
@@ -81,8 +81,6 @@ jboolean Java_androidx_media_filterpacks_image_SobelFilter_sobelOperator(
short* gyPtr = new short[3 * numPixels];
computeGradient(srcPtr, width, height, gxPtr, gyPtr);
- unsigned char* mag = magPtr;
- unsigned char* dir = dirPtr;
for (int i = 0; i < numPixels; ++i) {
for (int c = 0; c < 3; c++) {
int gx = static_cast<int>(*(gxPtr + 3 * i + c) / 8 + 127.5);
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index 9f48d56cb56b..eda3f5e21f71 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -17,19 +17,28 @@
package android.security.net.config;
import android.app.Activity;
+import android.os.Build;
import android.test.ActivityUnitTestCase;
import android.util.ArraySet;
import android.util.Pair;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.URL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
+import com.android.org.conscrypt.TrustedCertificateStore;
+
public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
public NetworkSecurityConfigTests() {
@@ -40,6 +49,51 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
private static final byte[] G2_SPKI_SHA256
= hexToBytes("ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776");
+ private static final byte[] TEST_CA_BYTES
+ = hexToBytes(
+ "3082036130820249a003020102020900bd54597d6750ea62300d06092a86"
+ + "4886f70d01010b05003047310b3009060355040613025553310b30090603"
+ + "5504080c0243413110300e060355040a0c07416e64726f69643119301706"
+ + "035504030c104e53436f6e6669672054657374204341301e170d31363032"
+ + "32343030313130325a170d3136303332353030313130325a3047310b3009"
+ + "060355040613025553310b300906035504080c0243413110300e06035504"
+ + "0a0c07416e64726f69643119301706035504030c104e53436f6e66696720"
+ + "5465737420434130820122300d06092a864886f70d01010105000382010f"
+ + "003082010a0282010100e15ce8fd5794029841e760d68d6e0159c9c67630"
+ + "089775bc728d83dae7e29e23fe5f6e113b789f4c5b22f052300ec6d5faa5"
+ + "724432e7bac96682792ef6e9617c939c4329dce8788cbdf3a11b621fac9e"
+ + "2edbec2d7e5e07296bbb544b89263137a6a31573a2362e05ca8ff9c886bf"
+ + "52df4ff93c45475145a40a83f2670e23669220a5a4bf2c6860edb78d3022"
+ + "192fb5dc5e8c118f70870f89da292dfe522751462f020ed556653c8b07f8"
+ + "89712a6e8196c457a637439e3073d7d917ab55aa51a146826367f7b5922a"
+ + "64fb2f95099de21eb98341fa76faa79ffbda123fe5b8adc614b16174e8b0"
+ + "dfdac2bbc4d526d2487ad2b009d53996ec23ffbd732112efa66b02030100"
+ + "01a350304e301d0603551d0e04160414f66e1a95486c879edd60a5756bc2"
+ + "f1f4677e128e301f0603551d23041830168014f66e1a95486c879edd60a5"
+ + "756bc2f1f4677e128e300c0603551d13040530030101ff300d06092a8648"
+ + "86f70d01010b05000382010100d2856130dccae24e5f8901900d94bc642f"
+ + "85466ab7cfa1066399077a168cd4b56603a9e2af9d2e58aec13101e338a4"
+ + "8e95e9c7a84d7991f0d381d4965eaada1b80fbbd8277445f449babe64f53"
+ + "ba625387460b592a1a97b14b8251115e6610350021a6e716ae22b905f8d4"
+ + "eae24e668e71b12ab51fd2f2bb600e074487dec720c3db14dbca504844b6"
+ + "933bb0248283ea95464747689c37d706d4839c7d0e9bd86abf98ddce5d36"
+ + "8b38bfe5062353e28d5be378827fade1caa6bba3df9cd9ebf83d839eae52"
+ + "780181f31973f15f982686ba6d899f7b644fd1f26c8ebb99f4c986faaf4c"
+ + "1b9e3d9d391943ce3fb9fa2e631bd66b8ef3d47fd85acf09ea3a30f15f");
+
+ private static final X509Certificate TEST_CA_CERT;
+
+ static {
+ try {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ Certificate cert = factory.generateCertificate(new ByteArrayInputStream(TEST_CA_BYTES));
+ TEST_CA_CERT = (X509Certificate) cert;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
private static byte[] hexToBytes(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
@@ -51,7 +105,6 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
}
-
/**
* Return a NetworkSecurityConfig that has an empty TrustAnchor set. This should always cause a
* SSLHandshakeException when used for a connection.
@@ -174,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())
+ .setParent(NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N))
.build();
assert(!config.getTrustAnchors().isEmpty());
}
@@ -208,4 +261,38 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
TestUtils.assertUrlConnectionSucceeds(context, "developer.android.com", 443);
TestUtils.assertUrlConnectionFails(context, "google.com", 443);
}
+
+ public void testUserAddedCaOptIn() throws Exception {
+ TrustedCertificateStore store = new TrustedCertificateStore();
+ try {
+ // Install the test CA.
+ store.installCertificate(TEST_CA_CERT);
+ NetworkSecurityConfig preNConfig =
+ NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.M).build();
+ NetworkSecurityConfig nConfig =
+ NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N).build();
+ Set<TrustAnchor> preNAnchors = preNConfig.getTrustAnchors();
+ Set<TrustAnchor> nAnchors = nConfig.getTrustAnchors();
+ Set<X509Certificate> preNCerts = new HashSet<X509Certificate>();
+ for (TrustAnchor anchor : preNAnchors) {
+ preNCerts.add(anchor.certificate);
+ }
+ Set<X509Certificate> nCerts = new HashSet<X509Certificate>();
+ for (TrustAnchor anchor : nAnchors) {
+ nCerts.add(anchor.certificate);
+ }
+ assertTrue(preNCerts.contains(TEST_CA_CERT));
+ assertFalse(nCerts.contains(TEST_CA_CERT));
+ } finally {
+ // Delete the user added CA. We don't know the alias so just delete them all.
+ for (String alias : store.aliases()) {
+ if (store.isUser(alias)) {
+ try {
+ store.deleteCertificateEntry(alias);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+ }
}
diff --git a/tests/SoundTriggerTestApp/Android.mk b/tests/SoundTriggerTestApp/Android.mk
index 7bcab5e53772..c327b0956811 100644
--- a/tests/SoundTriggerTestApp/Android.mk
+++ b/tests/SoundTriggerTestApp/Android.mk
@@ -8,5 +8,6 @@ LOCAL_PACKAGE_NAME := SoundTriggerTestApp
LOCAL_MODULE_TAGS := optional
LOCAL_PRIVILEGED_MODULE := true
+LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
index 40619da156ee..dc4cdb59b8db 100644
--- a/tests/SoundTriggerTestApp/AndroidManifest.xml
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -2,16 +2,24 @@
package="com.android.test.soundtrigger">
<uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
- <application
- android:permission="android.permission.MANAGE_SOUND_TRIGGER">
+ <uses-permission android:name="android.permission.WAKE_LOCk" />
+ <application>
<activity
android:name="TestSoundTriggerActivity"
android:label="SoundTrigger Test Application"
- android:theme="@android:style/Theme.Material.Light.Voice">
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Material">
+ <!--
<intent-filter>
<action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ -->
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
</activity>
</application>
</manifest>
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 9d2b9d92c016..702be49aac7b 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -18,6 +18,11 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
>
<Button
@@ -37,7 +42,64 @@
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:text="@string/start_recog"
+ android:onClick="onStartRecognitionButtonClicked"
+ android:padding="20dp" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/stop_recog"
+ android:onClick="onStopRecognitionButtonClicked"
+ android:padding="20dp" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:text="@string/unenroll"
android:onClick="onUnEnrollButtonClicked"
android:padding="20dp" />
-</LinearLayout> \ No newline at end of file
+
+</LinearLayout>
+
+<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="20dp"
+ android:checkedButton="@+id/model_one"
+ android:orientation="vertical">
+ <RadioButton android:id="@+id/model_one"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/model_one"
+ android:onClick="onRadioButtonClicked"/>
+ <RadioButton android:id="@+id/model_two"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/model_two"
+ android:onClick="onRadioButtonClicked"/>
+ <RadioButton android:id="@+id/model_three"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/model_three"
+ android:onClick="onRadioButtonClicked"/>
+</RadioGroup>
+
+<ScrollView
+ android:id="@+id/scroller_id"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:fillViewport="true">
+
+ <TextView
+ android:id="@+id/console"
+ android:paddingTop="20pt"
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:textSize="14dp"
+ android:layout_weight="1.0"
+ android:text="@string/none">
+ </TextView>
+</ScrollView>
+</LinearLayout>
diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
index 07bac2a263ef..b4ca71b8286e 100644
--- a/tests/SoundTriggerTestApp/res/values/strings.xml
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -16,7 +16,13 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="enroll">Enroll</string>
- <string name="reenroll">Re-enroll</string>
- <string name="unenroll">Un-enroll</string>
-</resources> \ No newline at end of file
+ <string name="enroll">Load</string>
+ <string name="reenroll">Re-load</string>
+ <string name="unenroll">Un-load</string>
+ <string name="start_recog">Start</string>
+ <string name="stop_recog">Stop</string>
+ <string name="model_one">Model One</string>
+ <string name="model_two">Model Two</string>
+ <string name="model_three">Model Three</string>
+ <string name="none">Debug messages appear here:\n</string>
+</resources>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
index 4702835eae43..1c95c25370d2 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerDetector;
import android.media.soundtrigger.SoundTriggerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -28,6 +29,7 @@ import android.util.Log;
import com.android.internal.app.ISoundTriggerService;
+import java.lang.RuntimeException;
import java.util.UUID;
/**
@@ -56,6 +58,9 @@ public class SoundTriggerUtil {
*/
public boolean addOrUpdateSoundModel(GenericSoundModel soundModel) {
try {
+ if (soundModel == null) {
+ throw new RuntimeException("Bad sound model");
+ }
mSoundTriggerService.updateSoundModel(soundModel);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in updateSoundModel", e);
@@ -112,4 +117,10 @@ public class SoundTriggerUtil {
public void deleteSoundModelUsingManager(UUID modelId) {
mSoundTriggerManager.deleteModel(modelId);
}
+
+ public SoundTriggerDetector createSoundTriggerDetector(UUID modelId,
+ SoundTriggerDetector.Callback callback) {
+ return mSoundTriggerManager.createSoundTriggerDetector(modelId, callback, null);
+ }
+
}
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
index 966179b8dbd5..4770c056814c 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -22,11 +22,20 @@ import java.util.UUID;
import android.app.Activity;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.AudioFormat;
+import android.media.soundtrigger.SoundTriggerDetector;
import android.media.soundtrigger.SoundTriggerManager;
+import android.text.Editable;
+import android.text.method.ScrollingMovementMethod;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.PowerManager;
import android.os.UserManager;
import android.util.Log;
import android.view.View;
+import android.widget.RadioButton;
+import android.widget.ScrollView;
+import android.widget.TextView;
import android.widget.Toast;
public class TestSoundTriggerActivity extends Activity {
@@ -35,17 +44,87 @@ public class TestSoundTriggerActivity extends Activity {
private SoundTriggerUtil mSoundTriggerUtil;
private Random mRandom;
- private UUID mModelUuid = UUID.randomUUID();
+ private UUID mModelUuid1 = UUID.randomUUID();
private UUID mModelUuid2 = UUID.randomUUID();
+ private UUID mModelUuid3 = UUID.randomUUID();
private UUID mVendorUuid = UUID.randomUUID();
+ private SoundTriggerDetector mDetector1 = null;
+ private SoundTriggerDetector mDetector2 = null;
+ private SoundTriggerDetector mDetector3 = null;
+
+ private TextView mDebugView = null;
+ private int mSelectedModelId = 1;
+ private ScrollView mScrollView = null;
+ private PowerManager.WakeLock mScreenWakelock;
+ private Handler mHandler;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DBG) Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
+ mDebugView = (TextView) findViewById(R.id.console);
+ mScrollView = (ScrollView) findViewById(R.id.scroller_id);
+ mDebugView.setText(mDebugView.getText(), TextView.BufferType.EDITABLE);
+ mDebugView.setMovementMethod(new ScrollingMovementMethod());
mSoundTriggerUtil = new SoundTriggerUtil(this);
mRandom = new Random();
+ mHandler = new Handler();
+ }
+
+ private void postMessage(String msg) {
+ Log.i(TAG, "Posted: " + msg);
+ ((Editable) mDebugView.getText()).append(msg + "\n");
+ if ((mDebugView.getMeasuredHeight() - mScrollView.getScrollY()) <=
+ (mScrollView.getHeight() + mDebugView.getLineHeight())) {
+ scrollToBottom();
+ }
+ }
+
+ private void scrollToBottom() {
+ mScrollView.post(new Runnable() {
+ public void run() {
+ mScrollView.smoothScrollTo(0, mDebugView.getBottom());
+ }
+ });
+ }
+
+ private synchronized UUID getSelectedUuid() {
+ if (mSelectedModelId == 2) return mModelUuid2;
+ if (mSelectedModelId == 3) return mModelUuid3;
+ return mModelUuid1; // Default.
+ }
+
+ private synchronized void setDetector(SoundTriggerDetector detector) {
+ if (mSelectedModelId == 2) {
+ mDetector2 = detector;
+ return;
+ }
+ if (mSelectedModelId == 3) {
+ mDetector3 = detector;
+ return;
+ }
+ mDetector1 = detector;
+ }
+
+ private synchronized SoundTriggerDetector getDetector() {
+ if (mSelectedModelId == 2) return mDetector2;
+ if (mSelectedModelId == 3) return mDetector3;
+ return mDetector1;
+ }
+
+ private void screenWakeup() {
+ PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE));
+ if (mScreenWakelock == null) {
+ mScreenWakelock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG");
+ }
+ mScreenWakelock.acquire();
+ }
+
+ private void screenRelease() {
+ PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE));
+ mScreenWakelock.release();
}
/**
@@ -53,24 +132,23 @@ public class TestSoundTriggerActivity extends Activity {
* Performs a fresh enrollment.
*/
public void onEnrollButtonClicked(View v) {
+ postMessage("Loading model: " + mSelectedModelId);
// Generate a fake model to push.
byte[] data = new byte[1024];
mRandom.nextBytes(data);
- GenericSoundModel model = new GenericSoundModel(mModelUuid, mVendorUuid, data);
+ UUID modelUuid = getSelectedUuid();
+ GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(model);
if (status) {
Toast.makeText(
- this, "Successfully created sound trigger model UUID=" + mModelUuid, Toast.LENGTH_SHORT)
- .show();
+ this, "Successfully created sound trigger model UUID=" + modelUuid,
+ Toast.LENGTH_SHORT).show();
} else {
- Toast.makeText(this, "Failed to enroll!!!" + mModelUuid, Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, "Failed to enroll!!!" + modelUuid, Toast.LENGTH_SHORT).show();
}
// Test the SoundManager API.
- SoundTriggerManager.Model tmpModel = SoundTriggerManager.Model.create(mModelUuid2,
- mVendorUuid, data);
- mSoundTriggerUtil.addOrUpdateSoundModel(tmpModel);
}
/**
@@ -78,12 +156,14 @@ public class TestSoundTriggerActivity extends Activity {
* Clears the enrollment information for the user.
*/
public void onUnEnrollButtonClicked(View v) {
- GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(mModelUuid);
+ postMessage("Unloading model: " + mSelectedModelId);
+ UUID modelUuid = getSelectedUuid();
+ GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
if (soundModel == null) {
Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
return;
}
- boolean status = mSoundTriggerUtil.deleteSoundModel(mModelUuid);
+ boolean status = mSoundTriggerUtil.deleteSoundModel(modelUuid);
if (status) {
Toast.makeText(this, "Successfully deleted model UUID=" + soundModel.uuid,
Toast.LENGTH_SHORT)
@@ -91,7 +171,6 @@ public class TestSoundTriggerActivity extends Activity {
} else {
Toast.makeText(this, "Failed to delete sound model!!!", Toast.LENGTH_SHORT).show();
}
- mSoundTriggerUtil.deleteSoundModelUsingManager(mModelUuid2);
}
/**
@@ -99,7 +178,9 @@ public class TestSoundTriggerActivity extends Activity {
* Uses the previously enrolled sound model and makes changes to it before pushing it back.
*/
public void onReEnrollButtonClicked(View v) {
- GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(mModelUuid);
+ postMessage("Re-loading model: " + mSelectedModelId);
+ UUID modelUuid = getSelectedUuid();
+ GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
if (soundModel == null) {
Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
return;
@@ -118,4 +199,105 @@ public class TestSoundTriggerActivity extends Activity {
Toast.makeText(this, "Failed to re-enroll!!!", Toast.LENGTH_SHORT).show();
}
}
+
+ public void onStartRecognitionButtonClicked(View v) {
+ UUID modelUuid = getSelectedUuid();
+ SoundTriggerDetector detector = getDetector();
+ if (detector == null) {
+ Log.i(TAG, "Created an instance of the SoundTriggerDetector for model #" +
+ mSelectedModelId);
+ postMessage("Created an instance of the SoundTriggerDetector for model #" +
+ mSelectedModelId);
+ detector = mSoundTriggerUtil.createSoundTriggerDetector(modelUuid,
+ new DetectorCallback());
+ setDetector(detector);
+ }
+ postMessage("Triggering start recognition for model: " + mSelectedModelId);
+ if (!detector.startRecognition(
+ SoundTriggerDetector.RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS)) {
+ Log.e(TAG, "Fast failure attempting to start recognition.");
+ postMessage("Fast failure attempting to start recognition:" + mSelectedModelId);
+ }
+ }
+
+ public void onStopRecognitionButtonClicked(View v) {
+ SoundTriggerDetector detector = getDetector();
+ if (detector == null) {
+ Log.e(TAG, "Stop called on null detector.");
+ postMessage("Error: Stop called on null detector.");
+ return;
+ }
+ postMessage("Triggering stop recognition for model: " + mSelectedModelId);
+ if (!detector.stopRecognition()) {
+ Log.e(TAG, "Fast failure attempting to stop recognition.");
+ postMessage("Fast failure attempting to stop recognition: " + mSelectedModelId);
+ }
+ }
+
+ public synchronized void onRadioButtonClicked(View view) {
+ // Is the button now checked?
+ boolean checked = ((RadioButton) view).isChecked();
+ // Check which radio button was clicked
+ switch(view.getId()) {
+ case R.id.model_one:
+ if (checked) {
+ mSelectedModelId = 1;
+ postMessage("Selected model one.");
+ }
+ break;
+ case R.id.model_two:
+ if (checked) {
+ mSelectedModelId = 2;
+ postMessage("Selected model two.");
+ }
+ break;
+ case R.id.model_three:
+ if (checked) {
+ mSelectedModelId = 3;
+ postMessage("Selected model three.");
+ }
+ break;
+ }
+ }
+
+ // Implementation of SoundTriggerDetector.Callback.
+ public class DetectorCallback extends SoundTriggerDetector.Callback {
+ public void onAvailabilityChanged(int status) {
+ postMessage("Availability changed to: " + status);
+ }
+
+ public void onDetected(SoundTriggerDetector.EventPayload event) {
+ postMessage("onDetected(): " + eventPayloadToString(event));
+ screenWakeup();
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ screenRelease();
+ }
+ }, 1000L);
+ }
+
+ public void onError() {
+ postMessage("onError()");
+ }
+
+ public void onRecognitionPaused() {
+ postMessage("onRecognitionPaused()");
+ }
+
+ public void onRecognitionResumed() {
+ postMessage("onRecognitionResumed()");
+ }
+ }
+
+ private String eventPayloadToString(SoundTriggerDetector.EventPayload event) {
+ String result = "EventPayload(";
+ AudioFormat format = event.getCaptureAudioFormat();
+ result = result + "AudioFormat: " + ((format == null) ? "null" : format.toString());
+ byte[] triggerAudio = event.getTriggerAudio();
+ result = result + "TriggerAudio: " + (triggerAudio == null ? "null" : triggerAudio.length);
+ result = result + "CaptureSession: " + event.getCaptureSession();
+ result += " )";
+ return result;
+ }
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 3a30230833ed..2a3f14340a39 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -37,6 +37,7 @@ import android.os.PowerManager;
// private NM API
import android.app.INotificationManager;
+import android.widget.Toast;
public class NotificationTestList extends TestActivity
{
@@ -85,6 +86,122 @@ public class NotificationTestList extends TestActivity
}
private Test[] mTests = new Test[] {
+ new Test("Min priority") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("Min priority")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_MIN)
+ .setFullScreenIntent(makeIntent2(), false)
+ .build();
+ mNM.notify(7000, n);
+ }
+ },
+ new Test("Min priority, high pri flag") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("Min priority, high pri flag")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_MIN)
+ .setFullScreenIntent(makeIntent2(), true)
+ .build();
+ mNM.notify(7001, n);
+ }
+ },
+ new Test("Low priority") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("Low priority")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_LOW)
+ .setFullScreenIntent(makeIntent2(), false)
+ .build();
+ mNM.notify(7002, n);
+ }
+ },
+ new Test("Default priority") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("Default priority")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setFullScreenIntent(makeIntent2(), false)
+ .build();
+ mNM.notify(7004, n);
+ }
+ },
+ new Test("High priority") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("High priority")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setFullScreenIntent(makeIntent2(), false)
+ .build();
+ mNM.notify(7006, n);
+ }
+ },
+ new Test("Max priority") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("Max priority")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_MAX)
+ .setFullScreenIntent(makeIntent2(), false)
+ .build();
+ mNM.notify(7008, n);
+ }
+ },
+ new Test("Max priority with delay") {
+ public void run()
+ {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ }
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("Max priority")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .setPriority(Notification.PRIORITY_MAX)
+ .setFullScreenIntent(makeIntent2(), false)
+ .build();
+ mNM.notify(7008, n);
+ }
+ },
new Test("Off") {
public void run() {
PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
@@ -161,75 +278,19 @@ public class NotificationTestList extends TestActivity
}
},
- new Test("with topic Hello") {
- public void run() {
- Notification.BigTextStyle bigText = new Notification.BigTextStyle();
- bigText.bigText("FgBHreherhethethethe\ntwetwrterter\netetweterteryetry");
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setStyle(bigText)
- .setWhen(mActivityCreateTime)
- .setContentTitle("hihi")
- .setContentText("This is a notification!!!")
- .setContentIntent(makeIntent2())
- .setTopic(new Notification.Topic("hello", "Hello"))
- .build();
-
- mNM.notify(70, n);
- }
- },
-
- new Test("with topic GoodBye") {
- public void run() {
- Notification.BigPictureStyle picture = new Notification.BigPictureStyle();
- picture.bigPicture(BitmapFactory.decodeResource(getResources(),
- R.id.large_icon_pineapple2));
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setWhen(mActivityCreateTime)
- .setContentTitle("byebye")
- .setContentText("This is a notification!!!")
- .setContentIntent(makeIntent2())
- .setTopic(new Notification.Topic("bye", "Goodbye"))
- .setStyle(picture)
- .build();
-
- mNM.notify(71, n);
- }
- },
- new Test("with topic Bananas") {
- public void run() {
- Notification.BigTextStyle bigText = new Notification.BigTextStyle();
- bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setStyle(bigText)
- .setWhen(mActivityCreateTime)
- .setContentTitle("bananananana")
- .setContentText("This is a banana!!!")
- .setContentIntent(makeIntent2())
- .setTopic(new Notification.Topic("bananas", "Bananas"))
- .build();
-
- mNM.notify(72, n);
- }
- },
-
- new Test("with delete intent") {
+ new Test("Is blocked?") {
public void run() {
- Notification.BigTextStyle bigText = new Notification.BigTextStyle();
- bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setStyle(bigText)
- .setWhen(mActivityCreateTime)
- .setContentTitle("bananananana")
- .setContentText("This is a banana!!!")
- .setTopic(new Notification.Topic("bananas", "Bananas"))
- .setDeleteIntent(makeIntent2())
- .build();
+ Toast.makeText(NotificationTestList.this,
+ "package enabled? " + mNM.areNotificationsEnabled(),
+ Toast.LENGTH_LONG).show();
+ }
+ },
- mNM.notify(73, n);
+ new Test("importance?") {
+ public void run() {
+ Toast.makeText(NotificationTestList.this,
+ "importance? " + mNM.getImportance(),
+ Toast.LENGTH_LONG).show();
}
},
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
index d4c661027a35..4556b0263b6e 100644
--- a/tests/UiBench/res/layout/activity_transition.xml
+++ b/tests/UiBench/res/layout/activity_transition.xml
@@ -15,6 +15,7 @@
~ limitations under the License
-->
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/transition_grid_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
@@ -25,8 +26,6 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:scaleType="centerCrop"
- android:layout_column="0"
- android:layout_row="0"
android:src="@drawable/ducky"
android:onClick="clicked"
android:transitionName="ducky"/>
@@ -36,8 +35,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/woot"
- android:layout_column="1"
- android:layout_row="0"
android:onClick="clicked"
android:transitionName="woot"/>
<ImageView
@@ -46,8 +43,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/ball"
- android:layout_column="0"
- android:layout_row="1"
android:onClick="clicked"
android:transitionName="ball"/>
<ImageView
@@ -56,8 +51,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/block"
- android:layout_column="1"
- android:layout_row="1"
android:onClick="clicked"
android:transitionName="block"/>
<ImageView
@@ -66,8 +59,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/jellies"
- android:layout_column="0"
- android:layout_row="2"
android:onClick="clicked"
android:transitionName="jellies"/>
<ImageView
@@ -76,8 +67,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/mug"
- android:layout_column="1"
- android:layout_row="2"
android:onClick="clicked"
android:transitionName="mug"/>
<ImageView
@@ -86,8 +75,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/pencil"
- android:layout_column="0"
- android:layout_row="3"
android:onClick="clicked"
android:transitionName="pencil"/>
<ImageView
@@ -96,8 +83,6 @@
android:layout_width="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/scissors"
- android:layout_column="1"
- android:layout_row="3"
android:onClick="clicked"
android:transitionName="scissors"/>
</GridLayout> \ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
index 1106a13bfc2a..0a069c269697 100644
--- a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
@@ -18,11 +18,13 @@ package com.android.test.uibench;
import android.app.ActivityOptions;
import android.app.SharedElementCallback;
import android.content.Intent;
+import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
+import android.widget.GridLayout;
import android.widget.ImageView;
import java.util.List;
@@ -90,6 +92,13 @@ public class ActivityTransition extends AppCompatActivity {
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
setContentView(R.layout.activity_transition);
setupHero();
+
+ // Ensure that all images are visible regardless of orientation.
+ GridLayout gridLayout = (GridLayout) findViewById(R.id.transition_grid_layout);
+ boolean isPortrait =
+ getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+ gridLayout.setRowCount(isPortrait ? 4 : 2);
+ gridLayout.setColumnCount(isPortrait ? 2 : 4);
}
private void setupHero() {
diff --git a/tests/touchlag/Android.mk b/tests/touchlag/Android.mk
index 4f8aa1e60ca8..70b198917547 100644
--- a/tests/touchlag/Android.mk
+++ b/tests/touchlag/Android.mk
@@ -9,6 +9,8 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE:= test-touchlag
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
diff --git a/tests/touchlag/touchlag.cpp b/tests/touchlag/touchlag.cpp
index df4befb95fb9..9264a254ed24 100644
--- a/tests/touchlag/touchlag.cpp
+++ b/tests/touchlag/touchlag.cpp
@@ -54,11 +54,11 @@ void clearBuffer(Buffer* buf, uint32_t pixel) {
void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
if (y>0 && y<ssize_t(buf->h)) {
uint32_t* bits = buf->pixels + y * buf->s;
- if (x>=0 && x<buf->w) {
+ if (x>=0 && x<ssize_t(buf->w)) {
bits[x] = pixel;
}
ssize_t W(w);
- if ((x+W)>=0 && (x+W)<buf->w) {
+ if ((x+W)>=0 && (x+W)<ssize_t(buf->w)) {
bits[x+W] = pixel;
}
}
@@ -251,13 +251,13 @@ int main(int argc, char** argv) {
Queue queue;
- int x=0, y=0, down=0;
+ int x=0, y=0;
int lag_x=0, lag_y=0;
clearBuffer(&framebuffer, 0);
while (true) {
uint32_t crt = 0;
- int err = ioctl(fd, FBIO_WAITFORVSYNC, &crt);
+ ioctl(fd, FBIO_WAITFORVSYNC, &crt);
// draw beam marker
drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 4d9ba6c95d9e..18a194326de7 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1883,8 +1883,6 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
//printf("Comment of %s: %s\n", String8(e).string(),
// String8(cmt).string());
syms->appendComment(String8(e), String16(cmt), srcPos);
- } else {
- //printf("No comment for %s\n", String8(e).string());
}
syms->makeSymbolPublic(String8(e), srcPos);
} else if (strcmp16(block.getElementName(&len), uses_permission16.string()) == 0) {
@@ -2535,10 +2533,6 @@ static status_t writeSymbolClass(
fprintf(fp,
"%s/** %s\n",
getIndentSpace(indent), cmt.string());
- } else if (sym.isPublic && !includePrivate) {
- sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
- assets->getPackage().string(), className.string(),
- String8(sym.name).string());
}
String16 typeComment(sym.typeComment);
if (typeComment.size() > 0) {
@@ -2581,10 +2575,6 @@ static status_t writeSymbolClass(
"%s */\n",
getIndentSpace(indent), cmt.string(),
getIndentSpace(indent));
- } else if (sym.isPublic && !includePrivate) {
- sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
- assets->getPackage().string(), className.string(),
- String8(sym.name).string());
}
ann.printAnnotations(fp, getIndentSpace(indent));
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index e87c7d40f1d4..6a4b63789815 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -308,29 +308,11 @@ struct PendingAttribute
}
added = true;
- String16 attr16("attr");
-
- if (outTable->hasBagOrEntry(myPackage, attr16, ident)) {
- sourcePos.error("Attribute \"%s\" has already been defined\n",
- String8(ident).string());
+ if (!outTable->makeAttribute(myPackage, ident, sourcePos, type, comment, appendComment)) {
hasErrors = true;
return UNKNOWN_ERROR;
}
-
- char numberStr[16];
- sprintf(numberStr, "%d", type);
- status_t err = outTable->addBag(sourcePos, myPackage,
- attr16, ident, String16(""),
- String16("^type"),
- String16(numberStr), NULL, NULL);
- if (err != NO_ERROR) {
- hasErrors = true;
- return err;
- }
- outTable->appendComment(myPackage, attr16, ident, comment, appendComment);
- //printf("Attribute %s comment: %s\n", String8(ident).string(),
- // String8(comment).string());
- return err;
+ return NO_ERROR;
}
};
@@ -2115,6 +2097,61 @@ bool ResourceTable::appendTypeComment(const String16& package,
return false;
}
+bool ResourceTable::makeAttribute(const String16& package,
+ const String16& name,
+ const SourcePos& source,
+ int32_t format,
+ const String16& comment,
+ bool shouldAppendComment) {
+ const String16 attr16("attr");
+
+ // First look for this in the included resources...
+ uint32_t rid = mAssets->getIncludedResources()
+ .identifierForName(name.string(), name.size(),
+ attr16.string(), attr16.size(),
+ package.string(), package.size());
+ if (rid != 0) {
+ source.error("Attribute \"%s\" has already been defined", String8(name).string());
+ return false;
+ }
+
+ sp<ResourceTable::Entry> entry = getEntry(package, attr16, name, source, false);
+ if (entry == NULL) {
+ source.error("Failed to create entry attr/%s", String8(name).string());
+ return false;
+ }
+
+ if (entry->makeItABag(source) != NO_ERROR) {
+ return false;
+ }
+
+ const String16 formatKey16("^type");
+ const String16 formatValue16(String8::format("%d", format));
+
+ ssize_t idx = entry->getBag().indexOfKey(formatKey16);
+ if (idx >= 0) {
+ // We have already set a format for this attribute, check if they are different.
+ // We allow duplicate attribute definitions so long as they are identical.
+ // This is to ensure inter-operation with libraries that define the same generic attribute.
+ const Item& formatItem = entry->getBag().valueAt(idx);
+ if ((format & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) ||
+ formatItem.value != formatValue16) {
+ source.error("Attribute \"%s\" already defined with incompatible format.\n"
+ "%s:%d: Original attribute defined here.",
+ String8(name).string(), formatItem.sourcePos.file.string(),
+ formatItem.sourcePos.line);
+ return false;
+ }
+ } else {
+ entry->addToBag(source, formatKey16, formatValue16);
+ // Increment the number of resources we have. This is used to determine if we should
+ // even generate a resource table.
+ mNumLocal++;
+ }
+ appendComment(package, attr16, name, comment, shouldAppendComment);
+ return true;
+}
+
void ResourceTable::canAddEntry(const SourcePos& pos,
const String16& package, const String16& type, const String16& name)
{
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 4b7b3cdcef2b..cf1e992ec330 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -571,6 +571,18 @@ public:
void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
+ /**
+ * Make an attribute with the specified format. If another attribute with the same name but
+ * different format exists, this method returns false. If the name is not taken, or if the
+ * format is identical, this returns true.
+ */
+ bool makeAttribute(const String16& package,
+ const String16& name,
+ const SourcePos& source,
+ int32_t format,
+ const String16& comment,
+ bool appendComment);
+
private:
void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
sp<Package> getPackage(const String16& package);
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index f74b93abd796..f9d35aba86d2 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -38,11 +38,16 @@ sources := \
io/ZipArchive.cpp \
link/AutoVersioner.cpp \
link/ManifestFixer.cpp \
+ link/ProductFilter.cpp \
link/PrivateAttributeMover.cpp \
link/ReferenceLinker.cpp \
link/TableMerger.cpp \
link/XmlReferenceLinker.cpp \
process/SymbolTable.cpp \
+ proto/ProtoHelpers.cpp \
+ proto/TableProtoDeserializer.cpp \
+ proto/TableProtoSerializer.cpp \
+ split/TableSplitter.cpp \
unflatten/BinaryResourceParser.cpp \
unflatten/ResChunkPullParser.cpp \
util/BigBuffer.cpp \
@@ -67,23 +72,26 @@ sources := \
xml/XmlPullParser.cpp \
xml/XmlUtil.cpp
+sources += Format.proto
+
testSources := \
compile/IdAssigner_test.cpp \
compile/PseudolocaleGenerator_test.cpp \
compile/Pseudolocalizer_test.cpp \
compile/XmlIdCollector_test.cpp \
filter/ConfigFilter_test.cpp \
- flatten/FileExportWriter_test.cpp \
flatten/TableFlattener_test.cpp \
flatten/XmlFlattener_test.cpp \
link/AutoVersioner_test.cpp \
link/ManifestFixer_test.cpp \
link/PrivateAttributeMover_test.cpp \
+ link/ProductFilter_test.cpp \
link/ReferenceLinker_test.cpp \
link/TableMerger_test.cpp \
link/XmlReferenceLinker_test.cpp \
process/SymbolTable_test.cpp \
- unflatten/FileExportHeaderReader_test.cpp \
+ proto/TableProtoSerializer_test.cpp \
+ split/TableSplitter_test.cpp \
util/BigBuffer_test.cpp \
util/Maybe_test.cpp \
util/StringPiece_test.cpp \
@@ -97,6 +105,7 @@ testSources := \
ResourceParser_test.cpp \
ResourceTable_test.cpp \
ResourceUtils_test.cpp \
+ SdkConstants_test.cpp \
StringPool_test.cpp \
ValueVisitor_test.cpp \
xml/XmlDom_test.cpp \
@@ -105,6 +114,7 @@ testSources := \
toolSources := \
compile/Compile.cpp \
+ dump/Dump.cpp \
link/Link.cpp
hostLdLibs :=
@@ -119,6 +129,9 @@ hostStaticLibs := \
libpng \
libbase
+hostSharedLibs := \
+ libprotobuf-cpp-lite
+
ifneq ($(strip $(USE_MINGW)),)
hostStaticLibs += libz
else
@@ -127,21 +140,23 @@ endif
cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG
cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions -fno-rtti
+protoIncludes := $(call generated-sources-dir-for,STATIC_LIBRARIES,libaapt2,HOST)
# ==========================================================
# Build the host static library: libaapt2
# ==========================================================
include $(CLEAR_VARS)
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE := libaapt2
LOCAL_SRC_FILES := $(sources)
LOCAL_STATIC_LIBRARIES += $(hostStaticLibs)
LOCAL_CFLAGS += $(cFlags)
LOCAL_CPPFLAGS += $(cppFlags)
+LOCAL_C_INCLUDES += $(protoIncludes)
include $(BUILD_HOST_STATIC_LIBRARY)
-
# ==========================================================
# Build the host tests: libaapt2_tests
# ==========================================================
@@ -152,9 +167,11 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(testSources)
LOCAL_STATIC_LIBRARIES += libaapt2 $(hostStaticLibs)
+LOCAL_SHARED_LIBRARIES += $(hostSharedLibs)
LOCAL_LDLIBS += $(hostLdLibs)
LOCAL_CFLAGS += $(cFlags)
LOCAL_CPPFLAGS += $(cppFlags)
+LOCAL_C_INCLUDES += $(protoIncludes)
include $(BUILD_HOST_NATIVE_TEST)
@@ -167,9 +184,11 @@ LOCAL_MODULE := aapt2
LOCAL_SRC_FILES := $(main) $(toolSources)
LOCAL_STATIC_LIBRARIES += libaapt2 $(hostStaticLibs)
+LOCAL_SHARED_LIBRARIES += $(hostSharedLibs)
LOCAL_LDLIBS += $(hostLdLibs)
LOCAL_CFLAGS += $(cFlags)
LOCAL_CPPFLAGS += $(cppFlags)
+LOCAL_C_INCLUDES += $(protoIncludes)
include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index b4e75f9be3a9..19bd5210c840 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -30,7 +30,8 @@
namespace aapt {
-struct PrintVisitor : public ValueVisitor {
+class PrintVisitor : public ValueVisitor {
+public:
using ValueVisitor::visit;
void visit(Attribute* attr) override {
@@ -69,7 +70,11 @@ struct PrintVisitor : public ValueVisitor {
for (const auto& entry : style->entries) {
std::cout << "\n ";
if (entry.key.name) {
- std::cout << entry.key.name.value().package << ":" << entry.key.name.value().entry;
+ const ResourceName& name = entry.key.name.value();
+ if (!name.package.empty()) {
+ std::cout << name.package << ":";
+ }
+ std::cout << name.entry;
}
if (entry.key.id) {
@@ -89,7 +94,21 @@ struct PrintVisitor : public ValueVisitor {
}
void visit(Styleable* styleable) override {
- styleable->print(&std::cout);
+ std::cout << "(styleable)";
+ for (const auto& attr : styleable->entries) {
+ std::cout << "\n ";
+ if (attr.name) {
+ const ResourceName& name = attr.name.value();
+ if (!name.package.empty()) {
+ std::cout << name.package << ":";
+ }
+ std::cout << name.entry;
+ }
+
+ if (attr.id) {
+ std::cout << "(" << attr.id.value() << ")";
+ }
+ }
}
void visitItem(Item* item) override {
@@ -97,7 +116,9 @@ struct PrintVisitor : public ValueVisitor {
}
};
-void Debug::printTable(ResourceTable* table) {
+void Debug::printTable(ResourceTable* table, const DebugPrintTableOptions& options) {
+ PrintVisitor visitor;
+
for (auto& package : table->packages) {
std::cout << "Package name=" << package->name;
if (package->id) {
@@ -106,7 +127,7 @@ void Debug::printTable(ResourceTable* table) {
std::cout << std::endl;
for (const auto& type : package->types) {
- std::cout << " type " << type->type;
+ std::cout << "\n type " << type->type;
if (type->id) {
std::cout << " id=" << std::hex << (int) type->id.value() << std::dec;
}
@@ -142,10 +163,12 @@ void Debug::printTable(ResourceTable* table) {
std::cout << std::endl;
- PrintVisitor visitor;
for (const auto& value : entry->values) {
- std::cout << " (" << value.config << ") ";
- value.value->accept(&visitor);
+ std::cout << " (" << value->config << ") ";
+ value->value->accept(&visitor);
+ if (options.showSources && !value->value->getSource().path.empty()) {
+ std::cout << " src=" << value->value->getSource();
+ }
std::cout << std::endl;
}
}
@@ -176,7 +199,7 @@ void Debug::printStyleGraph(ResourceTable* table, const ResourceName& targetStyl
if (result) {
ResourceEntry* entry = result.value().entry;
for (const auto& value : entry->values) {
- if (Style* style = valueCast<Style>(value.value.get())) {
+ if (Style* style = valueCast<Style>(value->value.get())) {
if (style->parent && style->parent.value().name) {
parents.insert(style->parent.value().name.value());
stylesToVisit.push(style->parent.value().name.value());
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index ba05be91e91d..fbe64773d4ed 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -25,8 +25,12 @@
namespace aapt {
+struct DebugPrintTableOptions {
+ bool showSources = false;
+};
+
struct Debug {
- static void printTable(ResourceTable* table);
+ static void printTable(ResourceTable* table, const DebugPrintTableOptions& options = {});
static void printStyleGraph(ResourceTable* table,
const ResourceName& targetStyle);
static void dumpHex(const void* data, size_t len);
diff --git a/tools/aapt2/Format.proto b/tools/aapt2/Format.proto
new file mode 100644
index 000000000000..d05425c5c64d
--- /dev/null
+++ b/tools/aapt2/Format.proto
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package aapt.pb;
+
+message ConfigDescription {
+ optional bytes data = 1;
+ optional string product = 2;
+}
+
+message StringPool {
+ optional bytes data = 1;
+}
+
+message CompiledFile {
+ message Symbol {
+ optional string resource_name = 1;
+ optional uint32 line_no = 2;
+ }
+
+ optional string resource_name = 1;
+ optional ConfigDescription config = 2;
+ optional string source_path = 3;
+ repeated Symbol exported_symbols = 4;
+}
+
+message ResourceTable {
+ optional StringPool string_pool = 1;
+ optional StringPool source_pool = 2;
+ optional StringPool symbol_pool = 3;
+ repeated Package packages = 4;
+}
+
+message Package {
+ optional uint32 package_id = 1;
+ optional string package_name = 2;
+ repeated Type types = 3;
+}
+
+message Type {
+ optional uint32 id = 1;
+ optional string name = 2;
+ repeated Entry entries = 3;
+}
+
+message SymbolStatus {
+ enum Visibility {
+ Unknown = 0;
+ Private = 1;
+ Public = 2;
+ }
+ optional Visibility visibility = 1;
+ optional Source source = 2;
+ optional string comment = 3;
+}
+
+message Entry {
+ optional uint32 id = 1;
+ optional string name = 2;
+ optional SymbolStatus symbol_status = 3;
+ repeated ConfigValue config_values = 4;
+}
+
+message ConfigValue {
+ optional ConfigDescription config = 1;
+ optional Value value = 2;
+}
+
+message Source {
+ optional uint32 path_idx = 1;
+ optional uint32 line_no = 2;
+ optional uint32 col_no = 3;
+}
+
+message Reference {
+ enum Type {
+ Ref = 0;
+ Attr = 1;
+ }
+ optional Type type = 1;
+ optional uint32 id = 2;
+ optional uint32 symbol_idx = 3;
+ optional bool private = 4;
+}
+
+message Id {
+}
+
+message String {
+ optional uint32 idx = 1;
+}
+
+message RawString {
+ optional uint32 idx = 1;
+}
+
+message FileReference {
+ optional uint32 path_idx = 1;
+}
+
+message Primitive {
+ optional uint32 type = 1;
+ optional uint32 data = 2;
+}
+
+message Attribute {
+ message Symbol {
+ optional Source source = 1;
+ optional string comment = 2;
+ optional Reference name = 3;
+ optional uint32 value = 4;
+ }
+ optional uint32 format_flags = 1;
+ optional int32 min_int = 2;
+ optional int32 max_int = 3;
+ repeated Symbol symbols = 4;
+}
+
+message Style {
+ message Entry {
+ optional Source source = 1;
+ optional string comment = 2;
+ optional Reference key = 3;
+ optional Item item = 4;
+ }
+
+ optional Reference parent = 1;
+ optional Source parent_source = 2;
+ repeated Entry entries = 3;
+}
+
+message Styleable {
+ message Entry {
+ optional Source source = 1;
+ optional string comment = 2;
+ optional Reference attr = 3;
+ }
+ repeated Entry entries = 1;
+}
+
+message Array {
+ message Entry {
+ optional Source source = 1;
+ optional string comment = 2;
+ optional Item item = 3;
+ }
+ repeated Entry entries = 1;
+}
+
+message Plural {
+ enum Arity {
+ Zero = 0;
+ One = 1;
+ Two = 2;
+ Few = 3;
+ Many = 4;
+ Other = 5;
+ }
+
+ message Entry {
+ optional Source source = 1;
+ optional string comment = 2;
+ optional Arity arity = 3;
+ optional Item item = 4;
+ }
+ repeated Entry entries = 1;
+}
+
+message Item {
+ optional Reference ref = 1;
+ optional String str = 2;
+ optional RawString raw_str = 3;
+ optional FileReference file = 4;
+ optional Id id = 5;
+ optional Primitive prim = 6;
+}
+
+message CompoundValue {
+ optional Attribute attr = 1;
+ optional Style style = 2;
+ optional Styleable styleable = 3;
+ optional Array array = 4;
+ optional Plural plural = 5;
+}
+
+message Value {
+ optional Source source = 1;
+ optional string comment = 2;
+ optional bool weak = 3;
+
+ optional Item item = 4;
+ optional CompoundValue compound_value = 5;
+}
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 248e7ad73a82..a2fadd95db3f 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -23,6 +23,7 @@ namespace aapt {
extern int compile(const std::vector<StringPiece>& args);
extern int link(const std::vector<StringPiece>& args);
+extern int dump(const std::vector<StringPiece>& args);
} // namespace aapt
@@ -41,12 +42,14 @@ int main(int argc, char** argv) {
return aapt::compile(args);
} else if (command == "link" || command == "l") {
return aapt::link(args);
+ } else if (command == "dump" || command == "d") {
+ return aapt::dump(args);
}
std::cerr << "unknown command '" << command << "'\n";
} else {
std::cerr << "no command specified\n";
}
- std::cerr << "\nusage: aapt2 [compile|link] ..." << std::endl;
+ std::cerr << "\nusage: aapt2 [compile|link|dump] ..." << std::endl;
return 1;
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index b37d366a7887..b100e84f8a46 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -19,7 +19,6 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
-#include "util/Comparators.h"
#include "util/ImmutableMap.h"
#include "util/Util.h"
#include "xml/XmlPullParser.h"
@@ -71,6 +70,7 @@ static uint32_t parseFormatAttribute(const StringPiece16& str) {
struct ParsedResource {
ResourceName name;
ConfigDescription config;
+ std::string product;
Source source;
ResourceId id;
Maybe<SymbolState> symbolState;
@@ -79,35 +79,6 @@ struct ParsedResource {
std::list<ParsedResource> childResources;
};
-bool ResourceParser::shouldStripResource(const ResourceNameRef& name,
- const Maybe<std::u16string>& product) const {
- if (product) {
- for (const std::u16string& productToMatch : mOptions.products) {
- if (product.value() == productToMatch) {
- // We specified a product, and it is in the list, so don't strip.
- return false;
- }
- }
- }
-
- // Nothing matched, try 'default'. Default only matches if we didn't already use another
- // product variant.
- if (!product || product.value() == u"default") {
- if (Maybe<ResourceTable::SearchResult> result = mTable->findResource(name)) {
- const ResourceEntry* entry = result.value().entry;
- auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), mConfig,
- cmp::lessThanConfig);
- if (iter != entry->values.end() && iter->config == mConfig && !iter->value->isWeak()) {
- // We have a value for this config already, and it is not weak,
- // so filter out this default.
- return true;
- }
- }
- return false;
- }
- return true;
-}
-
// Recursively adds resources to the ResourceTable.
static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
if (res->symbolState) {
@@ -125,7 +96,8 @@ static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
res->value->setComment(std::move(res->comment));
res->value->setSource(std::move(res->source));
- if (!table->addResource(res->name, res->id, res->config, std::move(res->value), diag)) {
+ if (!table->addResource(res->name, res->id, res->config, res->product,
+ std::move(res->value), diag)) {
return false;
}
}
@@ -295,9 +267,8 @@ bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
parsedResource.comment = std::move(comment);
// Extract the product name if it exists.
- Maybe<std::u16string> product;
if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
- product = maybeProduct.value().toString();
+ parsedResource.product = util::utf16ToUtf8(maybeProduct.value());
}
// Parse the resource regardless of product.
@@ -306,12 +277,7 @@ bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
continue;
}
- // We successfully parsed the resource. Check if we should include it or strip it.
- if (shouldStripResource(parsedResource.name, product)) {
- // Record that we stripped out this resource name.
- // We will check that at least one variant of this resource was included.
- strippedResources.insert(parsedResource.name);
- } else if (!addResourcesToTable(mTable, mDiag, &parsedResource)) {
+ if (!addResourcesToTable(mTable, mDiag, &parsedResource)) {
error = true;
}
}
@@ -524,7 +490,7 @@ std::unique_ptr<Item> ResourceParser::parseXml(xml::XmlPullParser* parser, const
// name.package can be empty here, as it will assume the package name of the table.
std::unique_ptr<Id> id = util::make_unique<Id>();
id->setSource(mSource.withLine(beginXmlLine));
- mTable->addResource(name, {}, std::move(id), mDiag);
+ mTable->addResource(name, {}, {}, std::move(id), mDiag);
};
// Process the raw value.
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 51cbbe19384e..ee5b33788312 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -34,13 +34,6 @@ struct ParsedResource;
struct ResourceParserOptions {
/**
- * Optional product names by which to filter resources.
- * This is like a preprocessor definition in that we strip out resources
- * that don't match before we compile them.
- */
- std::vector<std::u16string> products;
-
- /**
* Whether the default setting for this parser is to allow translation.
*/
bool translatable = true;
@@ -106,9 +99,6 @@ private:
bool parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask);
bool parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool shouldStripResource(const ResourceNameRef& name,
- const Maybe<std::u16string>& product) const;
-
IDiagnostics* mDiag;
ResourceTable* mTable;
Source mSource;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index cf0fcd11b903..3450de9078bb 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -48,24 +48,13 @@ struct ResourceParserTest : public ::testing::Test {
}
::testing::AssertionResult testParse(const StringPiece& str) {
- return testParse(str, ConfigDescription{}, {});
+ return testParse(str, ConfigDescription{});
}
::testing::AssertionResult testParse(const StringPiece& str, const ConfigDescription& config) {
- return testParse(str, config, {});
- }
-
- ::testing::AssertionResult testParse(const StringPiece& str,
- std::initializer_list<std::u16string> products) {
- return testParse(str, {}, std::move(products));
- }
-
- ::testing::AssertionResult testParse(const StringPiece& str, const ConfigDescription& config,
- std::initializer_list<std::u16string> products) {
std::stringstream input(kXmlPreamble);
input << "<resources>\n" << str << "\n</resources>" << std::endl;
ResourceParserOptions parserOptions;
- parserOptions.products = products;
ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, config,
parserOptions);
xml::XmlPullParser xmlParser(input);
@@ -546,7 +535,7 @@ TEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
ASSERT_NE(nullptr, id);
}
-TEST_F(ResourceParserTest, FilterProductsThatDontMatch) {
+TEST_F(ResourceParserTest, KeepAllProducts) {
std::string input = R"EOF(
<string name="foo" product="phone">hi</string>
<string name="foo" product="no-sdcard">ho</string>
@@ -555,33 +544,26 @@ TEST_F(ResourceParserTest, FilterProductsThatDontMatch) {
<string name="bit" product="phablet">hoot</string>
<string name="bot" product="default">yes</string>
)EOF";
- ASSERT_TRUE(testParse(input, { std::u16string(u"no-sdcard"), std::u16string(u"phablet") }));
-
- String* fooStr = test::getValue<String>(&mTable, u"@string/foo");
- ASSERT_NE(nullptr, fooStr);
- EXPECT_EQ(StringPiece16(u"ho"), *fooStr->value);
-
- EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bar"));
- EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/baz"));
- EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bit"));
- EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bot"));
-}
-
-TEST_F(ResourceParserTest, FilterProductsThatBothMatchInOrder) {
- std::string input = R"EOF(
- <string name="foo" product="phone">phone</string>
- <string name="foo" product="default">default</string>
- )EOF";
- ASSERT_TRUE(testParse(input, { std::u16string(u"phone") }));
-
- String* foo = test::getValue<String>(&mTable, u"@string/foo");
- ASSERT_NE(nullptr, foo);
- EXPECT_EQ(std::u16string(u"phone"), *foo->value);
-}
+ ASSERT_TRUE(testParse(input));
-TEST_F(ResourceParserTest, FailWhenProductFilterStripsOutAllVersionsOfResource) {
- std::string input = "<string name=\"foo\" product=\"tablet\">hello</string>\n";
- ASSERT_FALSE(testParse(input, { std::u16string(u"phone") }));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/foo",
+ ConfigDescription::defaultConfig(),
+ "phone"));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/foo",
+ ConfigDescription::defaultConfig(),
+ "no-sdcard"));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/bar",
+ ConfigDescription::defaultConfig(),
+ ""));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/baz",
+ ConfigDescription::defaultConfig(),
+ ""));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/bit",
+ ConfigDescription::defaultConfig(),
+ "phablet"));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<String>(&mTable, u"@string/bot",
+ ConfigDescription::defaultConfig(),
+ "default"));
}
TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 8a3d047f6e8d..8d734f3fc36d 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -19,8 +19,6 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
-
-#include "util/Comparators.h"
#include "util/Util.h"
#include <algorithm>
@@ -124,6 +122,73 @@ ResourceEntry* ResourceTableType::findOrCreateEntry(const StringPiece16& name) {
return entries.emplace(iter, new ResourceEntry(name))->get();
}
+ResourceConfigValue* ResourceEntry::findValue(const ConfigDescription& config) {
+ return findValue(config, StringPiece());
+}
+
+struct ConfigKey {
+ const ConfigDescription* config;
+ const StringPiece& product;
+};
+
+bool ltConfigKeyRef(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
+ int cmp = lhs->config.compare(*rhs.config);
+ if (cmp == 0) {
+ cmp = StringPiece(lhs->product).compare(rhs.product);
+ }
+ return cmp < 0;
+}
+
+ResourceConfigValue* ResourceEntry::findValue(const ConfigDescription& config,
+ const StringPiece& product) {
+ auto iter = std::lower_bound(values.begin(), values.end(),
+ ConfigKey{ &config, product }, ltConfigKeyRef);
+ if (iter != values.end()) {
+ ResourceConfigValue* value = iter->get();
+ if (value->config == config && StringPiece(value->product) == product) {
+ return value;
+ }
+ }
+ return nullptr;
+}
+
+ResourceConfigValue* ResourceEntry::findOrCreateValue(const ConfigDescription& config,
+ const StringPiece& product) {
+ auto iter = std::lower_bound(values.begin(), values.end(),
+ ConfigKey{ &config, product }, ltConfigKeyRef);
+ if (iter != values.end()) {
+ ResourceConfigValue* value = iter->get();
+ if (value->config == config && StringPiece(value->product) == product) {
+ return value;
+ }
+ }
+ ResourceConfigValue* newValue = values.insert(
+ iter, util::make_unique<ResourceConfigValue>(config, product))->get();
+ return newValue;
+}
+
+std::vector<ResourceConfigValue*> ResourceEntry::findAllValues(const ConfigDescription& config) {
+ std::vector<ResourceConfigValue*> results;
+
+ auto iter = values.begin();
+ for (; iter != values.end(); ++iter) {
+ ResourceConfigValue* value = iter->get();
+ if (value->config == config) {
+ results.push_back(value);
+ ++iter;
+ break;
+ }
+ }
+
+ for (; iter != values.end(); ++iter) {
+ ResourceConfigValue* value = iter->get();
+ if (value->config == config) {
+ results.push_back(value);
+ }
+ }
+ return results;
+}
+
/**
* The default handler for collisions. A return value of -1 means keep the
* existing value, 0 means fail, and +1 means take the incoming value.
@@ -188,56 +253,80 @@ int ResourceTable::resolveValueCollision(Value* existing, Value* incoming) {
static constexpr const char16_t* kValidNameChars = u"._-";
static constexpr const char16_t* kValidNameMangledChars = u"._-$";
-bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config,
- std::unique_ptr<Value> value, IDiagnostics* diag) {
- return addResourceImpl(name, {}, config, std::move(value), kValidNameChars,
+bool ResourceTable::addResource(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const StringPiece& product,
+ std::unique_ptr<Value> value,
+ IDiagnostics* diag) {
+ return addResourceImpl(name, {}, config, product, std::move(value), kValidNameChars,
resolveValueCollision, diag);
}
-bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId,
- const ConfigDescription& config, std::unique_ptr<Value> value,
+bool ResourceTable::addResource(const ResourceNameRef& name,
+ const ResourceId resId,
+ const ConfigDescription& config,
+ const StringPiece& product,
+ std::unique_ptr<Value> value,
IDiagnostics* diag) {
- return addResourceImpl(name, resId, config, std::move(value), kValidNameChars,
+ return addResourceImpl(name, resId, config, product, std::move(value), kValidNameChars,
resolveValueCollision, diag);
}
-bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
- const Source& source, const StringPiece16& path,
+bool ResourceTable::addFileReference(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const Source& source,
+ const StringPiece16& path,
IDiagnostics* diag) {
- return addFileReference(name, config, source, path, resolveValueCollision, diag);
+ return addFileReferenceImpl(name, config, source, path, nullptr, kValidNameChars, diag);
}
-bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
- const Source& source, const StringPiece16& path,
- std::function<int(Value*,Value*)> conflictResolver,
- IDiagnostics* diag) {
+bool ResourceTable::addFileReferenceAllowMangled(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const Source& source,
+ const StringPiece16& path,
+ io::IFile* file,
+ IDiagnostics* diag) {
+ return addFileReferenceImpl(name, config, source, path, file, kValidNameMangledChars, diag);
+}
+
+bool ResourceTable::addFileReferenceImpl(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const Source& source,
+ const StringPiece16& path,
+ io::IFile* file,
+ const char16_t* validChars,
+ IDiagnostics* diag) {
std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
stringPool.makeRef(path));
fileRef->setSource(source);
- return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars,
- conflictResolver, diag);
+ fileRef->file = file;
+ return addResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
+ kValidNameChars, resolveValueCollision, diag);
}
bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
const ConfigDescription& config,
+ const StringPiece& product,
std::unique_ptr<Value> value,
IDiagnostics* diag) {
- return addResourceImpl(name, ResourceId{}, config, std::move(value), kValidNameMangledChars,
- resolveValueCollision, diag);
+ return addResourceImpl(name, ResourceId{}, config, product, std::move(value),
+ kValidNameMangledChars, resolveValueCollision, diag);
}
bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
const ResourceId id,
const ConfigDescription& config,
+ const StringPiece& product,
std::unique_ptr<Value> value,
IDiagnostics* diag) {
- return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars,
+ return addResourceImpl(name, id, config, product, std::move(value), kValidNameMangledChars,
resolveValueCollision, diag);
}
bool ResourceTable::addResourceImpl(const ResourceNameRef& name,
const ResourceId resId,
const ConfigDescription& config,
+ const StringPiece& product,
std::unique_ptr<Value> value,
const char16_t* validChars,
std::function<int(Value*,Value*)> conflictResolver,
@@ -298,21 +387,21 @@ bool ResourceTable::addResourceImpl(const ResourceNameRef& name,
return false;
}
- const auto endIter = entry->values.end();
- auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmp::lessThanConfig);
- if (iter == endIter || iter->config != config) {
- // This resource did not exist before, add it.
- entry->values.insert(iter, ResourceConfigValue{ config, std::move(value) });
+ ResourceConfigValue* configValue = entry->findOrCreateValue(config, product);
+ if (!configValue->value) {
+ // Resource does not exist, add it now.
+ configValue->value = std::move(value);
+
} else {
- int collisionResult = conflictResolver(iter->value.get(), value.get());
+ int collisionResult = conflictResolver(configValue->value.get(), value.get());
if (collisionResult > 0) {
// Take the incoming value.
- iter->value = std::move(value);
+ configValue->value = std::move(value);
} else if (collisionResult == 0) {
diag->error(DiagMessage(value->getSource())
<< "duplicate value for resource '" << name << "' "
<< "with config '" << config << "'");
- diag->error(DiagMessage(iter->value->getSource())
+ diag->error(DiagMessage(configValue->value->getSource())
<< "resource previously defined here");
return false;
}
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 6b7b07ea3a93..7f5c2b8c0f37 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -23,10 +23,14 @@
#include "ResourceValues.h"
#include "Source.h"
#include "StringPool.h"
+#include "io/File.h"
+#include <android-base/macros.h>
+#include <map>
#include <memory>
#include <string>
#include <tuple>
+#include <unordered_map>
#include <vector>
namespace aapt {
@@ -46,19 +50,36 @@ struct Symbol {
std::u16string comment;
};
-/**
- * Represents a value defined for a given configuration.
- */
-struct ResourceConfigValue {
- ConfigDescription config;
+class ResourceConfigValue {
+public:
+ /**
+ * The configuration for which this value is defined.
+ */
+ const ConfigDescription config;
+
+ /**
+ * The product for which this value is defined.
+ */
+ const std::string product;
+
+ /**
+ * The actual Value.
+ */
std::unique_ptr<Value> value;
+
+ ResourceConfigValue(const ConfigDescription& config, const StringPiece& product) :
+ config(config), product(product.toString()) { }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
};
/**
* Represents a resource entry, which may have
* varying values for each defined configuration.
*/
-struct ResourceEntry {
+class ResourceEntry {
+public:
/**
* The name of the resource. Immutable, as
* this determines the order of this resource
@@ -72,24 +93,33 @@ struct ResourceEntry {
Maybe<uint16_t> id;
/**
- * Whether this resource is public (and must maintain the same
- * entry ID across builds).
+ * Whether this resource is public (and must maintain the same entry ID across builds).
*/
Symbol symbolStatus;
/**
* The resource's values for each configuration.
*/
- std::vector<ResourceConfigValue> values;
+ std::vector<std::unique_ptr<ResourceConfigValue>> values;
ResourceEntry(const StringPiece16& name) : name(name.toString()) { }
+
+ ResourceConfigValue* findValue(const ConfigDescription& config);
+ ResourceConfigValue* findValue(const ConfigDescription& config, const StringPiece& product);
+ ResourceConfigValue* findOrCreateValue(const ConfigDescription& config,
+ const StringPiece& product);
+ std::vector<ResourceConfigValue*> findAllValues(const ConfigDescription& config);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
};
/**
* Represents a resource type, which holds entries defined
* for this type.
*/
-struct ResourceTableType {
+class ResourceTableType {
+public:
/**
* The logical type of resource (string, drawable, layout, etc.).
*/
@@ -114,8 +144,10 @@ struct ResourceTableType {
explicit ResourceTableType(const ResourceType type) : type(type) { }
ResourceEntry* findEntry(const StringPiece16& name);
-
ResourceEntry* findOrCreateEntry(const StringPiece16& name);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
};
enum class PackageType {
@@ -125,16 +157,20 @@ enum class PackageType {
Dynamic
};
-struct ResourceTablePackage {
+class ResourceTablePackage {
+public:
PackageType type = PackageType::App;
Maybe<uint8_t> id;
std::u16string name;
std::vector<std::unique_ptr<ResourceTableType>> types;
+ ResourceTablePackage() = default;
ResourceTableType* findType(ResourceType type);
-
ResourceTableType* findOrCreateType(const ResourceType type);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
};
/**
@@ -144,8 +180,6 @@ struct ResourceTablePackage {
class ResourceTable {
public:
ResourceTable() = default;
- ResourceTable(const ResourceTable&) = delete;
- ResourceTable& operator=(const ResourceTable&) = delete;
/**
* When a collision of resources occurs, this method decides which value to keep.
@@ -155,38 +189,59 @@ public:
*/
static int resolveValueCollision(Value* existing, Value* incoming);
- bool addResource(const ResourceNameRef& name, const ConfigDescription& config,
- std::unique_ptr<Value> value, IDiagnostics* diag);
+ bool addResource(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const StringPiece& product,
+ std::unique_ptr<Value> value,
+ IDiagnostics* diag);
- bool addResource(const ResourceNameRef& name, const ResourceId resId,
- const ConfigDescription& config, std::unique_ptr<Value> value,
+ bool addResource(const ResourceNameRef& name,
+ const ResourceId resId,
+ const ConfigDescription& config,
+ const StringPiece& product,
+ std::unique_ptr<Value> value,
IDiagnostics* diag);
- bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
- const Source& source, const StringPiece16& path,
- IDiagnostics* diag);
+ bool addFileReference(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const Source& source,
+ const StringPiece16& path,
+ IDiagnostics* diag);
- bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
- const Source& source, const StringPiece16& path,
- std::function<int(Value*,Value*)> conflictResolver, IDiagnostics* diag);
+ bool addFileReferenceAllowMangled(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const Source& source,
+ const StringPiece16& path,
+ io::IFile* file,
+ IDiagnostics* diag);
/**
* Same as addResource, but doesn't verify the validity of the name. This is used
* when loading resources from an existing binary resource table that may have mangled
* names.
*/
- bool addResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config,
- std::unique_ptr<Value> value, IDiagnostics* diag);
+ bool addResourceAllowMangled(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const StringPiece& product,
+ std::unique_ptr<Value> value,
+ IDiagnostics* diag);
- bool addResourceAllowMangled(const ResourceNameRef& name, const ResourceId id,
- const ConfigDescription& config, std::unique_ptr<Value> value,
+ bool addResourceAllowMangled(const ResourceNameRef& name,
+ const ResourceId id,
+ const ConfigDescription& config,
+ const StringPiece& product,
+ std::unique_ptr<Value> value,
IDiagnostics* diag);
- bool setSymbolState(const ResourceNameRef& name, const ResourceId resId,
- const Symbol& symbol, IDiagnostics* diag);
+ bool setSymbolState(const ResourceNameRef& name,
+ const ResourceId resId,
+ const Symbol& symbol,
+ IDiagnostics* diag);
- bool setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId,
- const Symbol& symbol, IDiagnostics* diag);
+ bool setSymbolStateAllowMangled(const ResourceNameRef& name,
+ const ResourceId resId,
+ const Symbol& symbol,
+ IDiagnostics* diag);
struct SearchResult {
ResourceTablePackage* package;
@@ -226,16 +281,30 @@ public:
private:
ResourceTablePackage* findOrCreatePackage(const StringPiece16& name);
+ bool addFileReferenceImpl(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const Source& source,
+ const StringPiece16& path,
+ io::IFile* file,
+ const char16_t* validChars,
+ IDiagnostics* diag);
+
bool addResourceImpl(const ResourceNameRef& name,
ResourceId resId,
const ConfigDescription& config,
+ const StringPiece& product,
std::unique_ptr<Value> value,
const char16_t* validChars,
std::function<int(Value*,Value*)> conflictResolver,
IDiagnostics* diag);
- bool setSymbolStateImpl(const ResourceNameRef& name, ResourceId resId,
- const Symbol& symbol, const char16_t* validChars, IDiagnostics* diag);
+ bool setSymbolStateImpl(const ResourceNameRef& name,
+ ResourceId resId,
+ const Symbol& symbol,
+ const char16_t* validChars,
+ IDiagnostics* diag);
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceTable);
};
} // namespace aapt
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 42508fe154b8..180bd11275df 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -43,13 +43,13 @@ TEST_F(ResourceTableTest, FailToAddResourceWithBadName) {
EXPECT_FALSE(table.addResource(
ResourceNameRef(u"android", ResourceType::kId, u"hey,there"),
- ConfigDescription{},
+ ConfigDescription{}, "",
test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
&mDiagnostics));
EXPECT_FALSE(table.addResource(
ResourceNameRef(u"android", ResourceType::kId, u"hey:there"),
- ConfigDescription{},
+ ConfigDescription{}, "",
test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
&mDiagnostics));
}
@@ -59,6 +59,7 @@ TEST_F(ResourceTableTest, AddOneResource) {
EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"),
ConfigDescription{},
+ "",
test::ValueBuilder<Id>()
.setSource("test/path/file.xml", 23u).build(),
&mDiagnostics));
@@ -76,24 +77,28 @@ TEST_F(ResourceTableTest, AddMultipleResources) {
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:attr/layout_width"),
config,
+ "",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 10u).build(),
&mDiagnostics));
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:attr/id"),
config,
+ "",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 12u).build(),
&mDiagnostics));
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:string/ok"),
config,
+ "",
test::ValueBuilder<Id>().setSource("test/path/file.xml", 14u).build(),
&mDiagnostics));
EXPECT_TRUE(table.addResource(
test::parseNameOrDie(u"@android:string/ok"),
languageConfig,
+ "",
test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
.setSource("test/path/file.xml", 20u)
.build(),
@@ -110,18 +115,49 @@ TEST_F(ResourceTableTest, OverrideWeakResourceValue) {
ResourceTable table;
ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
- util::make_unique<Attribute>(true), &mDiagnostics));
+ "", util::make_unique<Attribute>(true), &mDiagnostics));
Attribute* attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_TRUE(attr->isWeak());
ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
- util::make_unique<Attribute>(false), &mDiagnostics));
+ "", util::make_unique<Attribute>(false), &mDiagnostics));
attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
ASSERT_NE(nullptr, attr);
EXPECT_FALSE(attr->isWeak());
}
+TEST_F(ResourceTableTest, ProductVaryingValues) {
+ ResourceTable table;
+
+ EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/foo"),
+ test::parseConfigOrDie("land"),
+ "tablet",
+ util::make_unique<Id>(),
+ &mDiagnostics));
+ EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/foo"),
+ test::parseConfigOrDie("land"),
+ "phone",
+ util::make_unique<Id>(),
+ &mDiagnostics));
+
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/foo",
+ test::parseConfigOrDie("land"),
+ "tablet"));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/foo",
+ test::parseConfigOrDie("land"),
+ "phone"));
+
+ Maybe<ResourceTable::SearchResult> sr = table.findResource(
+ test::parseNameOrDie(u"@android:string/foo"));
+ AAPT_ASSERT_TRUE(sr);
+ std::vector<ResourceConfigValue*> values = sr.value().entry->findAllValues(
+ test::parseConfigOrDie("land"));
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ(std::string("phone"), values[0]->product);
+ EXPECT_EQ(std::string("tablet"), values[1]->product);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 07f62afe05b9..74c48b0f8426 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -51,6 +51,10 @@ bool extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
}
bool parseResourceName(const StringPiece16& str, ResourceNameRef* outRef, bool* outPrivate) {
+ if (str.empty()) {
+ return false;
+ }
+
size_t offset = 0;
bool priv = false;
if (str.data()[0] == u'*') {
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 64ca97185153..a0fbcc6e700b 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -45,7 +45,8 @@ bool extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
* `outResource` set to the parsed resource name and `outPrivate` set to true if a '*' prefix
* was present.
*/
-bool parseResourceName(const StringPiece16& str, ResourceNameRef* outResource, bool* outPrivate);
+bool parseResourceName(const StringPiece16& str, ResourceNameRef* outResource,
+ bool* outPrivate = nullptr);
/*
* Returns true if the string was parsed as a reference (@[+][package:]type/name), with
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index c9f93e1dd7c2..7425f97ef8de 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -58,6 +58,8 @@ TEST(ResourceUtilsTest, ParseResourceName) {
EXPECT_TRUE(ResourceUtils::parseResourceName(u"*android:color/foo", &actual, &actualPriv));
EXPECT_EQ(ResourceNameRef(u"android", ResourceType::kColor, u"foo"), actual);
EXPECT_TRUE(actualPriv);
+
+ EXPECT_FALSE(ResourceUtils::parseResourceName(StringPiece16(), &actual, &actualPriv));
}
TEST(ResourceUtilsTest, ParseReferenceWithNoPackage) {
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index b93e6d889ad0..dd7ff013e524 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -18,8 +18,8 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "io/File.h"
#include "util/Util.h"
-#include "flatten/ResourceTypeExtensions.h"
#include <androidfw/ResourceTypes.h>
#include <limits>
@@ -47,7 +47,7 @@ RawString* RawString::clone(StringPool* newPool) const {
}
bool RawString::flatten(android::Res_value* outValue) const {
- outValue->dataType = ExtendedTypes::TYPE_RAW_STRING;
+ outValue->dataType = android::Res_value::TYPE_STRING;
outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
return true;
}
@@ -191,6 +191,7 @@ bool FileReference::flatten(android::Res_value* outValue) const {
FileReference* FileReference::clone(StringPool* newPool) const {
FileReference* fr = new FileReference(newPool->makeRef(*path));
+ fr->file = file;
fr->mComment = mComment;
fr->mSource = mSource;
return fr;
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 8e317dbcd1b1..43354acf1d0b 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -20,6 +20,7 @@
#include "Diagnostics.h"
#include "Resource.h"
#include "StringPool.h"
+#include "io/File.h"
#include "util/Maybe.h"
#include <array>
@@ -154,8 +155,8 @@ struct Reference : public BaseItem<Reference> {
bool privateReference = false;
Reference();
- Reference(const ResourceNameRef& n, Type type = Type::kResource);
- Reference(const ResourceId& i, Type type = Type::kResource);
+ explicit Reference(const ResourceNameRef& n, Type type = Type::kResource);
+ explicit Reference(const ResourceId& i, Type type = Type::kResource);
bool flatten(android::Res_value* outValue) const override;
Reference* clone(StringPool* newPool) const override;
@@ -226,6 +227,11 @@ private:
struct FileReference : public BaseItem<FileReference> {
StringPool::Ref path;
+ /**
+ * A handle to the file object from which this file can be read.
+ */
+ io::IFile* file = nullptr;
+
FileReference() = default;
FileReference(const StringPool::Ref& path);
diff --git a/tools/aapt2/SdkConstants_test.cpp b/tools/aapt2/SdkConstants_test.cpp
new file mode 100644
index 000000000000..e81f412dda15
--- /dev/null
+++ b/tools/aapt2/SdkConstants_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "SdkConstants.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(SdkConstantsTest, FirstAttributeIsSdk1) {
+ EXPECT_EQ(1u, findAttributeSdkLevel(ResourceId(0x01010000)));
+}
+
+TEST(SdkConstantsTest, AllAttributesAfterLollipopAreLollipopMR1) {
+ EXPECT_EQ(SDK_LOLLIPOP, findAttributeSdkLevel(ResourceId(0x010103f7)));
+ EXPECT_EQ(SDK_LOLLIPOP, findAttributeSdkLevel(ResourceId(0x010104ce)));
+
+ EXPECT_EQ(SDK_LOLLIPOP_MR1, findAttributeSdkLevel(ResourceId(0x010104cf)));
+ EXPECT_EQ(SDK_LOLLIPOP_MR1, findAttributeSdkLevel(ResourceId(0x010104d8)));
+
+ EXPECT_EQ(SDK_LOLLIPOP_MR1, findAttributeSdkLevel(ResourceId(0x010104d9)));
+ EXPECT_EQ(SDK_LOLLIPOP_MR1, findAttributeSdkLevel(ResourceId(0x0101ffff)));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h
index 94042e3c2618..ea2aa55764c1 100644
--- a/tools/aapt2/ValueVisitor.h
+++ b/tools/aapt2/ValueVisitor.h
@@ -18,6 +18,7 @@
#define AAPT_VALUE_VISITOR_H
#include "ResourceValues.h"
+#include "ResourceTable.h"
namespace aapt {
@@ -140,6 +141,23 @@ T* valueCast(Value* value) {
return visitor.value;
}
+
+inline void visitAllValuesInPackage(ResourceTablePackage* pkg, RawValueVisitor* visitor) {
+ for (auto& type : pkg->types) {
+ for (auto& entry : type->entries) {
+ for (auto& configValue : entry->values) {
+ configValue->value->accept(visitor);
+ }
+ }
+ }
+}
+
+inline void visitAllValuesInTable(ResourceTable* table, RawValueVisitor* visitor) {
+ for (auto& pkg : table->packages) {
+ visitAllValuesInPackage(pkg.get(), visitor);
+ }
+}
+
} // namespace aapt
#endif // AAPT_VALUE_VISITOR_H
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 689ace6e6aa1..5f9719e61a9a 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -24,15 +24,17 @@
#include "compile/PseudolocaleGenerator.h"
#include "compile/XmlIdCollector.h"
#include "flatten/Archive.h"
-#include "flatten/FileExportWriter.h"
-#include "flatten/TableFlattener.h"
#include "flatten/XmlFlattener.h"
+#include "proto/ProtoSerialize.h"
#include "util/Files.h"
#include "util/Maybe.h"
#include "util/Util.h"
#include "xml/XmlDom.h"
#include "xml/XmlPullParser.h"
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/io/coded_stream.h>
+
#include <dirent.h>
#include <fstream>
#include <string>
@@ -105,7 +107,6 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path,
struct CompileOptions {
std::string outputPath;
Maybe<std::string> resDir;
- std::vector<std::u16string> products;
bool pseudolocalize = false;
bool legacyMode = false;
bool verbose = false;
@@ -196,7 +197,6 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options,
xml::XmlPullParser xmlParser(fin);
ResourceParserOptions parserOptions;
- parserOptions.products = options.products;
parserOptions.errorOnPositionalArguments = !options.legacyMode;
// If the filename includes donottranslate, then the default translatable is false.
@@ -232,34 +232,95 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options,
}
}
- // Assign IDs to prepare the table for flattening.
- IdAssigner idAssigner;
- if (!idAssigner.consume(context, &table)) {
+ // Create the file/zip entry.
+ if (!writer->startEntry(outputPath, 0)) {
+ context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open");
return false;
}
- // Flatten the table.
- BigBuffer buffer(1024);
- TableFlattenerOptions tableFlattenerOptions;
- tableFlattenerOptions.useExtendedChunks = true;
- TableFlattener flattener(&buffer, tableFlattenerOptions);
- if (!flattener.consume(context, &table)) {
+ std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(&table);
+
+ // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
+ {
+ google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+
+ if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
+ context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+ return false;
+ }
+ }
+
+ if (!writer->finishEntry()) {
+ context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to finish entry");
return false;
}
+ return true;
+}
+static bool writeHeaderAndBufferToWriter(const StringPiece& outputPath, const ResourceFile& file,
+ const BigBuffer& buffer, IArchiveWriter* writer,
+ IDiagnostics* diag) {
+ // Start the entry so we can write the header.
if (!writer->startEntry(outputPath, 0)) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open");
+ diag->error(DiagMessage(outputPath) << "failed to open file");
return false;
}
- if (writer->writeEntry(buffer)) {
- if (writer->finishEntry()) {
- return true;
+ // Create the header.
+ std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file);
+
+ {
+ // The stream must be destroyed before we finish the entry, or else
+ // some data won't be flushed.
+ // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+ // interface.
+ google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+ CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get());
+ for (const BigBuffer::Block& block : buffer) {
+ if (!outputStream.Write(block.buffer.get(), block.size)) {
+ diag->error(DiagMessage(outputPath) << "failed to write data");
+ return false;
+ }
}
}
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
- return false;
+ if (!writer->finishEntry()) {
+ diag->error(DiagMessage(outputPath) << "failed to finish writing data");
+ return false;
+ }
+ return true;
+}
+
+static bool writeHeaderAndMmapToWriter(const StringPiece& outputPath, const ResourceFile& file,
+ const android::FileMap& map, IArchiveWriter* writer,
+ IDiagnostics* diag) {
+ // Start the entry so we can write the header.
+ if (!writer->startEntry(outputPath, 0)) {
+ diag->error(DiagMessage(outputPath) << "failed to open file");
+ return false;
+ }
+
+ // Create the header.
+ std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file);
+
+ {
+ // The stream must be destroyed before we finish the entry, or else
+ // some data won't be flushed.
+ // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+ // interface.
+ google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+ CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get());
+ if (!outputStream.Write(map.getDataPtr(), map.getDataLength())) {
+ diag->error(DiagMessage(outputPath) << "failed to write data");
+ return false;
+ }
+ }
+
+ if (!writer->finishEntry()) {
+ diag->error(DiagMessage(outputPath) << "failed to finish writing data");
+ return false;
+ }
+ return true;
}
static bool compileXml(IAaptContext* context, const CompileOptions& options,
@@ -267,7 +328,6 @@ static bool compileXml(IAaptContext* context, const CompileOptions& options,
const std::string& outputPath) {
std::unique_ptr<xml::XmlResource> xmlRes;
-
{
std::ifstream fin(pathData.source.path, std::ifstream::binary);
if (!fin) {
@@ -295,30 +355,18 @@ static bool compileXml(IAaptContext* context, const CompileOptions& options,
xmlRes->file.source = pathData.source;
BigBuffer buffer(1024);
- ChunkWriter fileExportWriter = wrapBufferWithFileExportHeader(&buffer, &xmlRes->file);
-
XmlFlattenerOptions xmlFlattenerOptions;
xmlFlattenerOptions.keepRawValues = true;
- XmlFlattener flattener(fileExportWriter.getBuffer(), xmlFlattenerOptions);
+ XmlFlattener flattener(&buffer, xmlFlattenerOptions);
if (!flattener.consume(context, xmlRes.get())) {
return false;
}
- fileExportWriter.finish();
-
- if (!writer->startEntry(outputPath, 0)) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open");
+ if (!writeHeaderAndBufferToWriter(outputPath, xmlRes->file, buffer, writer,
+ context->getDiagnostics())) {
return false;
}
-
- if (writer->writeEntry(buffer)) {
- if (writer->finishEntry()) {
- return true;
- }
- }
-
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
- return false;
+ return true;
}
static bool compilePng(IAaptContext* context, const CompileOptions& options,
@@ -330,8 +378,6 @@ static bool compilePng(IAaptContext* context, const CompileOptions& options,
resFile.config = pathData.config;
resFile.source = pathData.source;
- ChunkWriter fileExportWriter = wrapBufferWithFileExportHeader(&buffer, &resFile);
-
{
std::ifstream fin(pathData.source.path, std::ifstream::binary);
if (!fin) {
@@ -340,26 +386,16 @@ static bool compilePng(IAaptContext* context, const CompileOptions& options,
}
Png png(context->getDiagnostics());
- if (!png.process(pathData.source, &fin, fileExportWriter.getBuffer(), {})) {
+ if (!png.process(pathData.source, &fin, &buffer, {})) {
return false;
}
}
- fileExportWriter.finish();
-
- if (!writer->startEntry(outputPath, 0)) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open");
+ if (!writeHeaderAndBufferToWriter(outputPath, resFile, buffer, writer,
+ context->getDiagnostics())) {
return false;
}
-
- if (writer->writeEntry(buffer)) {
- if (writer->finishEntry()) {
- return true;
- }
- }
-
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
- return false;
+ return true;
}
static bool compileFile(IAaptContext* context, const CompileOptions& options,
@@ -371,8 +407,6 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options,
resFile.config = pathData.config;
resFile.source = pathData.source;
- ChunkWriter fileExportWriter = wrapBufferWithFileExportHeader(&buffer, &resFile);
-
std::string errorStr;
Maybe<android::FileMap> f = file::mmapPath(pathData.source.path, &errorStr);
if (!f) {
@@ -380,43 +414,27 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options,
return false;
}
- if (!writer->startEntry(outputPath, 0)) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open");
- return false;
- }
-
- // Manually set the size and don't call finish(). This is because we are not copying from
- // the buffer the entire file.
- fileExportWriter.getChunkHeader()->size =
- util::hostToDevice32(buffer.size() + f.value().getDataLength());
-
- if (!writer->writeEntry(buffer)) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
- return false;
- }
-
- // Only write if we have something to write. This is because mmap fails with length of 0,
- // but we still want to compile the file to get the resource ID.
- if (f.value().getDataPtr() && f.value().getDataLength() > 0) {
- if (!writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
- return false;
- }
- }
-
- if (!writer->finishEntry()) {
- context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+ if (!writeHeaderAndMmapToWriter(outputPath, resFile, f.value(), writer,
+ context->getDiagnostics())) {
return false;
}
-
return true;
}
class CompileContext : public IAaptContext {
private:
StdErrDiagnostics mDiagnostics;
+ bool mVerbose = false;
public:
+ void setVerbose(bool val) {
+ mVerbose = val;
+ }
+
+ bool verbose() override {
+ return mVerbose;
+ }
+
IDiagnostics* getDiagnostics() override {
return &mDiagnostics;
}
@@ -444,30 +462,24 @@ public:
* Entry point for compilation phase. Parses arguments and dispatches to the correct steps.
*/
int compile(const std::vector<StringPiece>& args) {
+ CompileContext context;
CompileOptions options;
- Maybe<std::string> productList;
+ bool verbose = false;
Flags flags = Flags()
.requiredFlag("-o", "Output path", &options.outputPath)
- .optionalFlag("--product", "Comma separated list of product types to compile",
- &productList)
.optionalFlag("--dir", "Directory to scan for resources", &options.resDir)
.optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
"(en-XA and ar-XB)", &options.pseudolocalize)
.optionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
&options.legacyMode)
- .optionalSwitch("-v", "Enables verbose logging", &options.verbose);
+ .optionalSwitch("-v", "Enables verbose logging", &verbose);
if (!flags.parse("aapt2 compile", args, &std::cerr)) {
return 1;
}
- if (productList) {
- for (StringPiece part : util::tokenize<char>(productList.value(), ',')) {
- options.products.push_back(util::utf8ToUtf16(part));
- }
- }
+ context.setVerbose(verbose);
- CompileContext context;
std::unique_ptr<IArchiveWriter> archiveWriter;
std::vector<ResourcePathData> inputData;
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index 80c6bbc1abca..aa4a5803b8df 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -64,14 +64,12 @@ bool IdAssigner::consume(IAaptContext* context, ResourceTable* table) {
// Mark entry ID as taken.
if (!usedEntryIds.insert(entry->id.value()).second) {
// This ID existed before!
- ResourceNameRef nameRef =
- { package->name, type->type, entry->name };
- ResourceId takenId(package->id.value(), type->id.value(),
- entry->id.value());
+ ResourceNameRef nameRef(package->name, type->type, entry->name);
context->getDiagnostics()->error(DiagMessage()
<< "resource '" << nameRef << "' "
- << "has duplicate ID '"
- << takenId << "'");
+ << "has duplicate entry ID "
+ << std::hex << (int) entry->id.value()
+ << std::dec);
return false;
}
}
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 2963d135cbca..be26b528b184 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -19,7 +19,6 @@
#include "ValueVisitor.h"
#include "compile/PseudolocaleGenerator.h"
#include "compile/Pseudolocalizer.h"
-#include "util/Comparators.h"
namespace aapt {
@@ -208,10 +207,12 @@ ConfigDescription modifyConfigForPseudoLocale(const ConfigDescription& base,
return modified;
}
-void pseudolocalizeIfNeeded(std::vector<ResourceConfigValue>* configValues,
- Pseudolocalizer::Method method, StringPool* pool, Value* value) {
+void pseudolocalizeIfNeeded(const Pseudolocalizer::Method method,
+ ResourceConfigValue* originalValue,
+ StringPool* pool,
+ ResourceEntry* entry) {
Visitor visitor(pool, method);
- value->accept(&visitor);
+ originalValue->value->accept(&visitor);
std::unique_ptr<Value> localizedValue;
if (visitor.mValue) {
@@ -220,16 +221,18 @@ void pseudolocalizeIfNeeded(std::vector<ResourceConfigValue>* configValues,
localizedValue = std::move(visitor.mItem);
}
- if (localizedValue) {
- ConfigDescription pseudolocalizedConfig = modifyConfigForPseudoLocale(ConfigDescription{},
- method);
- auto iter = std::lower_bound(configValues->begin(), configValues->end(),
- pseudolocalizedConfig, cmp::lessThanConfig);
- if (iter == configValues->end() || iter->config != pseudolocalizedConfig) {
- // The pseudolocalized config doesn't exist, add it.
- configValues->insert(iter, ResourceConfigValue{ pseudolocalizedConfig,
- std::move(localizedValue) });
- }
+ if (!localizedValue) {
+ return;
+ }
+
+ ConfigDescription configWithAccent = modifyConfigForPseudoLocale(
+ originalValue->config, method);
+
+ ResourceConfigValue* newConfigValue = entry->findOrCreateValue(
+ configWithAccent, originalValue->product);
+ if (!newConfigValue->value) {
+ // Only use auto-generated pseudo-localization if none is defined.
+ newConfigValue->value = std::move(localizedValue);
}
}
@@ -239,18 +242,13 @@ bool PseudolocaleGenerator::consume(IAaptContext* context, ResourceTable* table)
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- auto iter = std::lower_bound(entry->values.begin(), entry->values.end(),
- ConfigDescription{}, cmp::lessThanConfig);
- if (iter != entry->values.end() && iter->config == ConfigDescription{}) {
- // Only pseudolocalize the default configuration.
-
- // The iterator will be invalidated, so grab a pointer to the value.
- Value* originalValue = iter->value.get();
-
- pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kAccent,
- &table->stringPool, originalValue);
- pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kBidi,
- &table->stringPool, originalValue);
+ std::vector<ResourceConfigValue*> values = entry->findAllValues(
+ ConfigDescription::defaultConfig());
+ for (ResourceConfigValue* value : values) {
+ pseudolocalizeIfNeeded(Pseudolocalizer::Method::kAccent, value,
+ &table->stringPool, entry.get());
+ pseudolocalizeIfNeeded(Pseudolocalizer::Method::kBidi, value,
+ &table->stringPool, entry.get());
}
}
}
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
new file mode 100644
index 000000000000..ad7de0ab2fbd
--- /dev/null
+++ b/tools/aapt2/dump/Dump.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "Debug.h"
+#include "Diagnostics.h"
+#include "Flags.h"
+#include "process/IResourceTableConsumer.h"
+#include "proto/ProtoSerialize.h"
+#include "util/Files.h"
+#include "util/StringPiece.h"
+
+#include <vector>
+
+namespace aapt {
+
+//struct DumpOptions {
+//
+//};
+
+void dumpCompiledFile(const pb::CompiledFile& pbFile, const void* data, size_t len,
+ const Source& source, IAaptContext* context) {
+ std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(pbFile, source,
+ context->getDiagnostics());
+ if (!file) {
+ return;
+ }
+
+ std::cout << "Resource: " << file->name << "\n"
+ << "Config: " << file->config << "\n"
+ << "Source: " << file->source << "\n";
+}
+
+void dumpCompiledTable(const pb::ResourceTable& pbTable, const Source& source,
+ IAaptContext* context) {
+ std::unique_ptr<ResourceTable> table = deserializeTableFromPb(pbTable, source,
+ context->getDiagnostics());
+ if (!table) {
+ return;
+ }
+
+ Debug::printTable(table.get());
+}
+
+void tryDumpFile(IAaptContext* context, const std::string& filePath) {
+ std::string err;
+ Maybe<android::FileMap> file = file::mmapPath(filePath, &err);
+ if (!file) {
+ context->getDiagnostics()->error(DiagMessage(filePath) << err);
+ return;
+ }
+
+ android::FileMap* fileMap = &file.value();
+
+ // Try as a compiled table.
+ pb::ResourceTable pbTable;
+ if (pbTable.ParseFromArray(fileMap->getDataPtr(), fileMap->getDataLength())) {
+ dumpCompiledTable(pbTable, Source(filePath), context);
+ return;
+ }
+
+ // Try as a compiled file.
+ CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength());
+ if (const pb::CompiledFile* pbFile = input.CompiledFile()) {
+ dumpCompiledFile(*pbFile, input.data(), input.size(), Source(filePath), context);
+ return;
+ }
+}
+
+class DumpContext : public IAaptContext {
+public:
+ IDiagnostics* getDiagnostics() override {
+ return &mDiagnostics;
+ }
+
+ NameMangler* getNameMangler() override {
+ abort();
+ return nullptr;
+ }
+
+ StringPiece16 getCompilationPackage() override {
+ return {};
+ }
+
+ uint8_t getPackageId() override {
+ return 0;
+ }
+
+ ISymbolTable* getExternalSymbols() override {
+ abort();
+ return nullptr;
+ }
+
+ bool verbose() override {
+ return mVerbose;
+ }
+
+ void setVerbose(bool val) {
+ mVerbose = val;
+ }
+
+private:
+ StdErrDiagnostics mDiagnostics;
+ bool mVerbose = false;
+};
+
+/**
+ * Entry point for dump command.
+ */
+int dump(const std::vector<StringPiece>& args) {
+ bool verbose = false;
+ Flags flags = Flags()
+ .optionalSwitch("-v", "increase verbosity of output", &verbose);
+ if (!flags.parse("aapt2 dump", args, &std::cerr)) {
+ return 1;
+ }
+
+ DumpContext context;
+ context.setVerbose(verbose);
+
+ for (const std::string& arg : flags.getArgs()) {
+ tryDumpFile(&context, arg);
+ }
+ return 0;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/flatten/Archive.h b/tools/aapt2/flatten/Archive.h
index 6da1d2ac5620..34c10ad40365 100644
--- a/tools/aapt2/flatten/Archive.h
+++ b/tools/aapt2/flatten/Archive.h
@@ -22,6 +22,7 @@
#include "util/Files.h"
#include "util/StringPiece.h"
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <fstream>
#include <memory>
#include <string>
@@ -40,13 +41,18 @@ struct ArchiveEntry {
size_t uncompressedSize;
};
-struct IArchiveWriter {
+struct IArchiveWriter : public google::protobuf::io::CopyingOutputStream {
virtual ~IArchiveWriter() = default;
virtual bool startEntry(const StringPiece& path, uint32_t flags) = 0;
virtual bool writeEntry(const BigBuffer& buffer) = 0;
virtual bool writeEntry(const void* data, size_t len) = 0;
virtual bool finishEntry() = 0;
+
+ // CopyingOutputStream implementations.
+ bool Write(const void* buffer, int size) override {
+ return writeEntry(buffer, size);
+ }
};
std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(IDiagnostics* diag,
diff --git a/tools/aapt2/flatten/FileExportWriter.h b/tools/aapt2/flatten/FileExportWriter.h
deleted file mode 100644
index 7688fa71246e..000000000000
--- a/tools/aapt2/flatten/FileExportWriter.h
+++ /dev/null
@@ -1,67 +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.
- */
-
-#ifndef AAPT_FLATTEN_FILEEXPORTWRITER_H
-#define AAPT_FLATTEN_FILEEXPORTWRITER_H
-
-#include "StringPool.h"
-
-#include "flatten/ResourceTypeExtensions.h"
-#include "flatten/ChunkWriter.h"
-#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
-#include "util/Util.h"
-
-#include <androidfw/ResourceTypes.h>
-#include <utils/misc.h>
-
-namespace aapt {
-
-static ChunkWriter wrapBufferWithFileExportHeader(BigBuffer* buffer, ResourceFile* res) {
- ChunkWriter fileExportWriter(buffer);
- FileExport_header* fileExport = fileExportWriter.startChunk<FileExport_header>(
- RES_FILE_EXPORT_TYPE);
-
- ExportedSymbol* symbolRefs = nullptr;
- if (!res->exportedSymbols.empty()) {
- symbolRefs = fileExportWriter.nextBlock<ExportedSymbol>(
- res->exportedSymbols.size());
- }
- fileExport->exportedSymbolCount = util::hostToDevice32(res->exportedSymbols.size());
-
- StringPool symbolExportPool;
- memcpy(fileExport->magic, "AAPT", NELEM(fileExport->magic));
- fileExport->config = res->config;
- fileExport->config.swapHtoD();
- fileExport->name.index = util::hostToDevice32(symbolExportPool.makeRef(res->name.toString())
- .getIndex());
- fileExport->source.index = util::hostToDevice32(symbolExportPool.makeRef(util::utf8ToUtf16(
- res->source.path)).getIndex());
-
- for (const SourcedResourceName& name : res->exportedSymbols) {
- symbolRefs->name.index = util::hostToDevice32(symbolExportPool.makeRef(name.name.toString())
- .getIndex());
- symbolRefs->line = util::hostToDevice32(name.line);
- symbolRefs++;
- }
-
- StringPool::flattenUtf16(fileExportWriter.getBuffer(), symbolExportPool);
- return fileExportWriter;
-}
-
-} // namespace aapt
-
-#endif /* AAPT_FLATTEN_FILEEXPORTWRITER_H */
diff --git a/tools/aapt2/flatten/FileExportWriter_test.cpp b/tools/aapt2/flatten/FileExportWriter_test.cpp
deleted file mode 100644
index 32fc203c4dee..000000000000
--- a/tools/aapt2/flatten/FileExportWriter_test.cpp
+++ /dev/null
@@ -1,51 +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.
- */
-
-#include "Resource.h"
-
-#include "flatten/FileExportWriter.h"
-#include "util/BigBuffer.h"
-#include "util/Util.h"
-
-#include "test/Common.h"
-
-#include <gtest/gtest.h>
-
-namespace aapt {
-
-TEST(FileExportWriterTest, FlattenResourceFileDataWithNoExports) {
- ResourceFile resFile = {
- test::parseNameOrDie(u"@android:layout/main.xml"),
- test::parseConfigOrDie("sw600dp-v4"),
- Source{ "res/layout/main.xml" },
- };
-
- BigBuffer buffer(1024);
- ChunkWriter writer = wrapBufferWithFileExportHeader(&buffer, &resFile);
- *writer.getBuffer()->nextBlock<uint32_t>() = 42u;
- writer.finish();
-
- std::unique_ptr<uint8_t[]> data = util::copy(buffer);
-
- // There should be more data (string pool) besides the header and our data.
- ASSERT_GT(buffer.size(), sizeof(FileExport_header) + sizeof(uint32_t));
-
- // Write at the end of this chunk is our data.
- uint32_t* val = (uint32_t*)(data.get() + buffer.size()) - 1;
- EXPECT_EQ(*val, 42u);
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/flatten/ResourceTypeExtensions.h b/tools/aapt2/flatten/ResourceTypeExtensions.h
index 02bff2c69362..3e20ad643eb6 100644
--- a/tools/aapt2/flatten/ResourceTypeExtensions.h
+++ b/tools/aapt2/flatten/ResourceTypeExtensions.h
@@ -22,208 +22,6 @@
namespace aapt {
/**
- * New android::ResChunk_header types defined
- * for AAPT to use.
- *
- * TODO(adamlesinski): Consider reserving these
- * enums in androidfw/ResourceTypes.h to avoid
- * future collisions.
- */
-enum {
- /**
- * A chunk that contains an entire file that
- * has been compiled.
- */
- RES_FILE_EXPORT_TYPE = 0x000c,
-
- RES_TABLE_PUBLIC_TYPE = 0x000d,
-
- /**
- * A chunk that holds the string pool
- * for source entries (path/to/source:line).
- */
- RES_TABLE_SOURCE_POOL_TYPE = 0x000e,
-
- /**
- * A chunk holding names of externally
- * defined symbols and offsets to where
- * they are referenced in the table.
- */
- RES_TABLE_SYMBOL_TABLE_TYPE = 0x000f,
-};
-
-/**
- * New resource types that are meant to only be used
- * by AAPT and will not end up on the device.
- */
-struct ExtendedTypes {
- enum {
- /**
- * A raw string value that hasn't had its escape sequences
- * processed nor whitespace removed.
- */
- TYPE_RAW_STRING = 0xfe,
- };
-};
-
-/**
- * New types for a ResTable_map.
- */
-struct ExtendedResTableMapTypes {
- enum {
- /**
- * Type that contains the source path of the next item in the map.
- */
- ATTR_SOURCE_PATH = Res_MAKEINTERNAL(0xffff),
-
- /**
- * Type that contains the source line of the next item in the map.
- */
- ATTR_SOURCE_LINE = Res_MAKEINTERNAL(0xfffe),
-
- /**
- * Type that contains the comment of the next item in the map.
- */
- ATTR_COMMENT = Res_MAKEINTERNAL(0xfffd)
- };
-};
-
-/**
- * Followed by exportedSymbolCount ExportedSymbol structs, followed by the string pool.
- */
-struct FileExport_header {
- android::ResChunk_header header;
-
- /**
- * MAGIC value. Must be 'AAPT' (0x41415054)
- */
- uint8_t magic[4];
-
- /**
- * Version of AAPT that built this file.
- */
- uint32_t version;
-
- /**
- * The resource name.
- */
- android::ResStringPool_ref name;
-
- /**
- * Configuration of this file.
- */
- android::ResTable_config config;
-
- /**
- * Original source path of this file.
- */
- android::ResStringPool_ref source;
-
- /**
- * Number of symbols exported by this file.
- */
- uint32_t exportedSymbolCount;
-};
-
-struct ExportedSymbol {
- android::ResStringPool_ref name;
- uint32_t line;
-};
-
-struct Public_header {
- android::ResChunk_header header;
-
- /**
- * The ID of the type this structure refers to.
- */
- uint8_t typeId;
-
- /**
- * Reserved. Must be 0.
- */
- uint8_t res0;
-
- /**
- * Reserved. Must be 0.
- */
- uint16_t res1;
-
- /**
- * Number of public entries.
- */
- uint32_t count;
-};
-
-/**
- * A structure representing source data for a resource entry.
- * Appears after an android::ResTable_entry or android::ResTable_map_entry.
- *
- * TODO(adamlesinski): This causes some issues when runtime code checks
- * the size of an android::ResTable_entry. It assumes it is an
- * android::ResTable_map_entry if the size is bigger than an android::ResTable_entry
- * which may not be true if this structure is present.
- */
-struct ResTable_entry_source {
- /**
- * File path reference.
- */
- android::ResStringPool_ref path;
-
- /**
- * Line number this resource was defined on.
- */
- uint32_t line;
-
- /**
- * Comment string reference.
- */
- android::ResStringPool_ref comment;
-};
-
-struct Public_entry {
- uint16_t entryId;
-
- enum : uint16_t {
- kUndefined = 0,
- kPublic = 1,
- kPrivate = 2,
- };
-
- uint16_t state;
- android::ResStringPool_ref key;
- ResTable_entry_source source;
-};
-
-/**
- * A chunk with type RES_TABLE_SYMBOL_TABLE_TYPE.
- * Following the header are count number of SymbolTable_entry
- * structures, followed by an android::ResStringPool_header.
- */
-struct SymbolTable_header {
- android::ResChunk_header header;
-
- /**
- * Number of SymbolTable_entry structures following
- * this header.
- */
- uint32_t count;
-};
-
-struct SymbolTable_entry {
- /**
- * Offset from the beginning of the resource table
- * where the symbol entry is referenced.
- */
- uint32_t offset;
-
- /**
- * The index into the string pool where the name of this
- * symbol exists.
- */
- android::ResStringPool_ref name;
-};
-
-/**
* An alternative struct to use instead of ResTable_map_entry. This one is a standard_layout
* struct.
*/
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 26d7c2ca055c..da81046b2e42 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -51,157 +51,49 @@ static void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) {
dst[i] = 0;
}
+static bool cmpStyleEntries(const Style::Entry& a, const Style::Entry& b) {
+ if (a.key.id) {
+ if (b.key.id) {
+ return a.key.id.value() < b.key.id.value();
+ }
+ return true;
+ } else if (!b.key.id) {
+ return a.key.name.value() < b.key.name.value();
+ }
+ return false;
+}
+
struct FlatEntry {
ResourceEntry* entry;
Value* value;
// The entry string pool index to the entry's name.
uint32_t entryKey;
-
- // The source string pool index to the source file path.
- uint32_t sourcePathKey;
- uint32_t sourceLine;
-
- // The source string pool index to the comment.
- uint32_t commentKey;
};
-class SymbolWriter {
+class MapFlattenVisitor : public RawValueVisitor {
public:
- struct Entry {
- StringPool::Ref name;
- size_t offset;
- };
-
- std::vector<Entry> symbols;
-
- explicit SymbolWriter(StringPool* pool) : mPool(pool) {
- }
-
- void addSymbol(const Reference& ref, size_t offset) {
- const ResourceName& name = ref.name.value();
- std::u16string fullName;
- if (ref.privateReference) {
- fullName += u"*";
- }
-
- if (!name.package.empty()) {
- fullName += name.package + u":";
- }
- fullName += toString(name.type).toString() + u"/" + name.entry;
- symbols.push_back(Entry{ mPool->makeRef(fullName), offset });
- }
-
- void shiftAllOffsets(size_t offset) {
- for (Entry& entry : symbols) {
- entry.offset += offset;
- }
- }
-
-private:
- StringPool* mPool;
-};
-
-struct MapFlattenVisitor : public RawValueVisitor {
using RawValueVisitor::visit;
- SymbolWriter* mSymbols;
- FlatEntry* mEntry;
- BigBuffer* mBuffer;
- StringPool* mSourcePool;
- StringPool* mCommentPool;
- bool mUseExtendedChunks;
-
- size_t mEntryCount = 0;
- const Reference* mParent = nullptr;
-
- MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer,
- StringPool* sourcePool, StringPool* commentPool,
- bool useExtendedChunks) :
- mSymbols(symbols), mEntry(entry), mBuffer(buffer), mSourcePool(sourcePool),
- mCommentPool(commentPool), mUseExtendedChunks(useExtendedChunks) {
- }
-
- void flattenKey(Reference* key, ResTable_map* outEntry) {
- if (!key->id || (key->privateReference && mUseExtendedChunks)) {
- assert(key->name && "reference must have a name");
-
- outEntry->name.ident = util::hostToDevice32(0);
- mSymbols->addSymbol(*key, (mBuffer->size() - sizeof(ResTable_map)) +
- offsetof(ResTable_map, name));
- } else {
- outEntry->name.ident = util::hostToDevice32(key->id.value().id);
- }
- }
-
- void flattenValue(Item* value, ResTable_map* outEntry) {
- bool privateRef = false;
- if (Reference* ref = valueCast<Reference>(value)) {
- privateRef = ref->privateReference && mUseExtendedChunks;
- if (!ref->id || privateRef) {
- assert(ref->name && "reference must have a name");
-
- mSymbols->addSymbol(*ref, (mBuffer->size() - sizeof(ResTable_map)) +
- offsetof(ResTable_map, value) + offsetof(Res_value, data));
- }
- }
-
- bool result = value->flatten(&outEntry->value);
- if (privateRef) {
- outEntry->value.data = 0;
- }
- assert(result && "flatten failed");
- }
-
- void flattenEntry(Reference* key, Item* value) {
- ResTable_map* outEntry = mBuffer->nextBlock<ResTable_map>();
- flattenKey(key, outEntry);
- flattenValue(value, outEntry);
- outEntry->value.size = util::hostToDevice16(sizeof(outEntry->value));
- mEntryCount++;
- }
-
- void flattenMetaData(Value* value) {
- if (!mUseExtendedChunks) {
- return;
- }
-
- Reference key(ResourceId{ ExtendedResTableMapTypes::ATTR_SOURCE_PATH });
- StringPool::Ref sourcePathRef = mSourcePool->makeRef(
- util::utf8ToUtf16(value->getSource().path));
- BinaryPrimitive val(Res_value::TYPE_INT_DEC,
- static_cast<uint32_t>(sourcePathRef.getIndex()));
- flattenEntry(&key, &val);
-
- if (value->getSource().line) {
- key.id = ResourceId(ExtendedResTableMapTypes::ATTR_SOURCE_LINE);
- val.value.data = static_cast<uint32_t>(value->getSource().line.value());
- flattenEntry(&key, &val);
- }
-
- if (!value->getComment().empty()) {
- key.id = ResourceId(ExtendedResTableMapTypes::ATTR_COMMENT);
- StringPool::Ref commentRef = mCommentPool->makeRef(value->getComment());
- val.value.data = static_cast<uint32_t>(commentRef.getIndex());
- flattenEntry(&key, &val);
- }
+ MapFlattenVisitor(ResTable_entry_ext* outEntry, BigBuffer* buffer) :
+ mOutEntry(outEntry), mBuffer(buffer) {
}
void visit(Attribute* attr) override {
{
- Reference key(ResourceId{ ResTable_map::ATTR_TYPE });
+ Reference key = Reference(ResTable_map::ATTR_TYPE);
BinaryPrimitive val(Res_value::TYPE_INT_DEC, attr->typeMask);
flattenEntry(&key, &val);
}
if (attr->minInt != std::numeric_limits<int32_t>::min()) {
- Reference key(ResourceId{ ResTable_map::ATTR_MIN });
+ Reference key = Reference(ResTable_map::ATTR_MIN);
BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->minInt));
flattenEntry(&key, &val);
}
if (attr->maxInt != std::numeric_limits<int32_t>::max()) {
- Reference key(ResourceId{ ResTable_map::ATTR_MAX });
+ Reference key = Reference(ResTable_map::ATTR_MAX);
BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->maxInt));
flattenEntry(&key, &val);
}
@@ -212,22 +104,11 @@ struct MapFlattenVisitor : public RawValueVisitor {
}
}
- static bool cmpStyleEntries(const Style::Entry& a, const Style::Entry& b) {
- if (a.key.id) {
- if (b.key.id) {
- return a.key.id.value() < b.key.id.value();
- }
- return true;
- } else if (!b.key.id) {
- return a.key.name.value() < b.key.name.value();
- }
- return false;
- }
-
void visit(Style* style) override {
if (style->parent) {
- // Parents are treated a bit differently, so record the existence and move on.
- mParent = &style->parent.value();
+ const Reference& parentRef = style->parent.value();
+ assert(parentRef.id && "parent has no ID");
+ mOutEntry->parent.ident = util::hostToDevice32(parentRef.id.value().id);
}
// Sort the style.
@@ -235,7 +116,6 @@ struct MapFlattenVisitor : public RawValueVisitor {
for (Style::Entry& entry : style->entries) {
flattenEntry(&entry.key, entry.value.get());
- flattenMetaData(&entry.key);
}
}
@@ -243,8 +123,8 @@ struct MapFlattenVisitor : public RawValueVisitor {
for (auto& attrRef : styleable->entries) {
BinaryPrimitive val(Res_value{});
flattenEntry(&attrRef, &val);
- flattenMetaData(&attrRef);
}
+
}
void visit(Array* array) override {
@@ -253,7 +133,6 @@ struct MapFlattenVisitor : public RawValueVisitor {
flattenValue(item.get(), outEntry);
outEntry->value.size = util::hostToDevice16(sizeof(outEntry->value));
mEntryCount++;
- flattenMetaData(item.get());
}
}
@@ -297,18 +176,45 @@ struct MapFlattenVisitor : public RawValueVisitor {
Reference key(q);
flattenEntry(&key, plural->values[i].get());
- flattenMetaData(plural->values[i].get());
}
}
+
+ /**
+ * Call this after visiting a Value. This will finish any work that
+ * needs to be done to prepare the entry.
+ */
+ void finish() {
+ mOutEntry->count = util::hostToDevice32(mEntryCount);
+ }
+
+private:
+ void flattenKey(Reference* key, ResTable_map* outEntry) {
+ assert(key->id && "key has no ID");
+ outEntry->name.ident = util::hostToDevice32(key->id.value().id);
+ }
+
+ void flattenValue(Item* value, ResTable_map* outEntry) {
+ bool result = value->flatten(&outEntry->value);
+ assert(result && "flatten failed");
+ }
+
+ void flattenEntry(Reference* key, Item* value) {
+ ResTable_map* outEntry = mBuffer->nextBlock<ResTable_map>();
+ flattenKey(key, outEntry);
+ flattenValue(value, outEntry);
+ outEntry->value.size = util::hostToDevice16(sizeof(outEntry->value));
+ mEntryCount++;
+ }
+
+ ResTable_entry_ext* mOutEntry;
+ BigBuffer* mBuffer;
+ size_t mEntryCount = 0;
};
class PackageFlattener {
public:
- PackageFlattener(IDiagnostics* diag, TableFlattenerOptions options,
- ResourceTablePackage* package, SymbolWriter* symbolWriter,
- StringPool* sourcePool) :
- mDiag(diag), mOptions(options), mPackage(package), mSymbols(symbolWriter),
- mSourcePool(sourcePool) {
+ PackageFlattener(IDiagnostics* diag, ResourceTablePackage* package) :
+ mDiag(diag), mPackage(package) {
}
bool flattenPackage(BigBuffer* buffer) {
@@ -337,9 +243,6 @@ public:
pkgHeader->keyStrings = util::hostToDevice32(pkgWriter.size());
StringPool::flattenUtf16(pkgWriter.getBuffer(), mKeyPool);
- // Add the ResTable_package header/type/key strings to the offset.
- mSymbols->shiftAllOffsets(pkgWriter.size());
-
// Append the types.
buffer->appendBuffer(std::move(typeBuffer));
@@ -349,12 +252,9 @@ public:
private:
IDiagnostics* mDiag;
- TableFlattenerOptions mOptions;
ResourceTablePackage* mPackage;
StringPool mTypePool;
StringPool mKeyPool;
- SymbolWriter* mSymbols;
- StringPool* mSourcePool;
template <typename T, bool IsItem>
T* writeEntry(FlatEntry* entry, BigBuffer* buffer) {
@@ -376,62 +276,24 @@ private:
outEntry->flags |= ResTable_entry::FLAG_COMPLEX;
}
- outEntry->key.index = util::hostToDevice32(entry->entryKey);
- outEntry->size = sizeof(T);
-
- if (mOptions.useExtendedChunks) {
- // Write the extra source block. This will be ignored by the Android runtime.
- ResTable_entry_source* sourceBlock = buffer->nextBlock<ResTable_entry_source>();
- sourceBlock->path.index = util::hostToDevice32(entry->sourcePathKey);
- sourceBlock->line = util::hostToDevice32(entry->sourceLine);
- sourceBlock->comment.index = util::hostToDevice32(entry->commentKey);
- outEntry->size += sizeof(*sourceBlock);
- }
-
outEntry->flags = util::hostToDevice16(outEntry->flags);
- outEntry->size = util::hostToDevice16(outEntry->size);
+ outEntry->key.index = util::hostToDevice32(entry->entryKey);
+ outEntry->size = util::hostToDevice16(sizeof(T));
return result;
}
bool flattenValue(FlatEntry* entry, BigBuffer* buffer) {
if (Item* item = valueCast<Item>(entry->value)) {
writeEntry<ResTable_entry, true>(entry, buffer);
- bool privateRef = false;
- if (Reference* ref = valueCast<Reference>(entry->value)) {
- // If there is no ID or the reference is private and we allow extended chunks,
- // write out a 0 and mark the symbol table with the name of the reference.
- privateRef = (ref->privateReference && mOptions.useExtendedChunks);
- if (!ref->id || privateRef) {
- assert(ref->name && "reference must have at least a name");
- mSymbols->addSymbol(*ref, buffer->size() + offsetof(Res_value, data));
- }
- }
Res_value* outValue = buffer->nextBlock<Res_value>();
bool result = item->flatten(outValue);
assert(result && "flatten failed");
- if (privateRef) {
- // Force the value of 0 so we look up the symbol at unflatten time.
- outValue->data = 0;
- }
outValue->size = util::hostToDevice16(sizeof(*outValue));
} else {
- const size_t beforeEntry = buffer->size();
ResTable_entry_ext* outEntry = writeEntry<ResTable_entry_ext, false>(entry, buffer);
- MapFlattenVisitor visitor(mSymbols, entry, buffer, mSourcePool, mSourcePool,
- mOptions.useExtendedChunks);
+ MapFlattenVisitor visitor(outEntry, buffer);
entry->value->accept(&visitor);
- outEntry->count = util::hostToDevice32(visitor.mEntryCount);
- if (visitor.mParent) {
- const bool forceSymbol = visitor.mParent->privateReference &&
- mOptions.useExtendedChunks;
- if (!visitor.mParent->id || forceSymbol) {
- assert(visitor.mParent->name && "reference must have a name");
- mSymbols->addSymbol(*visitor.mParent,
- beforeEntry + offsetof(ResTable_entry_ext, parent));
- } else {
- outEntry->parent.ident = util::hostToDevice32(visitor.mParent->id.value().id);
- }
- }
+ visitor.finish();
}
return true;
}
@@ -480,7 +342,7 @@ private:
std::vector<ResourceTableType*> collectAndSortTypes() {
std::vector<ResourceTableType*> sortedTypes;
for (auto& type : mPackage->types) {
- if (type->type == ResourceType::kStyleable && !mOptions.useExtendedChunks) {
+ if (type->type == ResourceType::kStyleable) {
// Styleables aren't real Resource Types, they are represented in the R.java
// file.
continue;
@@ -540,10 +402,10 @@ private:
const size_t configCount = entry->values.size();
for (size_t i = 0; i < configCount; i++) {
- const ConfigDescription& config = entry->values[i].config;
+ const ConfigDescription& config = entry->values[i]->config;
for (size_t j = i + 1; j < configCount; j++) {
configMasks[entry->id.value()] |= util::hostToDevice32(
- config.diff(entry->values[j].config));
+ config.diff(entry->values[j]->config));
}
}
}
@@ -551,52 +413,6 @@ private:
return true;
}
- bool flattenPublic(ResourceTableType* type, std::vector<ResourceEntry*>* sortedEntries,
- BigBuffer* buffer) {
- ChunkWriter publicWriter(buffer);
- Public_header* publicHeader = publicWriter.startChunk<Public_header>(RES_TABLE_PUBLIC_TYPE);
- publicHeader->typeId = type->id.value();
-
- for (ResourceEntry* entry : *sortedEntries) {
- if (entry->symbolStatus.state != SymbolState::kUndefined) {
- // Write the public status of this entry.
- Public_entry* publicEntry = publicWriter.nextBlock<Public_entry>();
- publicEntry->entryId = util::hostToDevice32(entry->id.value());
- publicEntry->key.index = util::hostToDevice32(mKeyPool.makeRef(
- entry->name).getIndex());
- publicEntry->source.path.index = util::hostToDevice32(mSourcePool->makeRef(
- util::utf8ToUtf16(entry->symbolStatus.source.path)).getIndex());
- if (entry->symbolStatus.source.line) {
- publicEntry->source.line = util::hostToDevice32(
- entry->symbolStatus.source.line.value());
- }
- publicEntry->source.comment.index = util::hostToDevice32(mSourcePool->makeRef(
- entry->symbolStatus.comment).getIndex());
-
- switch (entry->symbolStatus.state) {
- case SymbolState::kPrivate:
- publicEntry->state = Public_entry::kPrivate;
- break;
-
- case SymbolState::kPublic:
- publicEntry->state = Public_entry::kPublic;
- break;
-
- case SymbolState::kUndefined:
- publicEntry->state = Public_entry::kUndefined;
- break;
- }
-
- // Don't hostToDevice until the last step.
- publicHeader->count += 1;
- }
- }
-
- publicHeader->count = util::hostToDevice32(publicHeader->count);
- publicWriter.finish();
- return true;
- }
-
bool flattenTypes(BigBuffer* buffer) {
// Sort the types by their IDs. They will be inserted into the StringPool in this order.
std::vector<ResourceTableType*> sortedTypes = collectAndSortTypes();
@@ -620,12 +436,6 @@ private:
return false;
}
- if (mOptions.useExtendedChunks) {
- if (!flattenPublic(type, &sortedEntries, buffer)) {
- return false;
- }
- }
-
// The binary resource table lists resource entries for each configuration.
// We store them inverted, where a resource entry lists the values for each
// configuration available. Here we reverse this to match the binary table.
@@ -635,26 +445,8 @@ private:
// Group values by configuration.
for (auto& configValue : entry->values) {
- Value* value = configValue.value.get();
-
- const StringPool::Ref sourceRef = mSourcePool->makeRef(
- util::utf8ToUtf16(value->getSource().path));
-
- uint32_t lineNumber = 0;
- if (value->getSource().line) {
- lineNumber = value->getSource().line.value();
- }
-
- const StringPool::Ref commentRef = mSourcePool->makeRef(value->getComment());
-
- configToEntryListMap[configValue.config]
- .push_back(FlatEntry{
- entry,
- value,
- keyIndex,
- (uint32_t) sourceRef.getIndex(),
- lineNumber,
- (uint32_t) commentRef.getIndex() });
+ configToEntryListMap[configValue->config].push_back(FlatEntry{
+ entry, configValue->value.get(), keyIndex });
}
}
@@ -692,86 +484,18 @@ bool TableFlattener::consume(IAaptContext* context, ResourceTable* table) {
// Flatten the values string pool.
StringPool::flattenUtf8(tableWriter.getBuffer(), table->stringPool);
- // If we have a reference to a symbol that doesn't exist, we don't know its resource ID.
- // We encode the name of the symbol along with the offset of where to include the resource ID
- // once it is found.
- StringPool symbolPool;
- std::vector<SymbolWriter::Entry> symbolOffsets;
-
- // String pool holding the source paths of each value.
- StringPool sourcePool;
-
BigBuffer packageBuffer(1024);
// Flatten each package.
for (auto& package : table->packages) {
- const size_t beforePackageSize = packageBuffer.size();
-
- // All packages will share a single global symbol pool.
- SymbolWriter packageSymbolWriter(&symbolPool);
-
- PackageFlattener flattener(context->getDiagnostics(), mOptions, package.get(),
- &packageSymbolWriter, &sourcePool);
+ PackageFlattener flattener(context->getDiagnostics(), package.get());
if (!flattener.flattenPackage(&packageBuffer)) {
return false;
}
-
- // The symbols are offset only from their own Package start. Offset them from the
- // start of the packageBuffer.
- packageSymbolWriter.shiftAllOffsets(beforePackageSize);
-
- // Extract all the symbols to offset
- symbolOffsets.insert(symbolOffsets.end(),
- std::make_move_iterator(packageSymbolWriter.symbols.begin()),
- std::make_move_iterator(packageSymbolWriter.symbols.end()));
}
- SymbolTable_entry* symbolEntryData = nullptr;
- if (mOptions.useExtendedChunks) {
- if (!symbolOffsets.empty()) {
- // Sort the offsets so we can scan them linearly.
- std::sort(symbolOffsets.begin(), symbolOffsets.end(),
- [](const SymbolWriter::Entry& a, const SymbolWriter::Entry& b) -> bool {
- return a.offset < b.offset;
- });
-
- // Write the Symbol header.
- ChunkWriter symbolWriter(tableWriter.getBuffer());
- SymbolTable_header* symbolHeader = symbolWriter.startChunk<SymbolTable_header>(
- RES_TABLE_SYMBOL_TABLE_TYPE);
- symbolHeader->count = util::hostToDevice32(symbolOffsets.size());
-
- symbolEntryData = symbolWriter.nextBlock<SymbolTable_entry>(symbolOffsets.size());
- StringPool::flattenUtf8(symbolWriter.getBuffer(), symbolPool);
- symbolWriter.finish();
- }
-
- if (sourcePool.size() > 0) {
- // Write out source pool.
- ChunkWriter srcWriter(tableWriter.getBuffer());
- srcWriter.startChunk<ResChunk_header>(RES_TABLE_SOURCE_POOL_TYPE);
- StringPool::flattenUtf8(srcWriter.getBuffer(), sourcePool);
- srcWriter.finish();
- }
- }
-
- const size_t beforePackagesSize = tableWriter.size();
-
// Finally merge all the packages into the main buffer.
tableWriter.getBuffer()->appendBuffer(std::move(packageBuffer));
-
- // Update the offsets to their final values.
- if (symbolEntryData) {
- for (SymbolWriter::Entry& entry : symbolOffsets) {
- symbolEntryData->name.index = util::hostToDevice32(entry.name.getIndex());
-
- // The symbols were all calculated with the packageBuffer offset. We need to
- // add the beginning of the output buffer.
- symbolEntryData->offset = util::hostToDevice32(entry.offset + beforePackagesSize);
- symbolEntryData++;
- }
- }
-
tableWriter.finish();
return true;
}
diff --git a/tools/aapt2/flatten/TableFlattener.h b/tools/aapt2/flatten/TableFlattener.h
index 901b129725ea..0ab01974044b 100644
--- a/tools/aapt2/flatten/TableFlattener.h
+++ b/tools/aapt2/flatten/TableFlattener.h
@@ -24,28 +24,15 @@ namespace aapt {
class BigBuffer;
class ResourceTable;
-struct TableFlattenerOptions {
- /**
- * Specifies whether to output extended chunks, like
- * source information and missing symbol entries. Default
- * is false.
- *
- * Set this to true when emitting intermediate resource table.
- */
- bool useExtendedChunks = false;
-};
-
class TableFlattener : public IResourceTableConsumer {
public:
- TableFlattener(BigBuffer* buffer, TableFlattenerOptions options) :
- mBuffer(buffer), mOptions(options) {
+ TableFlattener(BigBuffer* buffer) : mBuffer(buffer) {
}
bool consume(IAaptContext* context, ResourceTable* table) override;
private:
BigBuffer* mBuffer;
- TableFlattenerOptions mOptions;
};
} // namespace aapt
diff --git a/tools/aapt2/flatten/TableFlattener_test.cpp b/tools/aapt2/flatten/TableFlattener_test.cpp
index 7030603e5bbd..39c4fd318508 100644
--- a/tools/aapt2/flatten/TableFlattener_test.cpp
+++ b/tools/aapt2/flatten/TableFlattener_test.cpp
@@ -38,9 +38,7 @@ public:
::testing::AssertionResult flatten(ResourceTable* table, ResTable* outTable) {
BigBuffer buffer(1024);
- TableFlattenerOptions options = {};
- options.useExtendedChunks = true;
- TableFlattener flattener(&buffer, options);
+ TableFlattener flattener(&buffer);
if (!flattener.consume(mContext.get(), table)) {
return ::testing::AssertionFailure() << "failed to flatten ResourceTable";
}
@@ -54,9 +52,7 @@ public:
::testing::AssertionResult flatten(ResourceTable* table, ResourceTable* outTable) {
BigBuffer buffer(1024);
- TableFlattenerOptions options = {};
- options.useExtendedChunks = true;
- TableFlattener flattener(&buffer, options);
+ TableFlattener flattener(&buffer);
if (!flattener.consume(mContext.get(), table)) {
return ::testing::AssertionFailure() << "failed to flatten ResourceTable";
}
@@ -210,58 +206,6 @@ TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) {
Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
}
-TEST_F(TableFlattenerTest, FlattenUnlinkedTable) {
- std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
- .setPackageId(u"com.app.test", 0x7f)
- .addValue(u"@com.app.test:integer/one", ResourceId(0x7f020000),
- test::buildReference(u"@android:integer/foo"))
- .addValue(u"@com.app.test:style/Theme", ResourceId(0x7f030000), test::StyleBuilder()
- .setParent(u"@android:style/Theme.Material")
- .addItem(u"@android:attr/background", {})
- .addItem(u"@android:attr/colorAccent",
- test::buildReference(u"@com.app.test:color/green"))
- .build())
- .build();
-
- {
- // Need access to stringPool to make RawString.
- Style* style = test::getValue<Style>(table.get(), u"@com.app.test:style/Theme");
- style->entries[0].value = util::make_unique<RawString>(table->stringPool.makeRef(u"foo"));
- }
-
- ResourceTable finalTable;
- ASSERT_TRUE(flatten(table.get(), &finalTable));
-
- Reference* ref = test::getValue<Reference>(&finalTable, u"@com.app.test:integer/one");
- ASSERT_NE(ref, nullptr);
- AAPT_ASSERT_TRUE(ref->name);
- EXPECT_EQ(ref->name.value(), test::parseNameOrDie(u"@android:integer/foo"));
-
- Style* style = test::getValue<Style>(&finalTable, u"@com.app.test:style/Theme");
- ASSERT_NE(style, nullptr);
- AAPT_ASSERT_TRUE(style->parent);
- AAPT_ASSERT_TRUE(style->parent.value().name);
- EXPECT_EQ(style->parent.value().name.value(),
- test::parseNameOrDie(u"@android:style/Theme.Material"));
-
- ASSERT_EQ(2u, style->entries.size());
-
- AAPT_ASSERT_TRUE(style->entries[0].key.name);
- EXPECT_EQ(style->entries[0].key.name.value(),
- test::parseNameOrDie(u"@android:attr/background"));
- RawString* raw = valueCast<RawString>(style->entries[0].value.get());
- ASSERT_NE(raw, nullptr);
- EXPECT_EQ(*raw->value, u"foo");
-
- AAPT_ASSERT_TRUE(style->entries[1].key.name);
- EXPECT_EQ(style->entries[1].key.name.value(),
- test::parseNameOrDie(u"@android:attr/colorAccent"));
- ref = valueCast<Reference>(style->entries[1].value.get());
- ASSERT_NE(ref, nullptr);
- AAPT_ASSERT_TRUE(ref->name);
- EXPECT_EQ(ref->name.value(), test::parseNameOrDie(u"@com.app.test:color/green"));
-}
-
TEST_F(TableFlattenerTest, FlattenMinMaxAttributes) {
Attribute attr(false);
attr.typeMask = android::ResTable_map::TYPE_INTEGER;
@@ -284,33 +228,4 @@ TEST_F(TableFlattenerTest, FlattenMinMaxAttributes) {
EXPECT_EQ(attr.maxInt, actualAttr->maxInt);
}
-TEST_F(TableFlattenerTest, FlattenSourceAndCommentsForChildrenOfCompoundValues) {
- Style style;
- Reference key(test::parseNameOrDie(u"@android:attr/foo"));
- key.id = ResourceId(0x01010000);
- key.setSource(Source("test").withLine(2));
- key.setComment(StringPiece16(u"comment"));
- style.entries.push_back(Style::Entry{ key, util::make_unique<Id>() });
-
- test::ResourceTableBuilder builder = test::ResourceTableBuilder();
- std::unique_ptr<ResourceTable> table = builder
- .setPackageId(u"android", 0x01)
- .addValue(u"@android:attr/foo", ResourceId(0x01010000),
- test::AttributeBuilder().build())
- .addValue(u"@android:style/foo", ResourceId(0x01020000),
- std::unique_ptr<Style>(style.clone(builder.getStringPool())))
- .build();
-
- ResourceTable result;
- ASSERT_TRUE(flatten(table.get(), &result));
-
- Style* actualStyle = test::getValue<Style>(&result, u"@android:style/foo");
- ASSERT_NE(nullptr, actualStyle);
- ASSERT_EQ(1u, actualStyle->entries.size());
-
- Reference* actualKey = &actualStyle->entries[0].key;
- EXPECT_EQ(key.getSource(), actualKey->getSource());
- EXPECT_EQ(key.getComment(), actualKey->getComment());
-}
-
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 7280f3a968a0..6e340a2a2742 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -23,7 +23,6 @@
#include "java/AnnotationProcessor.h"
#include "java/ClassDefinitionWriter.h"
#include "java/JavaClassGenerator.h"
-#include "util/Comparators.h"
#include "util/StringPiece.h"
#include <algorithm>
@@ -258,12 +257,12 @@ bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef
}
for (const auto& configValue : entry->values) {
- processor.appendComment(configValue.value->getComment());
+ processor.appendComment(configValue->value->getComment());
}
// If this is an Attribute, append the format Javadoc.
if (!entry->values.empty()) {
- if (Attribute* attr = valueCast<Attribute>(entry->values.front().value.get())) {
+ if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
// We list out the available values for the given attribute.
addAttributeFormatDoc(&processor, attr);
}
@@ -272,7 +271,7 @@ bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef
if (type->type == ResourceType::kStyleable) {
assert(!entry->values.empty());
const Styleable* styleable = static_cast<const Styleable*>(
- entry->values.front().value.get());
+ entry->values.front()->value.get());
writeStyleableEntryForClass(outClassDef, &processor, packageNameToGenerate,
unmangledName, styleable);
} else {
@@ -311,11 +310,10 @@ bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
if (type->type == ResourceType::kAttr) {
// Also include private attributes in this same class.
- auto iter = std::lower_bound(package->types.begin(), package->types.end(),
- ResourceType::kAttrPrivate, cmp::lessThanType);
- if (iter != package->types.end() && (*iter)->type == ResourceType::kAttrPrivate) {
+ ResourceTableType* privType = package->findType(ResourceType::kAttrPrivate);
+ if (privType) {
result = writeEntriesForClass(&classDef, packageNameToGenerate,
- package.get(), iter->get());
+ package.get(), privType);
if (!result) {
return false;
}
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index c7e603ea3774..459c330cfbdc 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -18,9 +18,7 @@
#include "ResourceTable.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
-
#include "link/Linkers.h"
-#include "util/Comparators.h"
#include <algorithm>
#include <cassert>
@@ -31,7 +29,12 @@ bool shouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDes
const int sdkVersionToGenerate) {
assert(sdkVersionToGenerate > config.sdkVersion);
const auto endIter = entry->values.end();
- auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmp::lessThanConfig);
+ auto iter = entry->values.begin();
+ for (; iter != endIter; ++iter) {
+ if ((*iter)->config == config) {
+ break;
+ }
+ }
// The source config came from this list, so it should be here.
assert(iter != entry->values.end());
@@ -45,10 +48,10 @@ bool shouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDes
// are no higher sdk level versions of this resource.
ConfigDescription tempConfig(config);
for (; iter != endIter; ++iter) {
- tempConfig.sdkVersion = iter->config.sdkVersion;
- if (tempConfig == iter->config) {
+ tempConfig.sdkVersion = (*iter)->config.sdkVersion;
+ if (tempConfig == (*iter)->config) {
// The two configs are the same, check the sdk version.
- return sdkVersionToGenerate < iter->config.sdkVersion;
+ return sdkVersionToGenerate < (*iter)->config.sdkVersion;
}
}
@@ -65,14 +68,14 @@ bool AutoVersioner::consume(IAaptContext* context, ResourceTable* table) {
for (auto& entry : type->entries) {
for (size_t i = 0; i < entry->values.size(); i++) {
- ResourceConfigValue& configValue = entry->values[i];
- if (configValue.config.sdkVersion >= SDK_LOLLIPOP_MR1) {
+ ResourceConfigValue* configValue = entry->values[i].get();
+ if (configValue->config.sdkVersion >= SDK_LOLLIPOP_MR1) {
// If this configuration is only used on L-MR1 then we don't need
// to do anything since we use private attributes since that version.
continue;
}
- if (Style* style = valueCast<Style>(configValue.value.get())) {
+ if (Style* style = valueCast<Style>(configValue->value.get())) {
Maybe<size_t> minSdkStripped;
std::vector<Style::Entry> stripped;
@@ -82,7 +85,7 @@ bool AutoVersioner::consume(IAaptContext* context, ResourceTable* table) {
// Find the SDK level that is higher than the configuration allows.
const size_t sdkLevel = findAttributeSdkLevel(iter->key.id.value());
- if (sdkLevel > std::max<size_t>(configValue.config.sdkVersion, 1)) {
+ if (sdkLevel > std::max<size_t>(configValue->config.sdkVersion, 1)) {
// Record that we are about to strip this.
stripped.emplace_back(std::move(*iter));
@@ -105,10 +108,10 @@ bool AutoVersioner::consume(IAaptContext* context, ResourceTable* table) {
// there is no other defined resource for the version we want to
// generate.
if (shouldGenerateVersionedResource(entry.get(),
- configValue.config,
+ configValue->config,
minSdkStripped.value())) {
// Let's create a new Style for this versioned resource.
- ConfigDescription newConfig(configValue.config);
+ ConfigDescription newConfig(configValue->config);
newConfig.sdkVersion = minSdkStripped.value();
std::unique_ptr<Style> newStyle(style->clone(&table->stringPool));
@@ -121,14 +124,8 @@ bool AutoVersioner::consume(IAaptContext* context, ResourceTable* table) {
std::make_move_iterator(stripped.end()));
// Insert the new Resource into the correct place.
- auto iter = std::lower_bound(entry->values.begin(),
- entry->values.end(),
- newConfig,
- cmp::lessThanConfig);
-
- entry->values.insert(
- iter,
- ResourceConfigValue{ newConfig, std::move(newStyle) });
+ entry->findOrCreateValue(newConfig, {})->value =
+ std::move(newStyle);
}
}
}
diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp
index 29bcc93518cf..9b3a87c4eed0 100644
--- a/tools/aapt2/link/AutoVersioner_test.cpp
+++ b/tools/aapt2/link/AutoVersioner_test.cpp
@@ -15,9 +15,7 @@
*/
#include "ConfigDescription.h"
-
#include "link/Linkers.h"
-
#include "test/Builders.h"
#include "test/Context.h"
@@ -31,9 +29,9 @@ TEST(AutoVersionerTest, GenerateVersionedResources) {
const ConfigDescription sw600dpLandConfig = test::parseConfigOrDie("sw600dp-land");
ResourceEntry entry(u"foo");
- entry.values.push_back(ResourceConfigValue{ defaultConfig });
- entry.values.push_back(ResourceConfigValue{ landConfig });
- entry.values.push_back(ResourceConfigValue{ sw600dpLandConfig });
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(landConfig, ""));
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dpLandConfig, ""));
EXPECT_TRUE(shouldGenerateVersionedResource(&entry, defaultConfig, 17));
EXPECT_TRUE(shouldGenerateVersionedResource(&entry, landConfig, 17));
@@ -45,9 +43,9 @@ TEST(AutoVersionerTest, GenerateVersionedResourceWhenHigherVersionExists) {
const ConfigDescription v21Config = test::parseConfigOrDie("v21");
ResourceEntry entry(u"foo");
- entry.values.push_back(ResourceConfigValue{ defaultConfig });
- entry.values.push_back(ResourceConfigValue{ sw600dpV13Config });
- entry.values.push_back(ResourceConfigValue{ v21Config });
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dpV13Config, ""));
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(v21Config, ""));
EXPECT_TRUE(shouldGenerateVersionedResource(&entry, defaultConfig, 17));
EXPECT_FALSE(shouldGenerateVersionedResource(&entry, defaultConfig, 22));
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index fd76e887ab2a..d83f6def890c 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -19,6 +19,7 @@
#include "Flags.h"
#include "Locale.h"
#include "NameMangler.h"
+#include "ResourceUtils.h"
#include "compile/IdAssigner.h"
#include "filter/ConfigFilter.h"
#include "flatten/Archive.h"
@@ -30,17 +31,21 @@
#include "java/ManifestClassGenerator.h"
#include "java/ProguardRules.h"
#include "link/Linkers.h"
+#include "link/ProductFilter.h"
#include "link/ReferenceLinker.h"
#include "link/ManifestFixer.h"
#include "link/TableMerger.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
+#include "proto/ProtoSerialize.h"
+#include "split/TableSplitter.h"
#include "unflatten/BinaryResourceParser.h"
-#include "unflatten/FileExportHeaderReader.h"
#include "util/Files.h"
#include "util/StringPiece.h"
#include "xml/XmlDom.h"
+#include <google/protobuf/io/coded_stream.h>
+
#include <fstream>
#include <sys/stat.h>
#include <vector>
@@ -59,14 +64,14 @@ struct LinkOptions {
bool noAutoVersion = false;
bool staticLib = false;
bool generateNonFinalIds = false;
- bool verbose = false;
bool outputToDirectory = false;
bool autoAddOverlay = false;
bool doNotCompressAnything = false;
std::vector<std::string> extensionsToNotCompress;
Maybe<std::u16string> privateSymbols;
ManifestFixerOptions manifestFixerOptions;
- IConfigFilter* configFilter = nullptr;
+ std::unordered_set<std::string> products;
+ TableSplitterOptions tableSplitterOptions;
};
struct LinkContext : public IAaptContext {
@@ -75,6 +80,7 @@ struct LinkContext : public IAaptContext {
std::u16string mCompilationPackage;
uint8_t mPackageId;
std::unique_ptr<ISymbolTable> mSymbols;
+ bool mVerbose = false;
IDiagnostics* getDiagnostics() override {
return &mDiagnostics;
@@ -95,8 +101,376 @@ struct LinkContext : public IAaptContext {
ISymbolTable* getExternalSymbols() override {
return mSymbols.get();
}
+
+ bool verbose() override {
+ return mVerbose;
+ }
};
+static bool copyFileToArchive(io::IFile* file, const std::string& outPath,
+ uint32_t compressionFlags,
+ IArchiveWriter* writer, IAaptContext* context) {
+ std::unique_ptr<io::IData> data = file->openAsData();
+ if (!data) {
+ context->getDiagnostics()->error(DiagMessage(file->getSource())
+ << "failed to open file");
+ return false;
+ }
+
+ CompiledFileInputStream inputStream(data->data(), data->size());
+ if (!inputStream.CompiledFile()) {
+ context->getDiagnostics()->error(DiagMessage(file->getSource())
+ << "invalid compiled file header");
+ return false;
+ }
+
+ if (context->verbose()) {
+ context->getDiagnostics()->note(DiagMessage() << "writing " << outPath << " to archive");
+ }
+
+ if (writer->startEntry(outPath, compressionFlags)) {
+ if (writer->writeEntry(reinterpret_cast<const uint8_t*>(inputStream.data()),
+ inputStream.size())) {
+ if (writer->finishEntry()) {
+ return true;
+ }
+ }
+ }
+
+ context->getDiagnostics()->error(DiagMessage() << "failed to write file " << outPath);
+ return false;
+}
+
+static bool flattenXml(xml::XmlResource* xmlRes, const StringPiece& path, Maybe<size_t> maxSdkLevel,
+ bool keepRawValues, IArchiveWriter* writer, IAaptContext* context) {
+ BigBuffer buffer(1024);
+ XmlFlattenerOptions options = {};
+ options.keepRawValues = keepRawValues;
+ options.maxSdkLevel = maxSdkLevel;
+ XmlFlattener flattener(&buffer, options);
+ if (!flattener.consume(context, xmlRes)) {
+ return false;
+ }
+
+ if (context->verbose()) {
+ DiagMessage msg;
+ msg << "writing " << path << " to archive";
+ if (maxSdkLevel) {
+ msg << " maxSdkLevel=" << maxSdkLevel.value();
+ }
+ context->getDiagnostics()->note(msg);
+ }
+
+ if (writer->startEntry(path, ArchiveEntry::kCompress)) {
+ if (writer->writeEntry(buffer)) {
+ if (writer->finishEntry()) {
+ return true;
+ }
+ }
+ }
+ context->getDiagnostics()->error(DiagMessage() << "failed to write " << path << " to archive");
+ return false;
+}
+
+/*static std::unique_ptr<ResourceTable> loadTable(const Source& source, const void* data, size_t len,
+ IDiagnostics* diag) {
+ std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+ BinaryResourceParser parser(diag, table.get(), source, data, len);
+ if (!parser.parse()) {
+ return {};
+ }
+ return table;
+}*/
+
+static std::unique_ptr<ResourceTable> loadTableFromPb(const Source& source,
+ const void* data, size_t len,
+ IDiagnostics* diag) {
+ pb::ResourceTable pbTable;
+ if (!pbTable.ParseFromArray(data, len)) {
+ diag->error(DiagMessage(source) << "invalid compiled table");
+ return {};
+ }
+
+ std::unique_ptr<ResourceTable> table = deserializeTableFromPb(pbTable, source, diag);
+ if (!table) {
+ return {};
+ }
+ return table;
+}
+
+/**
+ * Inflates an XML file from the source path.
+ */
+static std::unique_ptr<xml::XmlResource> loadXml(const std::string& path, IDiagnostics* diag) {
+ std::ifstream fin(path, std::ifstream::binary);
+ if (!fin) {
+ diag->error(DiagMessage(path) << strerror(errno));
+ return {};
+ }
+ return xml::inflate(&fin, diag, Source(path));
+}
+
+static std::unique_ptr<xml::XmlResource> loadBinaryXmlSkipFileExport(const Source& source,
+ const void* data, size_t len,
+ IDiagnostics* diag) {
+ CompiledFileInputStream inputStream(data, len);
+ if (!inputStream.CompiledFile()) {
+ diag->error(DiagMessage(source) << "invalid compiled file header");
+ return {};
+ }
+
+ const uint8_t* xmlData = reinterpret_cast<const uint8_t*>(inputStream.data());
+ const size_t xmlDataLen = inputStream.size();
+
+ std::unique_ptr<xml::XmlResource> xmlRes = xml::inflate(xmlData, xmlDataLen, diag, source);
+ if (!xmlRes) {
+ return {};
+ }
+ return xmlRes;
+}
+
+static std::unique_ptr<ResourceFile> loadFileExportHeader(const Source& source,
+ const void* data, size_t len,
+ IDiagnostics* diag) {
+ CompiledFileInputStream inputStream(data, len);
+ const pb::CompiledFile* pbFile = inputStream.CompiledFile();
+ if (!pbFile) {
+ diag->error(DiagMessage(source) << "invalid compiled file header");
+ return {};
+ }
+
+ std::unique_ptr<ResourceFile> resFile = deserializeCompiledFileFromPb(*pbFile, source, diag);
+ if (!resFile) {
+ return {};
+ }
+ return resFile;
+}
+
+struct ResourceFileFlattenerOptions {
+ bool noAutoVersion = false;
+ bool keepRawValues = false;
+ bool doNotCompressAnything = false;
+ std::vector<std::string> extensionsToNotCompress;
+};
+
+class ResourceFileFlattener {
+public:
+ ResourceFileFlattener(const ResourceFileFlattenerOptions& options,
+ IAaptContext* context, proguard::KeepSet* keepSet) :
+ mOptions(options), mContext(context), mKeepSet(keepSet) {
+ }
+
+ bool flatten(ResourceTable* table, IArchiveWriter* archiveWriter);
+
+private:
+ struct FileOperation {
+ io::IFile* fileToCopy;
+ std::unique_ptr<xml::XmlResource> xmlToFlatten;
+ std::string dstPath;
+ };
+
+ uint32_t getCompressionFlags(const StringPiece& str);
+
+ std::unique_ptr<xml::XmlResource> linkAndVersionXmlFile(const ResourceEntry* entry,
+ const ResourceFile& fileDesc,
+ io::IFile* file,
+ ResourceTable* table);
+
+ ResourceFileFlattenerOptions mOptions;
+ IAaptContext* mContext;
+ proguard::KeepSet* mKeepSet;
+};
+
+uint32_t ResourceFileFlattener::getCompressionFlags(const StringPiece& str) {
+ if (mOptions.doNotCompressAnything) {
+ return 0;
+ }
+
+ for (const std::string& extension : mOptions.extensionsToNotCompress) {
+ if (util::stringEndsWith<char>(str, extension)) {
+ return 0;
+ }
+ }
+ return ArchiveEntry::kCompress;
+}
+
+std::unique_ptr<xml::XmlResource> ResourceFileFlattener::linkAndVersionXmlFile(
+ const ResourceEntry* entry,
+ const ResourceFile& fileDesc,
+ io::IFile* file,
+ ResourceTable* table) {
+ const StringPiece srcPath = file->getSource().path;
+ if (mContext->verbose()) {
+ mContext->getDiagnostics()->note(DiagMessage() << "linking " << srcPath);
+ }
+
+ std::unique_ptr<io::IData> data = file->openAsData();
+ if (!data) {
+ mContext->getDiagnostics()->error(DiagMessage(file->getSource()) << "failed to open file");
+ return {};
+ }
+
+ std::unique_ptr<xml::XmlResource> xmlRes;
+ if (util::stringEndsWith<char>(srcPath, ".flat")) {
+ xmlRes = loadBinaryXmlSkipFileExport(file->getSource(), data->data(), data->size(),
+ mContext->getDiagnostics());
+ } else {
+ xmlRes = xml::inflate(data->data(), data->size(), mContext->getDiagnostics(),
+ file->getSource());
+ }
+
+ if (!xmlRes) {
+ return {};
+ }
+
+ // Copy the the file description header.
+ xmlRes->file = fileDesc;
+
+ XmlReferenceLinker xmlLinker;
+ if (!xmlLinker.consume(mContext, xmlRes.get())) {
+ return {};
+ }
+
+ if (!proguard::collectProguardRules(xmlRes->file.source, xmlRes.get(), mKeepSet)) {
+ return {};
+ }
+
+ if (!mOptions.noAutoVersion) {
+ // Find the first SDK level used that is higher than this defined config and
+ // not superseded by a lower or equal SDK level resource.
+ for (int sdkLevel : xmlLinker.getSdkLevels()) {
+ if (sdkLevel > xmlRes->file.config.sdkVersion) {
+ if (!shouldGenerateVersionedResource(entry, xmlRes->file.config, sdkLevel)) {
+ // If we shouldn't generate a versioned resource, stop checking.
+ break;
+ }
+
+ ResourceFile versionedFileDesc = xmlRes->file;
+ versionedFileDesc.config.sdkVersion = sdkLevel;
+
+ if (mContext->verbose()) {
+ mContext->getDiagnostics()->note(DiagMessage(versionedFileDesc.source)
+ << "auto-versioning resource from config '"
+ << xmlRes->file.config << "' -> '"
+ << versionedFileDesc.config << "'");
+ }
+
+ std::u16string genPath = util::utf8ToUtf16(ResourceUtils::buildResourceFileName(
+ versionedFileDesc, mContext->getNameMangler()));
+
+ bool added = table->addFileReferenceAllowMangled(versionedFileDesc.name,
+ versionedFileDesc.config,
+ versionedFileDesc.source,
+ genPath,
+ file,
+ mContext->getDiagnostics());
+ if (!added) {
+ return {};
+ }
+ break;
+ }
+ }
+ }
+ return xmlRes;
+}
+
+/**
+ * Do not insert or remove any resources while executing in this function. It will
+ * corrupt the iteration order.
+ */
+bool ResourceFileFlattener::flatten(ResourceTable* table, IArchiveWriter* archiveWriter) {
+ bool error = false;
+ std::map<std::pair<ConfigDescription, StringPiece16>, FileOperation> configSortedFiles;
+
+ for (auto& pkg : table->packages) {
+ for (auto& type : pkg->types) {
+ // Sort by config and name, so that we get better locality in the zip file.
+ configSortedFiles.clear();
+ for (auto& entry : type->entries) {
+ // Iterate via indices because auto generated values can be inserted ahead of
+ // the value being processed.
+ for (size_t i = 0; i < entry->values.size(); i++) {
+ ResourceConfigValue* configValue = entry->values[i].get();
+
+ FileReference* fileRef = valueCast<FileReference>(configValue->value.get());
+ if (!fileRef) {
+ continue;
+ }
+
+ io::IFile* file = fileRef->file;
+ if (!file) {
+ mContext->getDiagnostics()->error(DiagMessage(fileRef->getSource())
+ << "file not found");
+ return false;
+ }
+
+ FileOperation fileOp;
+ fileOp.dstPath = util::utf16ToUtf8(*fileRef->path);
+
+ const StringPiece srcPath = file->getSource().path;
+ if (type->type != ResourceType::kRaw &&
+ (util::stringEndsWith<char>(srcPath, ".xml.flat") ||
+ util::stringEndsWith<char>(srcPath, ".xml"))) {
+ ResourceFile fileDesc;
+ fileDesc.config = configValue->config;
+ fileDesc.name = ResourceName(pkg->name, type->type, entry->name);
+ fileDesc.source = fileRef->getSource();
+ fileOp.xmlToFlatten = linkAndVersionXmlFile(entry.get(), fileDesc,
+ file, table);
+ if (!fileOp.xmlToFlatten) {
+ error = true;
+ continue;
+ }
+
+ } else {
+ fileOp.fileToCopy = file;
+ }
+
+ // NOTE(adamlesinski): Explicitly construct a StringPiece16 here, or else
+ // we end up copying the string in the std::make_pair() method, then creating
+ // a StringPiece16 from the copy, which would cause us to end up referencing
+ // garbage in the map.
+ const StringPiece16 entryName(entry->name);
+ configSortedFiles[std::make_pair(configValue->config, entryName)] =
+ std::move(fileOp);
+ }
+ }
+
+ if (error) {
+ return false;
+ }
+
+ // Now flatten the sorted values.
+ for (auto& mapEntry : configSortedFiles) {
+ const ConfigDescription& config = mapEntry.first.first;
+ const FileOperation& fileOp = mapEntry.second;
+
+ if (fileOp.xmlToFlatten) {
+ Maybe<size_t> maxSdkLevel;
+ if (!mOptions.noAutoVersion) {
+ maxSdkLevel = std::max<size_t>(config.sdkVersion, 1u);
+ }
+
+ bool result = flattenXml(fileOp.xmlToFlatten.get(), fileOp.dstPath, maxSdkLevel,
+ mOptions.keepRawValues,
+ archiveWriter, mContext);
+ if (!result) {
+ error = true;
+ }
+ } else {
+ bool result = copyFileToArchive(fileOp.fileToCopy, fileOp.dstPath,
+ getCompressionFlags(fileOp.dstPath),
+ archiveWriter, mContext);
+ if (!result) {
+ error = true;
+ }
+ }
+ }
+ }
+ }
+ return !error;
+}
+
class LinkCommand {
public:
LinkCommand(LinkContext* context, const LinkOptions& options) :
@@ -118,7 +492,7 @@ public:
std::unique_ptr<ISymbolTable> createSymbolTableFromIncludePaths() {
AssetManagerSymbolTableBuilder builder;
for (const std::string& path : mOptions.includePaths) {
- if (mOptions.verbose) {
+ if (mContext->verbose()) {
mContext->getDiagnostics()->note(DiagMessage(path) << "loading include path");
}
@@ -135,106 +509,6 @@ public:
return builder.build();
}
- std::unique_ptr<ResourceTable> loadTable(const Source& source, const void* data, size_t len) {
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(mContext, table.get(), source, data, len);
- if (!parser.parse()) {
- return {};
- }
- return table;
- }
-
- /**
- * Inflates an XML file from the source path.
- */
- static std::unique_ptr<xml::XmlResource> loadXml(const std::string& path, IDiagnostics* diag) {
- std::ifstream fin(path, std::ifstream::binary);
- if (!fin) {
- diag->error(DiagMessage(path) << strerror(errno));
- return {};
- }
-
- return xml::inflate(&fin, diag, Source(path));
- }
-
- static std::unique_ptr<xml::XmlResource> loadBinaryXmlSkipFileExport(
- const Source& source,
- const void* data, size_t len,
- IDiagnostics* diag) {
- std::string errorStr;
- ssize_t offset = getWrappedDataOffset(data, len, &errorStr);
- if (offset < 0) {
- diag->error(DiagMessage(source) << errorStr);
- return {};
- }
-
- std::unique_ptr<xml::XmlResource> xmlRes = xml::inflate(
- reinterpret_cast<const uint8_t*>(data) + static_cast<size_t>(offset),
- len - static_cast<size_t>(offset),
- diag,
- source);
- if (!xmlRes) {
- return {};
- }
- return xmlRes;
- }
-
- static std::unique_ptr<ResourceFile> loadFileExportHeader(const Source& source,
- const void* data, size_t len,
- IDiagnostics* diag) {
- std::unique_ptr<ResourceFile> resFile = util::make_unique<ResourceFile>();
- std::string errorStr;
- ssize_t offset = unwrapFileExportHeader(data, len, resFile.get(), &errorStr);
- if (offset < 0) {
- diag->error(DiagMessage(source) << errorStr);
- return {};
- }
- return resFile;
- }
-
- uint32_t getCompressionFlags(const StringPiece& str) {
- if (mOptions.doNotCompressAnything) {
- return 0;
- }
-
- for (const std::string& extension : mOptions.extensionsToNotCompress) {
- if (util::stringEndsWith<char>(str, extension)) {
- return 0;
- }
- }
- return ArchiveEntry::kCompress;
- }
-
- bool copyFileToArchive(io::IFile* file, const std::string& outPath,
- IArchiveWriter* writer) {
- std::unique_ptr<io::IData> data = file->openAsData();
- if (!data) {
- mContext->getDiagnostics()->error(DiagMessage(file->getSource())
- << "failed to open file");
- return false;
- }
-
- std::string errorStr;
- ssize_t offset = getWrappedDataOffset(data->data(), data->size(), &errorStr);
- if (offset < 0) {
- mContext->getDiagnostics()->error(DiagMessage(file->getSource()) << errorStr);
- return false;
- }
-
- if (writer->startEntry(outPath, getCompressionFlags(outPath))) {
- if (writer->writeEntry(reinterpret_cast<const uint8_t*>(data->data()) + offset,
- data->size() - static_cast<size_t>(offset))) {
- if (writer->finishEntry()) {
- return true;
- }
- }
- }
-
- mContext->getDiagnostics()->error(
- DiagMessage(mOptions.outputPath) << "failed to write file " << outPath);
- return false;
- }
-
Maybe<AppInfo> extractAppInfoFromManifest(xml::XmlResource* xmlRes) {
// Make sure the first element is <manifest> with package attribute.
if (xml::Element* manifestEl = xml::findRootElement(xmlRes->root.get())) {
@@ -270,16 +544,16 @@ public:
for (const auto& configValue : entry->values) {
// Special case the occurrence of an ID that is being generated for the
// 'android' package. This is due to legacy reasons.
- if (valueCast<Id>(configValue.value.get()) &&
+ if (valueCast<Id>(configValue->value.get()) &&
package->name == u"android") {
mContext->getDiagnostics()->warn(
- DiagMessage(configValue.value->getSource())
+ DiagMessage(configValue->value->getSource())
<< "generated id '" << resName
<< "' for external package '" << package->name
<< "'");
} else {
mContext->getDiagnostics()->error(
- DiagMessage(configValue.value->getSource())
+ DiagMessage(configValue->value->getSource())
<< "defined resource '" << resName
<< "' for external package '" << package->name
<< "'");
@@ -307,9 +581,7 @@ public:
bool flattenTable(ResourceTable* table, IArchiveWriter* writer) {
BigBuffer buffer(1024);
- TableFlattenerOptions options = {};
- options.useExtendedChunks = mOptions.staticLib;
- TableFlattener flattener(&buffer, options);
+ TableFlattener flattener(&buffer);
if (!flattener.consume(mContext, table)) {
return false;
}
@@ -327,28 +599,6 @@ public:
return false;
}
- bool flattenXml(xml::XmlResource* xmlRes, const StringPiece& path, Maybe<size_t> maxSdkLevel,
- IArchiveWriter* writer) {
- BigBuffer buffer(1024);
- XmlFlattenerOptions options = {};
- options.keepRawValues = mOptions.staticLib;
- options.maxSdkLevel = maxSdkLevel;
- XmlFlattener flattener(&buffer, options);
- if (!flattener.consume(mContext, xmlRes)) {
- return false;
- }
-
- if (writer->startEntry(path, ArchiveEntry::kCompress)) {
- if (writer->writeEntry(buffer)) {
- if (writer->finishEntry()) {
- return true;
- }
- }
- }
- mContext->getDiagnostics()->error(
- DiagMessage() << "failed to write " << path << " to archive");
- return false;
- }
bool writeJavaFile(ResourceTable* table, const StringPiece16& packageNameToGenerate,
const StringPiece16& outPackage, JavaClassGeneratorOptions javaOptions) {
@@ -434,7 +684,7 @@ public:
}
bool mergeResourceTable(io::IFile* file, bool override) {
- if (mOptions.verbose) {
+ if (mContext->verbose()) {
mContext->getDiagnostics()->note(DiagMessage() << "linking " << file->getSource());
}
@@ -445,8 +695,9 @@ public:
return false;
}
- std::unique_ptr<ResourceTable> table = loadTable(file->getSource(), data->data(),
- data->size());
+ std::unique_ptr<ResourceTable> table = loadTableFromPb(file->getSource(),
+ data->data(), data->size(),
+ mContext->getDiagnostics());
if (!table) {
return false;
}
@@ -461,7 +712,7 @@ public:
}
bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool overlay) {
- if (mOptions.verbose) {
+ if (mContext->verbose()) {
mContext->getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
}
@@ -492,7 +743,10 @@ public:
std::unique_ptr<Id> id = util::make_unique<Id>();
id->setSource(fileDesc->source.withLine(exportedSymbol.line));
- bool result = mFinalTable.addResourceAllowMangled(resName, {}, std::move(id),
+ bool result = mFinalTable.addResourceAllowMangled(resName,
+ ConfigDescription::defaultConfig(),
+ std::string(),
+ std::move(id),
mContext->getDiagnostics());
if (!result) {
return false;
@@ -603,10 +857,9 @@ public:
TableMergerOptions tableMergerOptions;
tableMergerOptions.autoAddOverlay = mOptions.autoAddOverlay;
- tableMergerOptions.filter = mOptions.configFilter;
mTableMerger = util::make_unique<TableMerger>(mContext, &mFinalTable, tableMergerOptions);
- if (mOptions.verbose) {
+ if (mContext->verbose()) {
mContext->getDiagnostics()->note(
DiagMessage() << "linking package '" << mContext->mCompilationPackage << "' "
<< "with package ID " << std::hex << (int) mContext->mPackageId);
@@ -661,6 +914,21 @@ public:
mContext->getDiagnostics()->error(DiagMessage() << "failed linking references");
return 1;
}
+
+ ProductFilter productFilter(mOptions.products);
+ if (!productFilter.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
+ return 1;
+ }
+
+ // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
+ // level.
+ TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
+ if (!tableSplitter.verifySplitConstraints(mContext)) {
+ return 1;
+ }
+
+ tableSplitter.splitTable(&mFinalTable);
}
proguard::KeepSet proguardKeepSet;
@@ -697,8 +965,10 @@ public:
}
}
- if (!flattenXml(manifestXml.get(), "AndroidManifest.xml", {},
- archiveWriter.get())) {
+ const bool keepRawValues = mOptions.staticLib;
+ bool result = flattenXml(manifestXml.get(), "AndroidManifest.xml", {},
+ keepRawValues, archiveWriter.get(), mContext);
+ if (!result) {
error = true;
}
} else {
@@ -711,113 +981,14 @@ public:
return 1;
}
- for (auto& mergeEntry : mTableMerger->getFilesToMerge()) {
- const ResourceKeyRef& key = mergeEntry.first;
- const FileToMerge& fileToMerge = mergeEntry.second;
-
- const StringPiece path = fileToMerge.file->getSource().path;
-
- if (key.name.type != ResourceType::kRaw &&
- (util::stringEndsWith<char>(path, ".xml.flat") ||
- util::stringEndsWith<char>(path, ".xml"))) {
- if (mOptions.verbose) {
- mContext->getDiagnostics()->note(DiagMessage() << "linking " << path);
- }
-
- io::IFile* file = fileToMerge.file;
- std::unique_ptr<io::IData> data = file->openAsData();
- if (!data) {
- mContext->getDiagnostics()->error(DiagMessage(file->getSource())
- << "failed to open file");
- return 1;
- }
-
- std::unique_ptr<xml::XmlResource> xmlRes;
- if (util::stringEndsWith<char>(path, ".flat")) {
- xmlRes = loadBinaryXmlSkipFileExport(file->getSource(),
- data->data(), data->size(),
- mContext->getDiagnostics());
- } else {
- xmlRes = xml::inflate(data->data(), data->size(), mContext->getDiagnostics(),
- file->getSource());
- }
-
- if (!xmlRes) {
- return 1;
- }
-
- // Create the file description header.
- xmlRes->file = ResourceFile{
- key.name.toResourceName(),
- key.config,
- fileToMerge.originalSource,
- };
-
- XmlReferenceLinker xmlLinker;
- if (xmlLinker.consume(mContext, xmlRes.get())) {
- if (!proguard::collectProguardRules(xmlRes->file.source, xmlRes.get(),
- &proguardKeepSet)) {
- error = true;
- }
-
- Maybe<size_t> maxSdkLevel;
- if (!mOptions.noAutoVersion) {
- maxSdkLevel = std::max<size_t>(xmlRes->file.config.sdkVersion, 1u);
- }
-
- if (!flattenXml(xmlRes.get(), fileToMerge.dstPath, maxSdkLevel,
- archiveWriter.get())) {
- error = true;
- }
-
- if (!mOptions.noAutoVersion) {
- Maybe<ResourceTable::SearchResult> result = mFinalTable.findResource(
- xmlRes->file.name);
- for (int sdkLevel : xmlLinker.getSdkLevels()) {
- if (sdkLevel > xmlRes->file.config.sdkVersion &&
- shouldGenerateVersionedResource(result.value().entry,
- xmlRes->file.config,
- sdkLevel)) {
- xmlRes->file.config.sdkVersion = sdkLevel;
-
- std::string genResourcePath = ResourceUtils::buildResourceFileName(
- xmlRes->file, mContext->getNameMangler());
-
- bool added = mFinalTable.addFileReference(
- xmlRes->file.name,
- xmlRes->file.config,
- xmlRes->file.source,
- util::utf8ToUtf16(genResourcePath),
- mContext->getDiagnostics());
- if (!added) {
- error = true;
- continue;
- }
-
- if (!flattenXml(xmlRes.get(), genResourcePath, sdkLevel,
- archiveWriter.get())) {
- error = true;
- }
- }
- }
- }
-
- } else {
- error = true;
- }
- } else {
- if (mOptions.verbose) {
- mContext->getDiagnostics()->note(DiagMessage() << "copying " << path);
- }
-
- if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath,
- archiveWriter.get())) {
- error = true;
- }
- }
- }
+ ResourceFileFlattenerOptions fileFlattenerOptions;
+ fileFlattenerOptions.keepRawValues = mOptions.staticLib;
+ fileFlattenerOptions.doNotCompressAnything = mOptions.doNotCompressAnything;
+ fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress;
+ fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion;
+ ResourceFileFlattener fileFlattener(fileFlattenerOptions, mContext, &proguardKeepSet);
- if (error) {
+ if (!fileFlattener.flatten(&mFinalTable, archiveWriter.get())) {
mContext->getDiagnostics()->error(DiagMessage() << "failed linking file resources");
return 1;
}
@@ -881,8 +1052,10 @@ public:
}
}
- if (mOptions.verbose) {
- Debug::printTable(&mFinalTable);
+ if (mContext->verbose()) {
+ DebugPrintTableOptions debugPrintTableOptions;
+ debugPrintTableOptions.showSources = true;
+ Debug::printTable(&mFinalTable, debugPrintTableOptions);
}
return 0;
}
@@ -903,6 +1076,7 @@ private:
};
int link(const std::vector<StringPiece>& args) {
+ LinkContext context;
LinkOptions options;
Maybe<std::string> privateSymbolsPackage;
Maybe<std::string> minSdkVersion, targetSdkVersion;
@@ -911,6 +1085,8 @@ int link(const std::vector<StringPiece>& args) {
Maybe<std::string> customJavaPackage;
std::vector<std::string> extraJavaPackages;
Maybe<std::string> configs;
+ Maybe<std::string> preferredDensity;
+ Maybe<std::string> productList;
bool legacyXFlag = false;
bool requireLocalization = false;
Flags flags = Flags()
@@ -934,6 +1110,11 @@ int link(const std::vector<StringPiece>& args) {
&requireLocalization)
.optionalFlag("-c", "Comma separated list of configurations to include. The default\n"
"is all configurations", &configs)
+ .optionalFlag("--preferred-density",
+ "Selects the closest matching density and strips out all others.",
+ &preferredDensity)
+ .optionalFlag("--product", "Comma separated list of product names to keep",
+ &productList)
.optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified "
"by -o",
&options.outputToDirectory)
@@ -967,14 +1148,12 @@ int link(const std::vector<StringPiece>& args) {
&renameInstrumentationTargetPackage)
.optionalFlagList("-0", "File extensions not to compress",
&options.extensionsToNotCompress)
- .optionalSwitch("-v", "Enables verbose logging", &options.verbose);
+ .optionalSwitch("-v", "Enables verbose logging", &context.mVerbose);
if (!flags.parse("aapt2 link", args, &std::cerr)) {
return 1;
}
- LinkContext context;
-
if (privateSymbolsPackage) {
options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
}
@@ -1019,6 +1198,14 @@ int link(const std::vector<StringPiece>& args) {
}
}
+ if (productList) {
+ for (StringPiece product : util::tokenize<char>(productList.value(), ',')) {
+ if (product != "" && product != "default") {
+ options.products.insert(product.toString());
+ }
+ }
+ }
+
AxisConfigFilter filter;
if (configs) {
for (const StringPiece& configStr : util::tokenize<char>(configs.value(), ',')) {
@@ -1040,7 +1227,29 @@ int link(const std::vector<StringPiece>& args) {
}
}
- options.configFilter = &filter;
+ options.tableSplitterOptions.configFilter = &filter;
+ }
+
+ if (preferredDensity) {
+ ConfigDescription preferredDensityConfig;
+ if (!ConfigDescription::parse(preferredDensity.value(), &preferredDensityConfig)) {
+ context.getDiagnostics()->error(DiagMessage() << "invalid density '"
+ << preferredDensity.value()
+ << "' for --preferred-density option");
+ return 1;
+ }
+
+ // Clear the version that can be automatically added.
+ preferredDensityConfig.sdkVersion = 0;
+
+ if (preferredDensityConfig.diff(ConfigDescription::defaultConfig())
+ != ConfigDescription::CONFIG_DENSITY) {
+ context.getDiagnostics()->error(DiagMessage() << "invalid preferred density '"
+ << preferredDensity.value() << "'. "
+ << "Preferred density must only be a density value");
+ return 1;
+ }
+ options.tableSplitterOptions.preferredDensity = preferredDensityConfig.density;
}
LinkCommand cmd(&context, options);
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 4d3a483c6b82..ec532aba465f 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -26,7 +26,7 @@
namespace aapt {
class ResourceTable;
-struct ResourceEntry;
+class ResourceEntry;
struct ConfigDescription;
/**
diff --git a/tools/aapt2/link/ProductFilter.cpp b/tools/aapt2/link/ProductFilter.cpp
new file mode 100644
index 000000000000..8784e891b293
--- /dev/null
+++ b/tools/aapt2/link/ProductFilter.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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 "link/ProductFilter.h"
+
+namespace aapt {
+
+ProductFilter::ResourceConfigValueIter
+ProductFilter::selectProductToKeep(const ResourceNameRef& name,
+ const ResourceConfigValueIter begin,
+ const ResourceConfigValueIter end,
+ IDiagnostics* diag) {
+ ResourceConfigValueIter defaultProductIter = end;
+ ResourceConfigValueIter selectedProductIter = end;
+
+ for (ResourceConfigValueIter iter = begin; iter != end; ++iter) {
+ ResourceConfigValue* configValue = iter->get();
+ if (mProducts.find(configValue->product) != mProducts.end()) {
+ if (selectedProductIter != end) {
+ // We have two possible values for this product!
+ diag->error(DiagMessage(configValue->value->getSource())
+ << "selection of product '" << configValue->product
+ << "' for resource " << name << " is ambiguous");
+
+ ResourceConfigValue* previouslySelectedConfigValue = selectedProductIter->get();
+ diag->note(DiagMessage(previouslySelectedConfigValue->value->getSource())
+ << "product '" << previouslySelectedConfigValue->product
+ << "' is also a candidate");
+ return end;
+ }
+
+ // Select this product.
+ selectedProductIter = iter;
+ }
+
+ if (configValue->product.empty() || configValue->product == "default") {
+ if (defaultProductIter != end) {
+ // We have two possible default values.
+ diag->error(DiagMessage(configValue->value->getSource())
+ << "multiple default products defined for resource " << name);
+
+ ResourceConfigValue* previouslyDefaultConfigValue = defaultProductIter->get();
+ diag->note(DiagMessage(previouslyDefaultConfigValue->value->getSource())
+ << "default product also defined here");
+ return end;
+ }
+
+ // Mark the default.
+ defaultProductIter = iter;
+ }
+ }
+
+ if (defaultProductIter == end) {
+ diag->error(DiagMessage() << "no default product defined for resource " << name);
+ return end;
+ }
+
+ if (selectedProductIter == end) {
+ selectedProductIter = defaultProductIter;
+ }
+ return selectedProductIter;
+}
+
+bool ProductFilter::consume(IAaptContext* context, ResourceTable* table) {
+ bool error = false;
+ for (auto& pkg : table->packages) {
+ for (auto& type : pkg->types) {
+ for (auto& entry : type->entries) {
+ std::vector<std::unique_ptr<ResourceConfigValue>> newValues;
+
+ ResourceConfigValueIter iter = entry->values.begin();
+ ResourceConfigValueIter startRangeIter = iter;
+ while (iter != entry->values.end()) {
+ ++iter;
+ if (iter == entry->values.end() ||
+ (*iter)->config != (*startRangeIter)->config) {
+
+ // End of the array, or we saw a different config,
+ // so this must be the end of a range of products.
+ // Select the product to keep from the set of products defined.
+ ResourceNameRef name(pkg->name, type->type, entry->name);
+ auto valueToKeep = selectProductToKeep(name, startRangeIter, iter,
+ context->getDiagnostics());
+ if (valueToKeep == iter) {
+ // An error occurred, we could not pick a product.
+ error = true;
+ } else {
+ // We selected a product to keep. Move it to the new array.
+ newValues.push_back(std::move(*valueToKeep));
+ }
+
+ // Start the next range of products.
+ startRangeIter = iter;
+ }
+ }
+
+ // Now move the new values in to place.
+ entry->values = std::move(newValues);
+ }
+ }
+ }
+ return !error;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/link/ProductFilter.h b/tools/aapt2/link/ProductFilter.h
new file mode 100644
index 000000000000..d2edd38289dc
--- /dev/null
+++ b/tools/aapt2/link/ProductFilter.h
@@ -0,0 +1,49 @@
+/*
+ * 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_LINK_PRODUCTFILTER_H
+#define AAPT_LINK_PRODUCTFILTER_H
+
+#include "ResourceTable.h"
+#include "process/IResourceTableConsumer.h"
+
+#include <android-base/macros.h>
+#include <unordered_set>
+
+namespace aapt {
+
+class ProductFilter {
+public:
+ using ResourceConfigValueIter = std::vector<std::unique_ptr<ResourceConfigValue>>::iterator;
+
+ ProductFilter(std::unordered_set<std::string> products) : mProducts(products) { }
+
+ ResourceConfigValueIter selectProductToKeep(const ResourceNameRef& name,
+ const ResourceConfigValueIter begin,
+ const ResourceConfigValueIter end,
+ IDiagnostics* diag);
+
+ bool consume(IAaptContext* context, ResourceTable* table);
+
+private:
+ std::unordered_set<std::string> mProducts;
+
+ DISALLOW_COPY_AND_ASSIGN(ProductFilter);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_LINK_PRODUCTFILTER_H */
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
new file mode 100644
index 000000000000..f4f756ae4519
--- /dev/null
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "link/ProductFilter.h"
+#include "test/Builders.h"
+#include "test/Context.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(ProductFilterTest, SelectTwoProducts) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+
+ const ConfigDescription land = test::parseConfigOrDie("land");
+ const ConfigDescription port = test::parseConfigOrDie("port");
+
+ ResourceTable table;
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ land, "",
+ test::ValueBuilder<Id>()
+ .setSource(Source("land/default.xml")).build(),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ land, "tablet",
+ test::ValueBuilder<Id>()
+ .setSource(Source("land/tablet.xml")).build(),
+ context->getDiagnostics()));
+
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ port, "",
+ test::ValueBuilder<Id>()
+ .setSource(Source("port/default.xml")).build(),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ port, "tablet",
+ test::ValueBuilder<Id>()
+ .setSource(Source("port/tablet.xml")).build(),
+ context->getDiagnostics()));
+
+ ProductFilter filter({ "tablet" });
+ ASSERT_TRUE(filter.consume(context.get(), &table));
+
+ EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ land, ""));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ land, "tablet"));
+ EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ port, ""));
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ port, "tablet"));
+}
+
+TEST(ProductFilterTest, SelectDefaultProduct) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+
+ ResourceTable table;
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "",
+ test::ValueBuilder<Id>()
+ .setSource(Source("default.xml")).build(),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "tablet",
+ test::ValueBuilder<Id>()
+ .setSource(Source("tablet.xml")).build(),
+ context->getDiagnostics()));
+
+ ProductFilter filter({});
+ ASSERT_TRUE(filter.consume(context.get(), &table));
+
+ EXPECT_NE(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ ConfigDescription::defaultConfig(),
+ ""));
+ EXPECT_EQ(nullptr, test::getValueForConfigAndProduct<Id>(&table, u"@android:string/one",
+ ConfigDescription::defaultConfig(),
+ "tablet"));
+}
+
+TEST(ProductFilterTest, FailOnAmbiguousProduct) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+
+ ResourceTable table;
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "",
+ test::ValueBuilder<Id>()
+ .setSource(Source("default.xml")).build(),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "tablet",
+ test::ValueBuilder<Id>()
+ .setSource(Source("tablet.xml")).build(),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "no-sdcard",
+ test::ValueBuilder<Id>()
+ .setSource(Source("no-sdcard.xml")).build(),
+ context->getDiagnostics()));
+
+ ProductFilter filter({ "tablet", "no-sdcard" });
+ ASSERT_FALSE(filter.consume(context.get(), &table));
+}
+
+TEST(ProductFilterTest, FailOnMultipleDefaults) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+
+ ResourceTable table;
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "",
+ test::ValueBuilder<Id>()
+ .setSource(Source(".xml")).build(),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:string/one"),
+ ConfigDescription::defaultConfig(), "default",
+ test::ValueBuilder<Id>()
+ .setSource(Source("default.xml")).build(),
+ context->getDiagnostics()));
+
+ ProductFilter filter({});
+ ASSERT_FALSE(filter.consume(context.get(), &table));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 27435398c408..ef3fe4f58d41 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -316,7 +316,7 @@ bool ReferenceLinker::consume(IAaptContext* context, ResourceTable* table) {
&table->stringPool, &declStack, &callSite);
for (auto& configValue : entry->values) {
- configValue.value->accept(&visitor);
+ configValue->value->accept(&visitor);
}
if (visitor.hasError()) {
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index e01a00401133..5f1174588438 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -18,9 +18,7 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
-
#include "link/TableMerger.h"
-#include "util/Comparators.h"
#include "util/Util.h"
#include <cassert>
@@ -100,8 +98,7 @@ bool TableMerger::mergeAndMangle(const Source& src, const StringPiece16& package
return false;
}
- mFilesToMerge[ResourceKeyRef(name, config)] = FileToMerge{
- f, oldFile->getSource(), util::utf16ToUtf8(*newFile->path) };
+ newFile->file = f;
return true;
};
@@ -197,28 +194,24 @@ bool TableMerger::doMerge(const Source& src,
ResourceNameRef resName(mMasterPackage->name, dstType->type, dstEntry->name);
- for (ResourceConfigValue& srcValue : srcEntry->values) {
- auto iter = std::lower_bound(dstEntry->values.begin(), dstEntry->values.end(),
- srcValue.config, cmp::lessThanConfig);
-
- const bool stripConfig = mOptions.filter ?
- !mOptions.filter->match(srcValue.config) : false;
-
- if (iter != dstEntry->values.end() && iter->config == srcValue.config) {
+ for (auto& srcValue : srcEntry->values) {
+ ResourceConfigValue* dstValue = dstEntry->findValue(srcValue->config,
+ srcValue->product);
+ if (dstValue) {
const int collisionResult = ResourceTable::resolveValueCollision(
- iter->value.get(), srcValue.value.get());
+ dstValue->value.get(), srcValue->value.get());
if (collisionResult == 0 && !overlay) {
// Error!
ResourceNameRef resourceName(srcPackage->name,
srcType->type,
srcEntry->name);
- mContext->getDiagnostics()->error(DiagMessage(srcValue.value->getSource())
+ mContext->getDiagnostics()->error(DiagMessage(srcValue->value->getSource())
<< "resource '" << resourceName
<< "' has a conflicting value for "
<< "configuration ("
- << srcValue.config << ")");
- mContext->getDiagnostics()->note(DiagMessage(iter->value->getSource())
+ << srcValue->config << ")");
+ mContext->getDiagnostics()->note(DiagMessage(dstValue->value->getSource())
<< "originally defined here");
error = true;
continue;
@@ -227,16 +220,14 @@ bool TableMerger::doMerge(const Source& src,
continue;
}
- } else if (!stripConfig){
- // Insert a place holder value. We will fill it in below.
- iter = dstEntry->values.insert(iter, ResourceConfigValue{ srcValue.config });
}
- if (stripConfig) {
- continue;
+ if (!dstValue) {
+ // Force create the entry if we didn't have it.
+ dstValue = dstEntry->findOrCreateValue(srcValue->config, srcValue->product);
}
- if (FileReference* f = valueCast<FileReference>(srcValue.value.get())) {
+ if (FileReference* f = valueCast<FileReference>(srcValue->value.get())) {
std::unique_ptr<FileReference> newFileRef;
if (manglePackage) {
newFileRef = cloneAndMangleFile(srcPackage->name, *f);
@@ -246,15 +237,15 @@ bool TableMerger::doMerge(const Source& src,
}
if (callback) {
- if (!callback(resName, iter->config, newFileRef.get(), f)) {
+ if (!callback(resName, srcValue->config, newFileRef.get(), f)) {
error = true;
continue;
}
}
- iter->value = std::move(newFileRef);
+ dstValue->value = std::move(newFileRef);
} else {
- iter->value = std::unique_ptr<Value>(srcValue.value->clone(
+ dstValue->value = std::unique_ptr<Value>(srcValue->value->clone(
&mMasterTable->stringPool));
}
}
@@ -286,21 +277,16 @@ bool TableMerger::mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, b
std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
table.stringPool.makeRef(path));
fileRef->setSource(fileDesc.source);
+ fileRef->file = file;
ResourceTablePackage* pkg = table.createPackage(fileDesc.name.package, 0x0);
pkg->findOrCreateType(fileDesc.name.type)
->findOrCreateEntry(fileDesc.name.entry)
- ->values.push_back(ResourceConfigValue{ fileDesc.config, std::move(fileRef) });
-
- auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
- FileReference* newFile, FileReference* oldFile) -> bool {
- mFilesToMerge[ResourceKeyRef(name, config)] = FileToMerge{
- file, oldFile->getSource(), util::utf16ToUtf8(*newFile->path) };
- return true;
- };
+ ->findOrCreateValue(fileDesc.config, {})
+ ->value = std::move(fileRef);
return doMerge(file->getSource(), &table, pkg,
- false /* mangle */, overlay /* overlay */, true /* allow new */, callback);
+ false /* mangle */, overlay /* overlay */, true /* allow new */, {});
}
bool TableMerger::mergeFile(const ResourceFile& fileDesc, io::IFile* file) {
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 4539679fa769..b3c22dd736f4 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -30,33 +30,11 @@
namespace aapt {
-struct FileToMerge {
- /**
- * The compiled file from which to read the data.
- */
- io::IFile* file;
-
- /**
- * Where the original, uncompiled file came from.
- */
- Source originalSource;
-
- /**
- * The destination path within the APK/archive.
- */
- std::string dstPath;
-};
-
struct TableMergerOptions {
/**
* If true, resources in overlays can be added without previously having existed.
*/
bool autoAddOverlay = false;
-
- /**
- * A filter that removes resources whose configurations don't match.
- */
- IConfigFilter* filter = nullptr;
};
/**
@@ -81,10 +59,6 @@ public:
*/
TableMerger(IAaptContext* context, ResourceTable* outTable, const TableMergerOptions& options);
- const std::map<ResourceKeyRef, FileToMerge>& getFilesToMerge() {
- return mFilesToMerge;
- }
-
const std::set<std::u16string>& getMergedPackages() const {
return mMergedPackages;
}
@@ -119,8 +93,7 @@ public:
private:
using FileMergeCallback = std::function<bool(const ResourceNameRef&,
const ConfigDescription& config,
- FileReference*,
- FileReference*)>;
+ FileReference*, FileReference*)>;
IAaptContext* mContext;
ResourceTable* mMasterTable;
@@ -128,7 +101,6 @@ private:
ResourceTablePackage* mMasterPackage;
std::set<std::u16string> mMergedPackages;
- std::map<ResourceKeyRef, FileToMerge> mFilesToMerge;
bool mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay);
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 45c8c98780b8..4a80d3f48777 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -97,16 +97,6 @@ TEST_F(TableMergerTest, MergeFile) {
test::parseConfigOrDie("hdpi-v4"));
ASSERT_NE(nullptr, file);
EXPECT_EQ(std::u16string(u"res/layout-hdpi-v4/main.xml"), *file->path);
-
- ResourceName name = test::parseNameOrDie(u"@com.app.a:layout/main");
- ResourceKeyRef key = { name, test::parseConfigOrDie("hdpi-v4") };
-
- auto iter = merger.getFilesToMerge().find(key);
- ASSERT_NE(merger.getFilesToMerge().end(), iter);
-
- const FileToMerge& actualFileToMerge = iter->second;
- EXPECT_EQ(&testFile, actualFileToMerge.file);
- EXPECT_EQ(std::string("res/layout-hdpi-v4/main.xml"), actualFileToMerge.dstPath);
}
TEST_F(TableMergerTest, MergeFileOverlay) {
@@ -122,14 +112,6 @@ TEST_F(TableMergerTest, MergeFileOverlay) {
ASSERT_TRUE(merger.mergeFile(fileDesc, &fileA));
ASSERT_TRUE(merger.mergeFileOverlay(fileDesc, &fileB));
-
- ResourceName name = test::parseNameOrDie(u"@com.app.a:xml/foo");
- ResourceKeyRef key = { name, ConfigDescription{} };
- auto iter = merger.getFilesToMerge().find(key);
- ASSERT_NE(merger.getFilesToMerge().end(), iter);
-
- const FileToMerge& actualFileToMerge = iter->second;
- EXPECT_EQ(&fileB, actualFileToMerge.file);
}
TEST_F(TableMergerTest, MergeFileReferences) {
@@ -157,15 +139,6 @@ TEST_F(TableMergerTest, MergeFileReferences) {
f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/com.app.b$file");
ASSERT_NE(f, nullptr);
EXPECT_EQ(std::u16string(u"res/xml/com.app.b$file.xml"), *f->path);
-
- ResourceName name = test::parseNameOrDie(u"@com.app.a:xml/com.app.b$file");
- ResourceKeyRef key = { name, ConfigDescription{} };
- auto iter = merger.getFilesToMerge().find(key);
- ASSERT_NE(merger.getFilesToMerge().end(), iter);
-
- const FileToMerge& actualFileToMerge = iter->second;
- EXPECT_EQ(Source("res/xml/file.xml"), actualFileToMerge.file->getSource());
- EXPECT_EQ(std::string("res/xml/com.app.b$file.xml"), actualFileToMerge.dstPath);
}
TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
@@ -244,36 +217,4 @@ TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
ASSERT_FALSE(merger.mergeOverlay({}, tableB.get()));
}
-TEST_F(TableMergerTest, MergeAndStripResourcesNotMatchingFilter) {
- ResourceTable finalTable;
- TableMergerOptions options;
- options.autoAddOverlay = false;
-
- AxisConfigFilter filter;
- filter.addConfig(test::parseConfigOrDie("en"));
- options.filter = &filter;
-
- test::TestFile fileA("res/layout-en/main.xml"), fileB("res/layout-fr-rFR/main.xml");
- const ResourceName name = test::parseNameOrDie(u"@com.app.a:layout/main");
- const ConfigDescription configEn = test::parseConfigOrDie("en");
- const ConfigDescription configFr = test::parseConfigOrDie("fr-rFR");
-
- TableMerger merger(mContext.get(), &finalTable, options);
- ASSERT_TRUE(merger.mergeFile(ResourceFile{ name, configEn }, &fileA));
- ASSERT_TRUE(merger.mergeFile(ResourceFile{ name, configFr }, &fileB));
-
- EXPECT_NE(nullptr, test::getValueForConfig<FileReference>(&finalTable,
- u"@com.app.a:layout/main",
- configEn));
- EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(&finalTable,
- u"@com.app.a:layout/main",
- configFr));
-
- EXPECT_NE(merger.getFilesToMerge().end(),
- merger.getFilesToMerge().find(ResourceKeyRef(name, configEn)));
-
- EXPECT_EQ(merger.getFilesToMerge().end(),
- merger.getFilesToMerge().find(ResourceKeyRef(name, configFr)));
-}
-
} // namespace aapt
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index a2528d2ac195..3a880449b759 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -40,6 +40,7 @@ struct IAaptContext {
virtual StringPiece16 getCompilationPackage() = 0;
virtual uint8_t getPackageId() = 0;
virtual NameMangler* getNameMangler() = 0;
+ virtual bool verbose() = 0;
};
struct IResourceTableConsumer {
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 6ad2f9c10d22..b6030a2874a3 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -17,9 +17,7 @@
#include "ConfigDescription.h"
#include "Resource.h"
#include "ValueVisitor.h"
-
#include "process/SymbolTable.h"
-#include "util/Comparators.h"
#include "util/Util.h"
#include <androidfw/AssetManager.h>
@@ -55,12 +53,10 @@ const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& n
if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
const ConfigDescription kDefaultConfig;
- auto iter = std::lower_bound(sr.entry->values.begin(), sr.entry->values.end(),
- kDefaultConfig, cmp::lessThanConfig);
-
- if (iter != sr.entry->values.end() && iter->config == kDefaultConfig) {
+ ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig);
+ if (configValue) {
// This resource has an Attribute.
- if (Attribute* attr = valueCast<Attribute>(iter->value.get())) {
+ if (Attribute* attr = valueCast<Attribute>(configValue->value.get())) {
symbol->attribute = util::make_unique<Attribute>(*attr);
} else {
return {};
diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp
new file mode 100644
index 000000000000..99981c52e26f
--- /dev/null
+++ b/tools/aapt2/proto/ProtoHelpers.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "proto/ProtoHelpers.h"
+
+namespace aapt {
+
+void serializeStringPoolToPb(const StringPool& pool, pb::StringPool* outPbPool) {
+ BigBuffer buffer(1024);
+ StringPool::flattenUtf8(&buffer, pool);
+
+ std::string* data = outPbPool->mutable_data();
+ data->reserve(buffer.size());
+
+ size_t offset = 0;
+ for (const BigBuffer::Block& block : buffer) {
+ data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
+ offset += block.size;
+ }
+}
+
+void serializeSourceToPb(const Source& source, StringPool* srcPool, pb::Source* outPbSource) {
+ StringPool::Ref ref = srcPool->makeRef(util::utf8ToUtf16(source.path));
+ outPbSource->set_path_idx(static_cast<uint32_t>(ref.getIndex()));
+ if (source.line) {
+ outPbSource->set_line_no(static_cast<uint32_t>(source.line.value()));
+ }
+}
+
+void deserializeSourceFromPb(const pb::Source& pbSource, const android::ResStringPool& srcPool,
+ Source* outSource) {
+ if (pbSource.has_path_idx()) {
+ outSource->path = util::getString8(srcPool, pbSource.path_idx()).toString();
+ }
+
+ if (pbSource.has_line_no()) {
+ outSource->line = static_cast<size_t>(pbSource.line_no());
+ }
+}
+
+pb::SymbolStatus_Visibility serializeVisibilityToPb(SymbolState state) {
+ switch (state) {
+ case SymbolState::kPrivate: return pb::SymbolStatus_Visibility_Private;
+ case SymbolState::kPublic: return pb::SymbolStatus_Visibility_Public;
+ default: break;
+ }
+ return pb::SymbolStatus_Visibility_Unknown;
+}
+
+SymbolState deserializeVisibilityFromPb(pb::SymbolStatus_Visibility pbVisibility) {
+ switch (pbVisibility) {
+ case pb::SymbolStatus_Visibility_Private: return SymbolState::kPrivate;
+ case pb::SymbolStatus_Visibility_Public: return SymbolState::kPublic;
+ default: break;
+ }
+ return SymbolState::kUndefined;
+}
+
+void serializeConfig(const ConfigDescription& config, pb::ConfigDescription* outPbConfig) {
+ android::ResTable_config flatConfig = config;
+ flatConfig.size = sizeof(flatConfig);
+ flatConfig.swapHtoD();
+ outPbConfig->set_data(&flatConfig, sizeof(flatConfig));
+}
+
+bool deserializeConfigDescriptionFromPb(const pb::ConfigDescription& pbConfig,
+ ConfigDescription* outConfig) {
+ if (!pbConfig.has_data()) {
+ return false;
+ }
+
+ const android::ResTable_config* config;
+ if (pbConfig.data().size() > sizeof(*config)) {
+ return false;
+ }
+
+ config = reinterpret_cast<const android::ResTable_config*>(pbConfig.data().data());
+ outConfig->copyFromDtoH(*config);
+ return true;
+}
+
+pb::Reference_Type serializeReferenceTypeToPb(Reference::Type type) {
+ switch (type) {
+ case Reference::Type::kResource: return pb::Reference_Type_Ref;
+ case Reference::Type::kAttribute: return pb::Reference_Type_Attr;
+ default: break;
+ }
+ return pb::Reference_Type_Ref;
+}
+
+Reference::Type deserializeReferenceTypeFromPb(pb::Reference_Type pbType) {
+ switch (pbType) {
+ case pb::Reference_Type_Ref: return Reference::Type::kResource;
+ case pb::Reference_Type_Attr: return Reference::Type::kAttribute;
+ default: break;
+ }
+ return Reference::Type::kResource;
+}
+
+pb::Plural_Arity serializePluralEnumToPb(size_t pluralIdx) {
+ switch (pluralIdx) {
+ case Plural::Zero: return pb::Plural_Arity_Zero;
+ case Plural::One: return pb::Plural_Arity_One;
+ case Plural::Two: return pb::Plural_Arity_Two;
+ case Plural::Few: return pb::Plural_Arity_Few;
+ case Plural::Many: return pb::Plural_Arity_Many;
+ default: break;
+ }
+ return pb::Plural_Arity_Other;
+}
+
+size_t deserializePluralEnumFromPb(pb::Plural_Arity arity) {
+ switch (arity) {
+ case pb::Plural_Arity_Zero: return Plural::Zero;
+ case pb::Plural_Arity_One: return Plural::One;
+ case pb::Plural_Arity_Two: return Plural::Two;
+ case pb::Plural_Arity_Few: return Plural::Few;
+ case pb::Plural_Arity_Many: return Plural::Many;
+ default: break;
+ }
+ return Plural::Other;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h
new file mode 100644
index 000000000000..02e67f17c80c
--- /dev/null
+++ b/tools/aapt2/proto/ProtoHelpers.h
@@ -0,0 +1,52 @@
+/*
+ * 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_PROTO_PROTOHELPERS_H
+#define AAPT_PROTO_PROTOHELPERS_H
+
+#include "ConfigDescription.h"
+#include "ResourceTable.h"
+#include "Source.h"
+#include "StringPool.h"
+
+#include "proto/frameworks/base/tools/aapt2/Format.pb.h"
+
+#include <androidfw/ResourceTypes.h>
+
+namespace aapt {
+
+void serializeStringPoolToPb(const StringPool& pool, pb::StringPool* outPbPool);
+
+void serializeSourceToPb(const Source& source, StringPool* srcPool, pb::Source* outPbSource);
+void deserializeSourceFromPb(const pb::Source& pbSource, const android::ResStringPool& srcPool,
+ Source* outSource);
+
+pb::SymbolStatus_Visibility serializeVisibilityToPb(SymbolState state);
+SymbolState deserializeVisibilityFromPb(pb::SymbolStatus_Visibility pbVisibility);
+
+void serializeConfig(const ConfigDescription& config, pb::ConfigDescription* outPbConfig);
+bool deserializeConfigDescriptionFromPb(const pb::ConfigDescription& pbConfig,
+ ConfigDescription* outConfig);
+
+pb::Reference_Type serializeReferenceTypeToPb(Reference::Type type);
+Reference::Type deserializeReferenceTypeFromPb(pb::Reference_Type pbType);
+
+pb::Plural_Arity serializePluralEnumToPb(size_t pluralIdx);
+size_t deserializePluralEnumFromPb(pb::Plural_Arity arity);
+
+} // namespace aapt
+
+#endif /* AAPT_PROTO_PROTOHELPERS_H */
diff --git a/tools/aapt2/proto/ProtoSerialize.h b/tools/aapt2/proto/ProtoSerialize.h
new file mode 100644
index 000000000000..6e224ab00af4
--- /dev/null
+++ b/tools/aapt2/proto/ProtoSerialize.h
@@ -0,0 +1,77 @@
+/*
+ * 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_FLATTEN_TABLEPROTOSERIALIZER_H
+#define AAPT_FLATTEN_TABLEPROTOSERIALIZER_H
+
+#include "Diagnostics.h"
+#include "ResourceTable.h"
+#include "Source.h"
+#include "proto/ProtoHelpers.h"
+
+#include <android-base/macros.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+namespace aapt {
+
+std::unique_ptr<pb::ResourceTable> serializeTableToPb(ResourceTable* table);
+std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
+ const Source& source,
+ IDiagnostics* diag);
+
+std::unique_ptr<pb::CompiledFile> serializeCompiledFileToPb(const ResourceFile& file);
+std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile,
+ const Source& source,
+ IDiagnostics* diag);
+
+class CompiledFileOutputStream : public google::protobuf::io::CopyingOutputStream {
+public:
+ CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out,
+ pb::CompiledFile* pbFile);
+ bool Write(const void* data, int size) override;
+ bool Finish();
+
+private:
+ bool ensureFileWritten();
+
+ google::protobuf::io::CodedOutputStream mOut;
+ pb::CompiledFile* mPbFile;
+
+ DISALLOW_COPY_AND_ASSIGN(CompiledFileOutputStream);
+};
+
+class CompiledFileInputStream {
+public:
+ CompiledFileInputStream(const void* data, size_t size);
+
+ const pb::CompiledFile* CompiledFile();
+
+ const void* data();
+ size_t size();
+
+private:
+ google::protobuf::io::CodedInputStream mIn;
+ std::unique_ptr<pb::CompiledFile> mPbFile;
+ const uint8_t* mData;
+ size_t mSize;
+
+ DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_FLATTEN_TABLEPROTOSERIALIZER_H */
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
new file mode 100644
index 000000000000..9856a00d7f67
--- /dev/null
+++ b/tools/aapt2/proto/TableProtoDeserializer.cpp
@@ -0,0 +1,511 @@
+/*
+ * 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 "ResourceTable.h"
+#include "ResourceUtils.h"
+#include "ValueVisitor.h"
+#include "proto/ProtoHelpers.h"
+#include "proto/ProtoSerialize.h"
+
+#include <androidfw/ResourceTypes.h>
+
+namespace aapt {
+
+namespace {
+
+class ReferenceIdToNameVisitor : public ValueVisitor {
+public:
+ using ValueVisitor::visit;
+
+ ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) :
+ mMapping(mapping) {
+ assert(mMapping);
+ }
+
+ void visit(Reference* reference) override {
+ if (!reference->id || !reference->id.value().isValid()) {
+ return;
+ }
+
+ ResourceId id = reference->id.value();
+ auto cacheIter = mMapping->find(id);
+ if (cacheIter != mMapping->end()) {
+ reference->name = cacheIter->second.toResourceName();
+ }
+ }
+
+private:
+ const std::map<ResourceId, ResourceNameRef>* mMapping;
+};
+
+class PackagePbDeserializer {
+public:
+ PackagePbDeserializer(const android::ResStringPool* valuePool,
+ const android::ResStringPool* sourcePool,
+ const android::ResStringPool* symbolPool,
+ const Source& source, IDiagnostics* diag) :
+ mValuePool(valuePool), mSourcePool(sourcePool), mSymbolPool(symbolPool),
+ mSource(source), mDiag(diag) {
+ }
+
+public:
+ bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) {
+ Maybe<uint8_t> id;
+ if (pbPackage.has_package_id()) {
+ id = static_cast<uint8_t>(pbPackage.package_id());
+ }
+
+ std::map<ResourceId, ResourceNameRef> idIndex;
+
+ ResourceTablePackage* pkg = table->createPackage(
+ util::utf8ToUtf16(pbPackage.package_name()), id);
+ for (const pb::Type& pbType : pbPackage.types()) {
+ const ResourceType* resType = parseResourceType(util::utf8ToUtf16(pbType.name()));
+ if (!resType) {
+ mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'");
+ return {};
+ }
+
+ ResourceTableType* type = pkg->findOrCreateType(*resType);
+
+ for (const pb::Entry& pbEntry : pbType.entries()) {
+ ResourceEntry* entry = type->findOrCreateEntry(util::utf8ToUtf16(pbEntry.name()));
+
+ // Deserialize the symbol status (public/private with source and comments).
+ if (pbEntry.has_symbol_status()) {
+ const pb::SymbolStatus& pbStatus = pbEntry.symbol_status();
+ if (pbStatus.has_source()) {
+ deserializeSourceFromPb(pbStatus.source(), *mSourcePool,
+ &entry->symbolStatus.source);
+ }
+
+ if (pbStatus.has_comment()) {
+ entry->symbolStatus.comment = util::utf8ToUtf16(pbStatus.comment());
+ }
+
+ SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility());
+ entry->symbolStatus.state = visibility;
+
+ if (visibility == SymbolState::kPublic) {
+ // This is a public symbol, we must encode the ID now if there is one.
+ if (pbEntry.has_id()) {
+ entry->id = static_cast<uint16_t>(pbEntry.id());
+ }
+
+ if (type->symbolStatus.state != SymbolState::kPublic) {
+ // If the type has not been made public, do so now.
+ type->symbolStatus.state = SymbolState::kPublic;
+ if (pbType.has_id()) {
+ type->id = static_cast<uint8_t>(pbType.id());
+ }
+ }
+ } else if (visibility == SymbolState::kPrivate) {
+ if (type->symbolStatus.state == SymbolState::kUndefined) {
+ type->symbolStatus.state = SymbolState::kPrivate;
+ }
+ }
+ }
+
+ ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id());
+ if (resId.isValid()) {
+ idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name);
+ }
+
+ for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) {
+ const pb::ConfigDescription& pbConfig = pbConfigValue.config();
+
+ ConfigDescription config;
+ if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) {
+ mDiag->error(DiagMessage(mSource) << "invalid configuration");
+ return {};
+ }
+
+ ResourceConfigValue* configValue = entry->findOrCreateValue(config,
+ pbConfig.product());
+ if (configValue->value) {
+ // Duplicate config.
+ mDiag->error(DiagMessage(mSource) << "duplicate configuration");
+ return {};
+ }
+
+ configValue->value = deserializeValueFromPb(pbConfigValue.value(),
+ config, &table->stringPool);
+ if (!configValue->value) {
+ return {};
+ }
+ }
+ }
+ }
+
+ ReferenceIdToNameVisitor visitor(&idIndex);
+ visitAllValuesInPackage(pkg, &visitor);
+ return true;
+ }
+
+private:
+ std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem,
+ const ConfigDescription& config,
+ StringPool* pool) {
+ if (pbItem.has_ref()) {
+ const pb::Reference& pbRef = pbItem.ref();
+ std::unique_ptr<Reference> ref = util::make_unique<Reference>();
+ if (!deserializeReferenceFromPb(pbRef, ref.get())) {
+ return {};
+ }
+ return std::move(ref);
+
+ } else if (pbItem.has_prim()) {
+ const pb::Primitive& pbPrim = pbItem.prim();
+ android::Res_value prim = {};
+ prim.dataType = static_cast<uint8_t>(pbPrim.type());
+ prim.data = pbPrim.data();
+ return util::make_unique<BinaryPrimitive>(prim);
+
+ } else if (pbItem.has_id()) {
+ return util::make_unique<Id>();
+
+ } else if (pbItem.has_str()) {
+ const uint32_t idx = pbItem.str().idx();
+ StringPiece16 str = util::getString(*mValuePool, idx);
+
+ const android::ResStringPool_span* spans = mValuePool->styleAt(idx);
+ if (spans && spans->name.index != android::ResStringPool_span::END) {
+ StyleString styleStr = { str.toString() };
+ while (spans->name.index != android::ResStringPool_span::END) {
+ styleStr.spans.push_back(Span{
+ util::getString(*mValuePool, spans->name.index).toString(),
+ spans->firstChar,
+ spans->lastChar
+ });
+ spans++;
+ }
+ return util::make_unique<StyledString>(
+ pool->makeRef(styleStr, StringPool::Context{ 1, config }));
+ }
+ return util::make_unique<String>(
+ pool->makeRef(str, StringPool::Context{ 1, config }));
+
+ } else if (pbItem.has_raw_str()) {
+ const uint32_t idx = pbItem.raw_str().idx();
+ StringPiece16 str = util::getString(*mValuePool, idx);
+ return util::make_unique<RawString>(
+ pool->makeRef(str, StringPool::Context{ 1, config }));
+
+ } else if (pbItem.has_file()) {
+ const uint32_t idx = pbItem.file().path_idx();
+ StringPiece16 str = util::getString(*mValuePool, idx);
+ return util::make_unique<FileReference>(
+ pool->makeRef(str, StringPool::Context{ 0, config }));
+
+ } else {
+ mDiag->error(DiagMessage(mSource) << "unknown item");
+ }
+ return {};
+ }
+
+ std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue,
+ const ConfigDescription& config,
+ StringPool* pool) {
+ const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false;
+
+ std::unique_ptr<Value> value;
+ if (pbValue.has_item()) {
+ value = deserializeItemFromPb(pbValue.item(), config, pool);
+ if (!value) {
+ return {};
+ }
+
+ } else if (pbValue.has_compound_value()) {
+ const pb::CompoundValue pbCompoundValue = pbValue.compound_value();
+ if (pbCompoundValue.has_attr()) {
+ const pb::Attribute& pbAttr = pbCompoundValue.attr();
+ std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
+ attr->typeMask = pbAttr.format_flags();
+ for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) {
+ Attribute::Symbol symbol;
+ deserializeItemCommon(pbSymbol, &symbol.symbol);
+ if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) {
+ return {};
+ }
+ symbol.value = pbSymbol.value();
+ attr->symbols.push_back(std::move(symbol));
+ }
+ value = std::move(attr);
+
+ } else if (pbCompoundValue.has_style()) {
+ const pb::Style& pbStyle = pbCompoundValue.style();
+ std::unique_ptr<Style> style = util::make_unique<Style>();
+ if (pbStyle.has_parent()) {
+ style->parent = Reference();
+ if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) {
+ return {};
+ }
+
+ if (pbStyle.has_parent_source()) {
+ Source parentSource;
+ deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool,
+ &parentSource);
+ style->parent.value().setSource(std::move(parentSource));
+ }
+ }
+
+ for (const pb::Style_Entry& pbEntry : pbStyle.entries()) {
+ Style::Entry entry;
+ deserializeItemCommon(pbEntry, &entry.key);
+ if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) {
+ return {};
+ }
+
+ entry.value = deserializeItemFromPb(pbEntry.item(), config, pool);
+ if (!entry.value) {
+ return {};
+ }
+
+ deserializeItemCommon(pbEntry, entry.value.get());
+ style->entries.push_back(std::move(entry));
+ }
+ value = std::move(style);
+
+ } else if (pbCompoundValue.has_styleable()) {
+ const pb::Styleable& pbStyleable = pbCompoundValue.styleable();
+ std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+ for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) {
+ Reference attrRef;
+ deserializeItemCommon(pbEntry, &attrRef);
+ deserializeReferenceFromPb(pbEntry.attr(), &attrRef);
+ styleable->entries.push_back(std::move(attrRef));
+ }
+ value = std::move(styleable);
+
+ } else if (pbCompoundValue.has_array()) {
+ const pb::Array& pbArray = pbCompoundValue.array();
+ std::unique_ptr<Array> array = util::make_unique<Array>();
+ for (const pb::Array_Entry& pbEntry : pbArray.entries()) {
+ std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config,
+ pool);
+ if (!item) {
+ return {};
+ }
+
+ deserializeItemCommon(pbEntry, item.get());
+ array->items.push_back(std::move(item));
+ }
+ value = std::move(array);
+
+ } else if (pbCompoundValue.has_plural()) {
+ const pb::Plural& pbPlural = pbCompoundValue.plural();
+ std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+ for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) {
+ size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity());
+ plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config,
+ pool);
+ if (!plural->values[pluralIdx]) {
+ return {};
+ }
+
+ deserializeItemCommon(pbEntry, plural->values[pluralIdx].get());
+ }
+ value = std::move(plural);
+
+ } else {
+ mDiag->error(DiagMessage(mSource) << "unknown compound value");
+ return {};
+ }
+ } else {
+ mDiag->error(DiagMessage(mSource) << "unknown value");
+ return {};
+ }
+
+ assert(value && "forgot to set value");
+
+ value->setWeak(isWeak);
+ deserializeItemCommon(pbValue, value.get());
+ return value;
+ }
+
+ bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) {
+ outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type());
+ outRef->privateReference = pbRef.private_();
+
+ if (!pbRef.has_id() && !pbRef.has_symbol_idx()) {
+ return false;
+ }
+
+ if (pbRef.has_id()) {
+ outRef->id = ResourceId(pbRef.id());
+ }
+
+ if (pbRef.has_symbol_idx()) {
+ StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
+ ResourceNameRef nameRef;
+ if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) {
+ mDiag->error(DiagMessage(mSource) << "invalid reference name '"
+ << strSymbol << "'");
+ return false;
+ }
+
+ outRef->name = nameRef.toResourceName();
+ }
+ return true;
+ }
+
+ template <typename T>
+ void deserializeItemCommon(const T& pbItem, Value* outValue) {
+ if (pbItem.has_source()) {
+ Source source;
+ deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source);
+ outValue->setSource(std::move(source));
+ }
+
+ if (pbItem.has_comment()) {
+ outValue->setComment(util::utf8ToUtf16(pbItem.comment()));
+ }
+ }
+
+private:
+ const android::ResStringPool* mValuePool;
+ const android::ResStringPool* mSourcePool;
+ const android::ResStringPool* mSymbolPool;
+ const Source mSource;
+ IDiagnostics* mDiag;
+};
+
+} // namespace
+
+std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
+ const Source& source,
+ IDiagnostics* diag) {
+ std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+
+ if (!pbTable.has_string_pool()) {
+ diag->error(DiagMessage(source) << "no string pool found");
+ return {};
+ }
+
+ android::ResStringPool valuePool;
+ android::status_t result = valuePool.setTo(pbTable.string_pool().data().data(),
+ pbTable.string_pool().data().size());
+ if (result != android::NO_ERROR) {
+ diag->error(DiagMessage(source) << "invalid string pool");
+ return {};
+ }
+
+ android::ResStringPool sourcePool;
+ if (pbTable.has_source_pool()) {
+ result = sourcePool.setTo(pbTable.source_pool().data().data(),
+ pbTable.source_pool().data().size());
+ if (result != android::NO_ERROR) {
+ diag->error(DiagMessage(source) << "invalid source pool");
+ return {};
+ }
+ }
+
+ android::ResStringPool symbolPool;
+ if (pbTable.has_symbol_pool()) {
+ result = symbolPool.setTo(pbTable.symbol_pool().data().data(),
+ pbTable.symbol_pool().data().size());
+ if (result != android::NO_ERROR) {
+ diag->error(DiagMessage(source) << "invalid symbol pool");
+ return {};
+ }
+ }
+
+ PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag);
+ for (const pb::Package& pbPackage : pbTable.packages()) {
+ if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) {
+ return {};
+ }
+ }
+ return table;
+}
+
+std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile,
+ const Source& source,
+ IDiagnostics* diag) {
+ std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
+
+ ResourceNameRef nameRef;
+
+ // Need to create an lvalue here so that nameRef can point to something real.
+ std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name());
+ if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
+ diag->error(DiagMessage(source) << "invalid resource name in compiled file header: "
+ << pbFile.resource_name());
+ return {};
+ }
+ file->name = nameRef.toResourceName();
+ file->source.path = pbFile.source_path();
+ deserializeConfigDescriptionFromPb(pbFile.config(), &file->config);
+
+ for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) {
+ // Need to create an lvalue here so that nameRef can point to something real.
+ utf16Name = util::utf8ToUtf16(pbSymbol.resource_name());
+ if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
+ diag->error(DiagMessage(source) << "invalid resource name for exported symbol in "
+ "compiled file header: "
+ << pbFile.resource_name());
+ return {};
+ }
+ file->exportedSymbols.push_back(
+ SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() });
+ }
+ return file;
+}
+
+CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
+ mIn(static_cast<const uint8_t*>(data), size), mPbFile(),
+ mData(static_cast<const uint8_t*>(data)), mSize(size) {
+}
+
+const pb::CompiledFile* CompiledFileInputStream::CompiledFile() {
+ if (!mPbFile) {
+ std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
+ uint64_t pbSize = 0u;
+ if (!mIn.ReadLittleEndian64(&pbSize)) {
+ return nullptr;
+ }
+ mIn.PushLimit(static_cast<int>(pbSize));
+ if (!pbFile->ParsePartialFromCodedStream(&mIn)) {
+ return nullptr;
+ }
+
+ const size_t padding = 4 - (pbSize & 0x03);
+ mData += sizeof(uint64_t) + pbSize + padding;
+ mSize -= sizeof(uint64_t) + pbSize + padding;
+ mPbFile = std::move(pbFile);
+ }
+ return mPbFile.get();
+}
+
+const void* CompiledFileInputStream::data() {
+ if (!mPbFile) {
+ if (!CompiledFile()) {
+ return nullptr;
+ }
+ }
+ return mData;
+}
+
+size_t CompiledFileInputStream::size() {
+ if (!mPbFile) {
+ if (!CompiledFile()) {
+ return 0;
+ }
+ }
+ return mSize;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
new file mode 100644
index 000000000000..b3d87d805c6d
--- /dev/null
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -0,0 +1,319 @@
+/*
+ * 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 "Resource.h"
+#include "ResourceTable.h"
+#include "StringPool.h"
+#include "ValueVisitor.h"
+#include "proto/ProtoHelpers.h"
+#include "proto/ProtoSerialize.h"
+#include "util/BigBuffer.h"
+
+namespace aapt {
+
+namespace {
+
+class PbSerializerVisitor : public RawValueVisitor {
+public:
+ using RawValueVisitor::visit;
+
+ /**
+ * Constructor to use when expecting to serialize any value.
+ */
+ PbSerializerVisitor(StringPool* sourcePool, StringPool* symbolPool, pb::Value* outPbValue) :
+ mSourcePool(sourcePool), mSymbolPool(symbolPool), mOutPbValue(outPbValue),
+ mOutPbItem(nullptr) {
+ }
+
+ /**
+ * Constructor to use when expecting to serialize an Item.
+ */
+ PbSerializerVisitor(StringPool* sourcePool, StringPool* symbolPool, pb::Item* outPbItem) :
+ mSourcePool(sourcePool), mSymbolPool(symbolPool), mOutPbValue(nullptr),
+ mOutPbItem(outPbItem) {
+ }
+
+ void visit(Reference* ref) override {
+ serializeReferenceToPb(*ref, getPbItem()->mutable_ref());
+ }
+
+ void visit(String* str) override {
+ getPbItem()->mutable_str()->set_idx(str->value.getIndex());
+ }
+
+ void visit(StyledString* str) override {
+ getPbItem()->mutable_str()->set_idx(str->value.getIndex());
+ }
+
+ void visit(FileReference* file) override {
+ getPbItem()->mutable_file()->set_path_idx(file->path.getIndex());
+ }
+
+ void visit(Id* id) override {
+ getPbItem()->mutable_id();
+ }
+
+ void visit(RawString* rawStr) override {
+ getPbItem()->mutable_raw_str()->set_idx(rawStr->value.getIndex());
+ }
+
+ void visit(BinaryPrimitive* prim) override {
+ android::Res_value val = {};
+ prim->flatten(&val);
+
+ pb::Primitive* pbPrim = getPbItem()->mutable_prim();
+ pbPrim->set_type(val.dataType);
+ pbPrim->set_data(val.data);
+ }
+
+ void visitItem(Item* item) override {
+ assert(false && "unimplemented item");
+ }
+
+ void visit(Attribute* attr) override {
+ pb::Attribute* pbAttr = getPbCompoundValue()->mutable_attr();
+ pbAttr->set_format_flags(attr->typeMask);
+ pbAttr->set_min_int(attr->minInt);
+ pbAttr->set_max_int(attr->maxInt);
+
+ for (auto& symbol : attr->symbols) {
+ pb::Attribute_Symbol* pbSymbol = pbAttr->add_symbols();
+ serializeItemCommonToPb(symbol.symbol, pbSymbol);
+ serializeReferenceToPb(symbol.symbol, pbSymbol->mutable_name());
+ pbSymbol->set_value(symbol.value);
+ }
+ }
+
+ void visit(Style* style) override {
+ pb::Style* pbStyle = getPbCompoundValue()->mutable_style();
+ if (style->parent) {
+ serializeReferenceToPb(style->parent.value(), pbStyle->mutable_parent());
+ serializeSourceToPb(style->parent.value().getSource(),
+ mSourcePool,
+ pbStyle->mutable_parent_source());
+ }
+
+ for (Style::Entry& entry : style->entries) {
+ pb::Style_Entry* pbEntry = pbStyle->add_entries();
+ serializeReferenceToPb(entry.key, pbEntry->mutable_key());
+
+ pb::Item* pbItem = pbEntry->mutable_item();
+ serializeItemCommonToPb(entry.key, pbEntry);
+ PbSerializerVisitor subVisitor(mSourcePool, mSymbolPool, pbItem);
+ entry.value->accept(&subVisitor);
+ }
+ }
+
+ void visit(Styleable* styleable) override {
+ pb::Styleable* pbStyleable = getPbCompoundValue()->mutable_styleable();
+ for (Reference& entry : styleable->entries) {
+ pb::Styleable_Entry* pbEntry = pbStyleable->add_entries();
+ serializeItemCommonToPb(entry, pbEntry);
+ serializeReferenceToPb(entry, pbEntry->mutable_attr());
+ }
+ }
+
+ void visit(Array* array) override {
+ pb::Array* pbArray = getPbCompoundValue()->mutable_array();
+ for (auto& value : array->items) {
+ pb::Array_Entry* pbEntry = pbArray->add_entries();
+ serializeItemCommonToPb(*value, pbEntry);
+ PbSerializerVisitor subVisitor(mSourcePool, mSymbolPool, pbEntry->mutable_item());
+ value->accept(&subVisitor);
+ }
+ }
+
+ void visit(Plural* plural) override {
+ pb::Plural* pbPlural = getPbCompoundValue()->mutable_plural();
+ const size_t count = plural->values.size();
+ for (size_t i = 0; i < count; i++) {
+ if (!plural->values[i]) {
+ // No plural value set here.
+ continue;
+ }
+
+ pb::Plural_Entry* pbEntry = pbPlural->add_entries();
+ pbEntry->set_arity(serializePluralEnumToPb(i));
+ pb::Item* pbElement = pbEntry->mutable_item();
+ serializeItemCommonToPb(*plural->values[i], pbEntry);
+ PbSerializerVisitor subVisitor(mSourcePool, mSymbolPool, pbElement);
+ plural->values[i]->accept(&subVisitor);
+ }
+ }
+
+private:
+ pb::Item* getPbItem() {
+ if (mOutPbValue) {
+ return mOutPbValue->mutable_item();
+ }
+ return mOutPbItem;
+ }
+
+ pb::CompoundValue* getPbCompoundValue() {
+ assert(mOutPbValue);
+ return mOutPbValue->mutable_compound_value();
+ }
+
+ template <typename T>
+ void serializeItemCommonToPb(const Item& item, T* pbItem) {
+ serializeSourceToPb(item.getSource(), mSourcePool, pbItem->mutable_source());
+ if (!item.getComment().empty()) {
+ pbItem->set_comment(util::utf16ToUtf8(item.getComment()));
+ }
+ }
+
+ void serializeReferenceToPb(const Reference& ref, pb::Reference* pbRef) {
+ if (ref.id) {
+ pbRef->set_id(ref.id.value().id);
+ } else if (ref.name) {
+ StringPool::Ref symbolRef = mSymbolPool->makeRef(ref.name.value().toString());
+ pbRef->set_symbol_idx(static_cast<uint32_t>(symbolRef.getIndex()));
+ }
+ pbRef->set_private_(ref.privateReference);
+ pbRef->set_type(serializeReferenceTypeToPb(ref.referenceType));
+ }
+
+ StringPool* mSourcePool;
+ StringPool* mSymbolPool;
+ pb::Value* mOutPbValue;
+ pb::Item* mOutPbItem;
+};
+
+} // namespace
+
+std::unique_ptr<pb::ResourceTable> serializeTableToPb(ResourceTable* table) {
+ // We must do this before writing the resources, since the string pool IDs may change.
+ table->stringPool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
+ int diff = a.context.priority - b.context.priority;
+ if (diff < 0) return true;
+ if (diff > 0) return false;
+ diff = a.context.config.compare(b.context.config);
+ if (diff < 0) return true;
+ if (diff > 0) return false;
+ return a.value < b.value;
+ });
+ table->stringPool.prune();
+
+ std::unique_ptr<pb::ResourceTable> pbTable = util::make_unique<pb::ResourceTable>();
+ serializeStringPoolToPb(table->stringPool, pbTable->mutable_string_pool());
+
+ StringPool sourcePool, symbolPool;
+
+ for (auto& package : table->packages) {
+ pb::Package* pbPackage = pbTable->add_packages();
+ if (package->id) {
+ pbPackage->set_package_id(package->id.value());
+ }
+ pbPackage->set_package_name(util::utf16ToUtf8(package->name));
+
+ for (auto& type : package->types) {
+ pb::Type* pbType = pbPackage->add_types();
+ if (type->id) {
+ pbType->set_id(type->id.value());
+ }
+ pbType->set_name(util::utf16ToUtf8(toString(type->type)));
+
+ for (auto& entry : type->entries) {
+ pb::Entry* pbEntry = pbType->add_entries();
+ if (entry->id) {
+ pbEntry->set_id(entry->id.value());
+ }
+ pbEntry->set_name(util::utf16ToUtf8(entry->name));
+
+ // Write the SymbolStatus struct.
+ pb::SymbolStatus* pbStatus = pbEntry->mutable_symbol_status();
+ pbStatus->set_visibility(serializeVisibilityToPb(entry->symbolStatus.state));
+ serializeSourceToPb(entry->symbolStatus.source, &sourcePool,
+ pbStatus->mutable_source());
+ pbStatus->set_comment(util::utf16ToUtf8(entry->symbolStatus.comment));
+
+ for (auto& configValue : entry->values) {
+ pb::ConfigValue* pbConfigValue = pbEntry->add_config_values();
+ serializeConfig(configValue->config, pbConfigValue->mutable_config());
+ if (!configValue->product.empty()) {
+ pbConfigValue->mutable_config()->set_product(configValue->product);
+ }
+
+ pb::Value* pbValue = pbConfigValue->mutable_value();
+ serializeSourceToPb(configValue->value->getSource(), &sourcePool,
+ pbValue->mutable_source());
+ if (!configValue->value->getComment().empty()) {
+ pbValue->set_comment(util::utf16ToUtf8(configValue->value->getComment()));
+ }
+
+ if (configValue->value->isWeak()) {
+ pbValue->set_weak(true);
+ }
+
+ PbSerializerVisitor visitor(&sourcePool, &symbolPool, pbValue);
+ configValue->value->accept(&visitor);
+ }
+ }
+ }
+ }
+
+ serializeStringPoolToPb(sourcePool, pbTable->mutable_source_pool());
+ serializeStringPoolToPb(symbolPool, pbTable->mutable_symbol_pool());
+ return pbTable;
+}
+
+std::unique_ptr<pb::CompiledFile> serializeCompiledFileToPb(const ResourceFile& file) {
+ std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
+ pbFile->set_resource_name(util::utf16ToUtf8(file.name.toString()));
+ pbFile->set_source_path(file.source.path);
+ serializeConfig(file.config, pbFile->mutable_config());
+
+ for (const SourcedResourceName& exported : file.exportedSymbols) {
+ pb::CompiledFile_Symbol* pbSymbol = pbFile->add_exported_symbols();
+ pbSymbol->set_resource_name(util::utf16ToUtf8(exported.name.toString()));
+ pbSymbol->set_line_no(exported.line);
+ }
+ return pbFile;
+}
+
+CompiledFileOutputStream::CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out,
+ pb::CompiledFile* pbFile) :
+ mOut(out), mPbFile(pbFile) {
+}
+
+bool CompiledFileOutputStream::ensureFileWritten() {
+ if (mPbFile) {
+ const uint64_t pbSize = mPbFile->ByteSize();
+ mOut.WriteLittleEndian64(pbSize);
+ mPbFile->SerializeWithCachedSizes(&mOut);
+ const size_t padding = 4 - (pbSize & 0x03);
+ if (padding > 0) {
+ uint32_t zero = 0u;
+ mOut.WriteRaw(&zero, padding);
+ }
+ mPbFile = nullptr;
+ }
+ return !mOut.HadError();
+}
+
+bool CompiledFileOutputStream::Write(const void* data, int size) {
+ if (!ensureFileWritten()) {
+ return false;
+ }
+ mOut.WriteRaw(data, size);
+ return !mOut.HadError();
+}
+
+bool CompiledFileOutputStream::Finish() {
+ return ensureFileWritten();
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
new file mode 100644
index 000000000000..70a33f795f87
--- /dev/null
+++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 "ResourceTable.h"
+#include "proto/ProtoSerialize.h"
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(TableProtoSerializer, SerializeSinglePackage) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .setPackageId(u"com.app.a", 0x7f)
+ .addFileReference(u"@com.app.a:layout/main", ResourceId(0x7f020000),
+ u"res/layout/main.xml")
+ .addReference(u"@com.app.a:layout/other", ResourceId(0x7f020001),
+ u"@com.app.a:layout/main")
+ .addString(u"@com.app.a:string/text", {}, u"hi")
+ .addValue(u"@com.app.a:id/foo", {}, util::make_unique<Id>())
+ .build();
+
+ Symbol publicSymbol;
+ publicSymbol.state = SymbolState::kPublic;
+ ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@com.app.a:layout/main"),
+ ResourceId(0x7f020000),
+ publicSymbol, context->getDiagnostics()));
+
+ Id* id = test::getValue<Id>(table.get(), u"@com.app.a:id/foo");
+ ASSERT_NE(nullptr, id);
+
+ // Make a plural.
+ std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+ plural->values[Plural::One] = util::make_unique<String>(table->stringPool.makeRef(u"one"));
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:plurals/hey"),
+ ConfigDescription{}, std::string(), std::move(plural),
+ context->getDiagnostics()));
+
+ // Make a resource with different products.
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:integer/one"),
+ test::parseConfigOrDie("land"), std::string(),
+ test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
+ context->getDiagnostics()));
+ ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:integer/one"),
+ test::parseConfigOrDie("land"), std::string("tablet"),
+ test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
+ context->getDiagnostics()));
+
+ std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table.get());
+ ASSERT_NE(nullptr, pbTable);
+
+ std::unique_ptr<ResourceTable> newTable = deserializeTableFromPb(*pbTable,
+ Source{ "test" },
+ context->getDiagnostics());
+ ASSERT_NE(nullptr, newTable);
+
+ Id* newId = test::getValue<Id>(newTable.get(), u"@com.app.a:id/foo");
+ ASSERT_NE(nullptr, newId);
+ EXPECT_EQ(id->isWeak(), newId->isWeak());
+
+ Maybe<ResourceTable::SearchResult> result = newTable->findResource(
+ test::parseNameOrDie(u"@com.app.a:layout/main"));
+ AAPT_ASSERT_TRUE(result);
+ EXPECT_EQ(SymbolState::kPublic, result.value().type->symbolStatus.state);
+ EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state);
+
+ // Find the product-dependent values
+ BinaryPrimitive* prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
+ newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "");
+ ASSERT_NE(nullptr, prim);
+ EXPECT_EQ(123u, prim->value.data);
+
+ prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
+ newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
+ ASSERT_NE(nullptr, prim);
+ EXPECT_EQ(321u, prim->value.data);
+}
+
+TEST(TableProtoSerializer, SerializeFileHeader) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+
+ ResourceFile f;
+ f.config = test::parseConfigOrDie("hdpi-v9");
+ f.name = test::parseNameOrDie(u"@com.app.a:layout/main");
+ f.source.path = "res/layout-hdpi-v9/main.xml";
+ f.exportedSymbols.push_back(SourcedResourceName{ test::parseNameOrDie(u"@+id/unchecked"), 23u });
+
+ const std::string expectedData = "1234";
+
+ std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
+
+ std::string outputStr;
+ {
+ google::protobuf::io::StringOutputStream outStream(&outputStr);
+ CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
+
+ ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
+ ASSERT_TRUE(outFileStream.Finish());
+ }
+
+ CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
+ const pb::CompiledFile* newPbFile = inFileStream.CompiledFile();
+ ASSERT_NE(nullptr, newPbFile);
+
+ std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(*newPbFile, Source{ "test" },
+ context->getDiagnostics());
+ ASSERT_NE(nullptr, file);
+
+ std::string actualData((const char*)inFileStream.data(), inFileStream.size());
+ EXPECT_EQ(expectedData, actualData);
+ EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(inFileStream.data()) & 0x03);
+
+ ASSERT_EQ(1u, file->exportedSymbols.size());
+ EXPECT_EQ(test::parseNameOrDie(u"@+id/unchecked"), file->exportedSymbols[0].name);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
new file mode 100644
index 000000000000..0f7649bac157
--- /dev/null
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -0,0 +1,264 @@
+/*
+ * 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 "ConfigDescription.h"
+#include "ResourceTable.h"
+#include "split/TableSplitter.h"
+
+#include <map>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+namespace aapt {
+
+using ConfigClaimedMap = std::unordered_map<ResourceConfigValue*, bool>;
+using ConfigDensityGroups = std::map<ConfigDescription, std::vector<ResourceConfigValue*>>;
+
+static ConfigDescription copyWithoutDensity(const ConfigDescription& config) {
+ ConfigDescription withoutDensity = config;
+ withoutDensity.density = 0;
+ return withoutDensity;
+}
+
+/**
+ * Selects values that match exactly the constraints given.
+ */
+class SplitValueSelector {
+public:
+ SplitValueSelector(const SplitConstraints& constraints) {
+ for (const ConfigDescription& config : constraints.configs) {
+ if (config.density == 0) {
+ mDensityIndependentConfigs.insert(config);
+ } else {
+ mDensityDependentConfigToDensityMap[copyWithoutDensity(config)] = config.density;
+ }
+ }
+ }
+
+ std::vector<ResourceConfigValue*> selectValues(const ConfigDensityGroups& densityGroups,
+ ConfigClaimedMap* claimedValues) {
+ std::vector<ResourceConfigValue*> selected;
+
+ // Select the regular values.
+ for (auto& entry : *claimedValues) {
+ // Check if the entry has a density.
+ ResourceConfigValue* configValue = entry.first;
+ if (configValue->config.density == 0 && !entry.second) {
+ // This is still available.
+ if (mDensityIndependentConfigs.find(configValue->config) !=
+ mDensityIndependentConfigs.end()) {
+ selected.push_back(configValue);
+
+ // Mark the entry as taken.
+ entry.second = true;
+ }
+ }
+ }
+
+ // Now examine the densities
+ for (auto& entry : densityGroups) {
+ // We do not care if the value is claimed, since density values can be
+ // in multiple splits.
+ const ConfigDescription& config = entry.first;
+ const std::vector<ResourceConfigValue*>& relatedValues = entry.second;
+
+ auto densityValueIter = mDensityDependentConfigToDensityMap.find(config);
+ if (densityValueIter != mDensityDependentConfigToDensityMap.end()) {
+ // Select the best one!
+ ConfigDescription targetDensity = config;
+ targetDensity.density = densityValueIter->second;
+
+ ResourceConfigValue* bestValue = nullptr;
+ for (ResourceConfigValue* thisValue : relatedValues) {
+ if (!bestValue ||
+ thisValue->config.isBetterThan(bestValue->config, &targetDensity)) {
+ bestValue = thisValue;
+ }
+
+ // When we select one of these, they are all claimed such that the base
+ // doesn't include any anymore.
+ (*claimedValues)[thisValue] = true;
+ }
+ assert(bestValue);
+ selected.push_back(bestValue);
+ }
+ }
+ return selected;
+ }
+
+private:
+ std::set<ConfigDescription> mDensityIndependentConfigs;
+ std::map<ConfigDescription, uint16_t> mDensityDependentConfigToDensityMap;
+};
+
+/**
+ * Marking non-preferred densities as claimed will make sure the base doesn't include them,
+ * leaving only the preferred density behind.
+ */
+static void markNonPreferredDensitiesAsClaimed(uint16_t preferredDensity,
+ const ConfigDensityGroups& densityGroups,
+ ConfigClaimedMap* configClaimedMap) {
+ for (auto& entry : densityGroups) {
+ const ConfigDescription& config = entry.first;
+ const std::vector<ResourceConfigValue*>& relatedValues = entry.second;
+
+ ConfigDescription targetDensity = config;
+ targetDensity.density = preferredDensity;
+ ResourceConfigValue* bestValue = nullptr;
+ for (ResourceConfigValue* thisValue : relatedValues) {
+ if (!bestValue) {
+ bestValue = thisValue;
+ } else if (thisValue->config.isBetterThan(bestValue->config, &targetDensity)) {
+ // Claim the previous value so that it is not included in the base.
+ (*configClaimedMap)[bestValue] = true;
+ bestValue = thisValue;
+ } else {
+ // Claim this value so that it is not included in the base.
+ (*configClaimedMap)[thisValue] = true;
+ }
+ }
+ assert(bestValue);
+ }
+}
+
+bool TableSplitter::verifySplitConstraints(IAaptContext* context) {
+ bool error = false;
+ for (size_t i = 0; i < mSplitConstraints.size(); i++) {
+ for (size_t j = i + 1; j < mSplitConstraints.size(); j++) {
+ for (const ConfigDescription& config : mSplitConstraints[i].configs) {
+ if (mSplitConstraints[j].configs.find(config) !=
+ mSplitConstraints[j].configs.end()) {
+ context->getDiagnostics()->error(DiagMessage() << "config '" << config
+ << "' appears in multiple splits, "
+ << "target split ambiguous");
+ error = true;
+ }
+ }
+ }
+ }
+ return !error;
+}
+
+void TableSplitter::splitTable(ResourceTable* originalTable) {
+ const size_t splitCount = mSplitConstraints.size();
+ for (auto& pkg : originalTable->packages) {
+ // Initialize all packages for splits.
+ for (size_t idx = 0; idx < splitCount; idx++) {
+ ResourceTable* splitTable = mSplits[idx].get();
+ splitTable->createPackage(pkg->name, pkg->id);
+ }
+
+ for (auto& type : pkg->types) {
+ if (type->type == ResourceType::kMipmap) {
+ // Always keep mipmaps.
+ continue;
+ }
+
+ for (auto& entry : type->entries) {
+ if (mConfigFilter) {
+ // First eliminate any resource that we definitely don't want.
+ for (std::unique_ptr<ResourceConfigValue>& configValue : entry->values) {
+ if (!mConfigFilter->match(configValue->config)) {
+ // null out the entry. We will clean up and remove nulls at the end
+ // for performance reasons.
+ configValue.reset();
+ }
+ }
+ }
+
+ // Organize the values into two separate buckets. Those that are density-dependent
+ // and those that are density-independent.
+ // One density technically matches all density, it's just that some densities
+ // match better. So we need to be aware of the full set of densities to make this
+ // decision.
+ ConfigDensityGroups densityGroups;
+ ConfigClaimedMap configClaimedMap;
+ for (const std::unique_ptr<ResourceConfigValue>& configValue : entry->values) {
+ if (configValue) {
+ configClaimedMap[configValue.get()] = false;
+
+ if (configValue->config.density != 0) {
+ // Create a bucket for this density-dependent config.
+ densityGroups[copyWithoutDensity(configValue->config)]
+ .push_back(configValue.get());
+ }
+ }
+ }
+
+ // First we check all the splits. If it doesn't match one of the splits, we
+ // leave it in the base.
+ for (size_t idx = 0; idx < splitCount; idx++) {
+ const SplitConstraints& splitConstraint = mSplitConstraints[idx];
+ ResourceTable* splitTable = mSplits[idx].get();
+
+ // Select the values we want from this entry for this split.
+ SplitValueSelector selector(splitConstraint);
+ std::vector<ResourceConfigValue*> selectedValues =
+ selector.selectValues(densityGroups, &configClaimedMap);
+
+ // No need to do any work if we selected nothing.
+ if (!selectedValues.empty()) {
+ // Create the same resource structure in the split. We do this lazily
+ // because we might not have actual values for each type/entry.
+ ResourceTablePackage* splitPkg = splitTable->findPackage(pkg->name);
+ ResourceTableType* splitType = splitPkg->findOrCreateType(type->type);
+ if (!splitType->id) {
+ splitType->id = type->id;
+ splitType->symbolStatus = type->symbolStatus;
+ }
+
+ ResourceEntry* splitEntry = splitType->findOrCreateEntry(entry->name);
+ if (!splitEntry->id) {
+ splitEntry->id = entry->id;
+ splitEntry->symbolStatus = entry->symbolStatus;
+ }
+
+ // Copy the selected values into the new Split Entry.
+ for (ResourceConfigValue* configValue : selectedValues) {
+ ResourceConfigValue* newConfigValue = splitEntry->findOrCreateValue(
+ configValue->config, configValue->product);
+ newConfigValue->value = std::unique_ptr<Value>(
+ configValue->value->clone(&splitTable->stringPool));
+ }
+ }
+ }
+
+ if (mPreferredDensity) {
+ markNonPreferredDensitiesAsClaimed(mPreferredDensity.value(),
+ densityGroups,
+ &configClaimedMap);
+ }
+
+ // All splits are handled, now check to see what wasn't claimed and remove
+ // whatever exists in other splits.
+ for (std::unique_ptr<ResourceConfigValue>& configValue : entry->values) {
+ if (configValue && configClaimedMap[configValue.get()]) {
+ // Claimed, remove from base.
+ configValue.reset();
+ }
+ }
+
+ // Now erase all nullptrs.
+ entry->values.erase(
+ std::remove(entry->values.begin(), entry->values.end(), nullptr),
+ entry->values.end());
+ }
+ }
+ }
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/split/TableSplitter.h b/tools/aapt2/split/TableSplitter.h
new file mode 100644
index 000000000000..15e0764c4259
--- /dev/null
+++ b/tools/aapt2/split/TableSplitter.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SPLIT_TABLESPLITTER_H
+#define AAPT_SPLIT_TABLESPLITTER_H
+
+#include "ConfigDescription.h"
+#include "ResourceTable.h"
+#include "filter/ConfigFilter.h"
+#include "process/IResourceTableConsumer.h"
+
+#include <android-base/macros.h>
+#include <set>
+#include <vector>
+
+namespace aapt {
+
+struct SplitConstraints {
+ std::set<ConfigDescription> configs;
+};
+
+struct TableSplitterOptions {
+ /**
+ * The preferred density to keep in the table, stripping out all others.
+ */
+ Maybe<uint16_t> preferredDensity;
+
+ /**
+ * Configuration filter that determines which resource configuration values end up in
+ * the final table.
+ */
+ IConfigFilter* configFilter = nullptr;
+};
+
+class TableSplitter {
+public:
+ TableSplitter(const std::vector<SplitConstraints>& splits,
+ const TableSplitterOptions& options) :
+ mSplitConstraints(splits), mPreferredDensity(options.preferredDensity),
+ mConfigFilter(options.configFilter) {
+ for (size_t i = 0; i < mSplitConstraints.size(); i++) {
+ mSplits.push_back(util::make_unique<ResourceTable>());
+ }
+ }
+
+ bool verifySplitConstraints(IAaptContext* context);
+
+ void splitTable(ResourceTable* originalTable);
+
+ const std::vector<std::unique_ptr<ResourceTable>>& getSplits() {
+ return mSplits;
+ }
+
+private:
+ std::vector<SplitConstraints> mSplitConstraints;
+ std::vector<std::unique_ptr<ResourceTable>> mSplits;
+ Maybe<uint16_t> mPreferredDensity;
+ IConfigFilter* mConfigFilter;
+
+ DISALLOW_COPY_AND_ASSIGN(TableSplitter);
+};
+
+}
+
+#endif /* AAPT_SPLIT_TABLESPLITTER_H */
diff --git a/tools/aapt2/split/TableSplitter_test.cpp b/tools/aapt2/split/TableSplitter_test.cpp
new file mode 100644
index 000000000000..74ca32e04a30
--- /dev/null
+++ b/tools/aapt2/split/TableSplitter_test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 "split/TableSplitter.h"
+#include "test/Builders.h"
+#include "test/Common.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(TableSplitterTest, NoSplitPreferredDensity) {
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .addFileReference(u"@android:drawable/icon", u"res/drawable-mdpi/icon.png",
+ test::parseConfigOrDie("mdpi"))
+ .addFileReference(u"@android:drawable/icon", u"res/drawable-hdpi/icon.png",
+ test::parseConfigOrDie("hdpi"))
+ .addFileReference(u"@android:drawable/icon", u"res/drawable-xhdpi/icon.png",
+ test::parseConfigOrDie("xhdpi"))
+ .addFileReference(u"@android:drawable/icon", u"res/drawable-xxhdpi/icon.png",
+ test::parseConfigOrDie("xxhdpi"))
+ .addSimple(u"@android:string/one", {})
+ .build();
+
+ TableSplitterOptions options;
+ options.preferredDensity = ConfigDescription::DENSITY_XHIGH;
+ TableSplitter splitter({}, options);
+ splitter.splitTable(table.get());
+
+ EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(table.get(),
+ u"@android:drawable/icon",
+ test::parseConfigOrDie("mdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(table.get(),
+ u"@android:drawable/icon",
+ test::parseConfigOrDie("hdpi")));
+ EXPECT_NE(nullptr, test::getValueForConfig<FileReference>(table.get(),
+ u"@android:drawable/icon",
+ test::parseConfigOrDie("xhdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<FileReference>(table.get(),
+ u"@android:drawable/icon",
+ test::parseConfigOrDie("xxhdpi")));
+ EXPECT_NE(nullptr, test::getValue<Id>(table.get(), u"@android:string/one"));
+}
+
+TEST(TableSplitterTest, SplitTableByConfigAndDensity) {
+ ResourceTable table;
+
+ const ResourceName foo = test::parseNameOrDie(u"@android:string/foo");
+ ASSERT_TRUE(table.addResource(foo, test::parseConfigOrDie("land-hdpi"), {},
+ util::make_unique<Id>(),
+ test::getDiagnostics()));
+ ASSERT_TRUE(table.addResource(foo, test::parseConfigOrDie("land-xhdpi"), {},
+ util::make_unique<Id>(),
+ test::getDiagnostics()));
+ ASSERT_TRUE(table.addResource(foo, test::parseConfigOrDie("land-xxhdpi"), {},
+ util::make_unique<Id>(),
+ test::getDiagnostics()));
+
+ std::vector<SplitConstraints> constraints;
+ constraints.push_back(SplitConstraints{ { test::parseConfigOrDie("land-mdpi") } });
+ constraints.push_back(SplitConstraints{ { test::parseConfigOrDie("land-xhdpi") } });
+
+ TableSplitter splitter(constraints, TableSplitterOptions{});
+ splitter.splitTable(&table);
+
+ ASSERT_EQ(2u, splitter.getSplits().size());
+
+ ResourceTable* splitOne = splitter.getSplits()[0].get();
+ ResourceTable* splitTwo = splitter.getSplits()[1].get();
+
+ // Since a split was defined, all densities should be gone from base.
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, u"@android:string/foo",
+ test::parseConfigOrDie("land-hdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, u"@android:string/foo",
+ test::parseConfigOrDie("land-xhdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(&table, u"@android:string/foo",
+ test::parseConfigOrDie("land-xxhdpi")));
+
+ EXPECT_NE(nullptr, test::getValueForConfig<Id>(splitOne, u"@android:string/foo",
+ test::parseConfigOrDie("land-hdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitOne, u"@android:string/foo",
+ test::parseConfigOrDie("land-xhdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitOne, u"@android:string/foo",
+ test::parseConfigOrDie("land-xxhdpi")));
+
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitTwo, u"@android:string/foo",
+ test::parseConfigOrDie("land-hdpi")));
+ EXPECT_NE(nullptr, test::getValueForConfig<Id>(splitTwo, u"@android:string/foo",
+ test::parseConfigOrDie("land-xhdpi")));
+ EXPECT_EQ(nullptr, test::getValueForConfig<Id>(splitTwo, u"@android:string/foo",
+ test::parseConfigOrDie("land-xxhdpi")));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 579a46ec230f..834caf8b9a49 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -104,8 +104,8 @@ public:
const ConfigDescription& config,
std::unique_ptr<Value> value) {
ResourceName resName = parseNameOrDie(name);
- bool result = mTable->addResourceAllowMangled(resName, id, config, std::move(value),
- &mDiagnostics);
+ bool result = mTable->addResourceAllowMangled(resName, id, config, std::string(),
+ std::move(value), &mDiagnostics);
assert(result);
return *this;
}
@@ -132,6 +132,14 @@ inline std::unique_ptr<Reference> buildReference(const StringPiece16& ref,
return reference;
}
+inline std::unique_ptr<BinaryPrimitive> buildPrimitive(uint8_t type, uint32_t data) {
+ android::Res_value value = {};
+ value.size = sizeof(value);
+ value.dataType = type;
+ value.data = data;
+ return util::make_unique<BinaryPrimitive>(value);
+}
+
template <typename T>
class ValueBuilder {
private:
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 51e2dd44e521..348c32a04e88 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -52,6 +52,11 @@ struct DummyDiagnosticsImpl : public IDiagnostics {
void note(const DiagMessage& message) override {}
};
+inline IDiagnostics* getDiagnostics() {
+ static DummyDiagnosticsImpl diag;
+ return &diag;
+}
+
inline ResourceName parseNameOrDie(const StringPiece16& str) {
ResourceNameRef ref;
bool result = ResourceUtils::tryParseReference(str, &ref);
@@ -66,23 +71,25 @@ inline ConfigDescription parseConfigOrDie(const StringPiece& str) {
return config;
}
-template <typename T> T* getValueForConfig(ResourceTable* table, const StringPiece16& resName,
- const ConfigDescription& config) {
+template <typename T> T* getValueForConfigAndProduct(ResourceTable* table,
+ const StringPiece16& resName,
+ const ConfigDescription& config,
+ const StringPiece& product) {
Maybe<ResourceTable::SearchResult> result = table->findResource(parseNameOrDie(resName));
if (result) {
- ResourceEntry* entry = result.value().entry;
- auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), config,
- [](const ResourceConfigValue& a, const ConfigDescription& b)
- -> bool {
- return a.config < b;
- });
- if (iter != entry->values.end() && iter->config == config) {
- return valueCast<T>(iter->value.get());
+ ResourceConfigValue* configValue = result.value().entry->findValue(config, product);
+ if (configValue) {
+ return valueCast<T>(configValue->value.get());
}
}
return nullptr;
}
+template <typename T> T* getValueForConfig(ResourceTable* table, const StringPiece16& resName,
+ const ConfigDescription& config) {
+ return getValueForConfigAndProduct<T>(table, resName, config, {});
+}
+
template <typename T> T* getValue(ResourceTable* table, const StringPiece16& resName) {
return getValueForConfig<T>(table, resName, {});
}
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 555a53959737..e540cd7ace90 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -71,6 +71,10 @@ public:
assert(mNameMangler && "test name mangler not set");
return mNameMangler.get();
}
+
+ bool verbose() override {
+ return false;
+ }
};
class ContextBuilder {
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 6b7a63cf7bf2..33b505ed2eb4 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -19,8 +19,6 @@
#include "ResourceValues.h"
#include "Source.h"
#include "ValueVisitor.h"
-
-#include "flatten/ResourceTypeExtensions.h"
#include "unflatten/BinaryResourceParser.h"
#include "unflatten/ResChunkPullParser.h"
#include "util/Util.h"
@@ -36,6 +34,8 @@ namespace aapt {
using namespace android;
+namespace {
+
/*
* Visitor that converts a reference's resource ID to a resource name,
* given a mapping from resource ID to resource name.
@@ -66,6 +66,8 @@ public:
}
};
+} // namespace
+
BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table,
const Source& source, const void* data, size_t len) :
mContext(context), mTable(table), mSource(source), mData(data), mDataLen(len) {
@@ -97,106 +99,6 @@ bool BinaryResourceParser::parse() {
return !error;
}
-Maybe<Reference> BinaryResourceParser::getSymbol(const void* data) {
- if (!mSymbolEntries || mSymbolEntryCount == 0) {
- return {};
- }
-
- if ((uintptr_t) data < (uintptr_t) mData) {
- return {};
- }
-
- // We only support 32 bit offsets right now.
- const uintptr_t offset = (uintptr_t) data - (uintptr_t) mData;
- if (offset > std::numeric_limits<uint32_t>::max()) {
- return {};
- }
-
- for (size_t i = 0; i < mSymbolEntryCount; i++) {
- if (util::deviceToHost32(mSymbolEntries[i].offset) == offset) {
- // This offset is a symbol!
- const StringPiece16 str = util::getString(
- mSymbolPool, util::deviceToHost32(mSymbolEntries[i].name.index));
-
- ResourceNameRef nameRef;
- bool privateRef = false;
- if (!ResourceUtils::parseResourceName(str, &nameRef, &privateRef)) {
- return {};
- }
-
- // Since we scan the symbol table in order, we can start looking for the
- // next symbol from this point.
- mSymbolEntryCount -= i + 1;
- mSymbolEntries += i + 1;
-
- Reference ref(nameRef);
- ref.privateReference = privateRef;
- return Maybe<Reference>(std::move(ref));
- }
- }
- return {};
-}
-
-/**
- * Parses the SymbolTable_header, which is present on non-final resource tables
- * after the compile phase.
- *
- * | SymbolTable_header |
- * |--------------------|
- * |SymbolTable_entry 0 |
- * |SymbolTable_entry 1 |
- * | ... |
- * |SymbolTable_entry n |
- * |--------------------|
- *
- */
-bool BinaryResourceParser::parseSymbolTable(const ResChunk_header* chunk) {
- const SymbolTable_header* header = convertTo<SymbolTable_header>(chunk);
- if (!header) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "corrupt SymbolTable_header");
- return false;
- }
-
- const uint32_t entrySizeBytes =
- util::deviceToHost32(header->count) * sizeof(SymbolTable_entry);
- if (entrySizeBytes > getChunkDataLen(&header->header)) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "SymbolTable_header data section too long");
- return false;
- }
-
- mSymbolEntries = (const SymbolTable_entry*) getChunkData(&header->header);
- mSymbolEntryCount = util::deviceToHost32(header->count);
-
- // Skip over the symbol entries and parse the StringPool chunk that should be next.
- ResChunkPullParser parser(getChunkData(&header->header) + entrySizeBytes,
- getChunkDataLen(&header->header) - entrySizeBytes);
- if (!ResChunkPullParser::isGoodEvent(parser.next())) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "failed to parse chunk in SymbolTable: "
- << parser.getLastError());
- return false;
- }
-
- const ResChunk_header* nextChunk = parser.getChunk();
- if (util::deviceToHost16(nextChunk->type) != android::RES_STRING_POOL_TYPE) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "expected string pool in SymbolTable but got "
- << "chunk of type "
- << (int) util::deviceToHost16(nextChunk->type));
- return false;
- }
-
- if (mSymbolPool.setTo(nextChunk, util::deviceToHost32(nextChunk->size)) != NO_ERROR) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "corrupt string pool in SymbolTable: "
- << mSymbolPool.getError());
- return false;
- }
- return true;
-}
-
/**
* Parses the resource table, which contains all the packages, types, and entries.
*/
@@ -230,24 +132,6 @@ bool BinaryResourceParser::parseTable(const ResChunk_header* chunk) {
}
break;
- case RES_TABLE_SYMBOL_TABLE_TYPE:
- if (!parseSymbolTable(parser.getChunk())) {
- return false;
- }
- break;
-
- case RES_TABLE_SOURCE_POOL_TYPE: {
- status_t err = mSourcePool.setTo(getChunkData(parser.getChunk()),
- getChunkDataLen(parser.getChunk()));
- if (err != NO_ERROR) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "corrupt source string pool in ResTable: "
- << mSourcePool.getError());
- return false;
- }
- break;
- }
-
case android::RES_TABLE_PACKAGE_TYPE:
if (!parsePackage(parser.getChunk())) {
return false;
@@ -350,12 +234,6 @@ bool BinaryResourceParser::parsePackage(const ResChunk_header* chunk) {
}
break;
- case RES_TABLE_PUBLIC_TYPE:
- if (!parsePublic(package, parser.getChunk())) {
- return false;
- }
- break;
-
default:
mContext->getDiagnostics()
->warn(DiagMessage(mSource)
@@ -375,97 +253,7 @@ bool BinaryResourceParser::parsePackage(const ResChunk_header* chunk) {
// Now go through the table and change local resource ID references to
// symbolic references.
ReferenceIdToNameVisitor visitor(&mIdIndex);
- for (auto& package : mTable->packages) {
- for (auto& type : package->types) {
- for (auto& entry : type->entries) {
- for (auto& configValue : entry->values) {
- configValue.value->accept(&visitor);
- }
- }
- }
- }
- return true;
-}
-
-bool BinaryResourceParser::parsePublic(const ResourceTablePackage* package,
- const ResChunk_header* chunk) {
- const Public_header* header = convertTo<Public_header>(chunk);
- if (!header) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "corrupt Public_header chunk");
- return false;
- }
-
- if (header->typeId == 0) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "invalid type ID "
- << (int) header->typeId);
- return false;
- }
-
- StringPiece16 typeStr16 = util::getString(mTypePool, header->typeId - 1);
- const ResourceType* parsedType = parseResourceType(typeStr16);
- if (!parsedType) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "invalid type '" << typeStr16 << "'");
- return false;
- }
-
- const uintptr_t chunkEnd = (uintptr_t) chunk + util::deviceToHost32(chunk->size);
- const Public_entry* entry = (const Public_entry*) getChunkData(&header->header);
- for (uint32_t i = 0; i < util::deviceToHost32(header->count); i++) {
- if ((uintptr_t) entry + sizeof(*entry) > chunkEnd) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "Public_entry data section is too long");
- return false;
- }
-
- const ResourceId resId(package->id.value(), header->typeId,
- util::deviceToHost16(entry->entryId));
-
- const ResourceName name(package->name, *parsedType,
- util::getString(mKeyPool, entry->key.index).toString());
-
- Symbol symbol;
- if (mSourcePool.getError() == NO_ERROR) {
- symbol.source.path = util::utf16ToUtf8(util::getString(
- mSourcePool, util::deviceToHost32(entry->source.path.index)));
- symbol.source.line = util::deviceToHost32(entry->source.line);
- }
-
- StringPiece16 comment = util::getString(mSourcePool,
- util::deviceToHost32(entry->source.comment.index));
- if (!comment.empty()) {
- symbol.comment = comment.toString();
- }
-
- switch (util::deviceToHost16(entry->state)) {
- case Public_entry::kPrivate:
- symbol.state = SymbolState::kPrivate;
- break;
-
- case Public_entry::kPublic:
- symbol.state = SymbolState::kPublic;
- break;
-
- case Public_entry::kUndefined:
- symbol.state = SymbolState::kUndefined;
- break;
- }
-
- if (!mTable->setSymbolStateAllowMangled(name, resId, symbol, mContext->getDiagnostics())) {
- return false;
- }
-
- // Add this resource name->id mapping to the index so
- // that we can resolve all ID references to name references.
- auto cacheIter = mIdIndex.find(resId);
- if (cacheIter == mIdIndex.end()) {
- mIdIndex.insert({ resId, name });
- }
-
- entry++;
- }
+ visitAllValuesInTable(mTable, &visitor);
return true;
}
@@ -545,25 +333,12 @@ bool BinaryResourceParser::parseType(const ResourceTablePackage* package,
const ResourceId resId(package->id.value(), type->id, static_cast<uint16_t>(it.index()));
std::unique_ptr<Value> resourceValue;
- const ResTable_entry_source* sourceBlock = nullptr;
-
if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
- if (util::deviceToHost32(mapEntry->size) - sizeof(*mapEntry) == sizeof(*sourceBlock)) {
- const uint8_t* data = (const uint8_t*) mapEntry;
- data += util::deviceToHost32(mapEntry->size) - sizeof(*sourceBlock);
- sourceBlock = (const ResTable_entry_source*) data;
- }
// TODO(adamlesinski): Check that the entry count is valid.
resourceValue = parseMapEntry(name, config, mapEntry);
} else {
- if (util::deviceToHost32(entry->size) - sizeof(*entry) == sizeof(*sourceBlock)) {
- const uint8_t* data = (const uint8_t*) entry;
- data += util::deviceToHost32(entry->size) - sizeof(*sourceBlock);
- sourceBlock = (const ResTable_entry_source*) data;
- }
-
const Res_value* value = (const Res_value*)(
(const uint8_t*) entry + util::deviceToHost32(entry->size));
resourceValue = parseValue(name, config, value, entry->flags);
@@ -577,31 +352,7 @@ bool BinaryResourceParser::parseType(const ResourceTablePackage* package,
return false;
}
- Source source = mSource;
- if (sourceBlock) {
- StringPiece path = util::getString8(mSourcePool,
- util::deviceToHost32(sourceBlock->path.index));
- if (!path.empty()) {
- source.path = path.toString();
- }
- source.line = util::deviceToHost32(sourceBlock->line);
-
- if (Style* style = valueCast<Style>(resourceValue.get())) {
- // The parent's source is the same as the resource itself, set it here.
- if (style->parent) {
- style->parent.value().setSource(source);
- }
- }
- }
-
- StringPiece16 comment = util::getString(mSourcePool,
- util::deviceToHost32(sourceBlock->comment.index));
- if (!comment.empty()) {
- resourceValue->setComment(comment);
- }
-
- resourceValue->setSource(source);
- if (!mTable->addResourceAllowMangled(name, config, std::move(resourceValue),
+ if (!mTable->addResourceAllowMangled(name, config, {}, std::move(resourceValue),
mContext->getDiagnostics())) {
return false;
}
@@ -674,26 +425,15 @@ std::unique_ptr<Item> BinaryResourceParser::parseValue(const ResourceNameRef& na
const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE) ?
Reference::Type::kResource : Reference::Type::kAttribute;
- if (data != 0) {
- // This is a normal reference.
- return util::make_unique<Reference>(data, type);
- }
-
- // This reference has an invalid ID. Check if it is an unresolved symbol.
- if (Maybe<Reference> ref = getSymbol(&value->data)) {
- ref.value().referenceType = type;
- return util::make_unique<Reference>(std::move(ref.value()));
+ if (data == 0) {
+ // A reference of 0, must be the magic @null reference.
+ Res_value nullType = {};
+ nullType.dataType = Res_value::TYPE_REFERENCE;
+ return util::make_unique<BinaryPrimitive>(nullType);
}
- // This is not an unresolved symbol, so it must be the magic @null reference.
- Res_value nullType = {};
- nullType.dataType = Res_value::TYPE_REFERENCE;
- return util::make_unique<BinaryPrimitive>(nullType);
- }
-
- if (value->dataType == ExtendedTypes::TYPE_RAW_STRING) {
- return util::make_unique<RawString>(mTable->stringPool.makeRef(
- util::getString(mValuePool, data), StringPool::Context{ 1, config }));
+ // This is a normal reference.
+ return util::make_unique<Reference>(data, type);
}
// Treat this as a raw binary primitive.
@@ -712,8 +452,6 @@ std::unique_ptr<Value> BinaryResourceParser::parseMapEntry(const ResourceNameRef
return parseAttr(name, config, map);
case ResourceType::kArray:
return parseArray(name, config, map);
- case ResourceType::kStyleable:
- return parseStyleable(name, config, map);
case ResourceType::kPlurals:
return parsePlural(name, config, map);
default:
@@ -727,51 +465,23 @@ std::unique_ptr<Style> BinaryResourceParser::parseStyle(const ResourceNameRef& n
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Style> style = util::make_unique<Style>();
- if (util::deviceToHost32(map->parent.ident) == 0) {
- // The parent is either not set or it is an unresolved symbol.
- // Check to see if it is a symbol.
- style->parent = getSymbol(&map->parent.ident);
-
- } else {
- // The parent is a regular reference to a resource.
+ if (util::deviceToHost32(map->parent.ident) != 0) {
+ // The parent is a regular reference to a resource.
style->parent = Reference(util::deviceToHost32(map->parent.ident));
}
for (const ResTable_map& mapEntry : map) {
if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) {
- if (style->entries.empty()) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "out-of-sequence meta data in style");
- return {};
- }
- collectMetaData(mapEntry, &style->entries.back().key);
continue;
}
- style->entries.emplace_back();
- Style::Entry& styleEntry = style->entries.back();
-
- if (util::deviceToHost32(mapEntry.name.ident) == 0) {
- // The map entry's key (attribute) is not set. This must be
- // a symbol reference, so resolve it.
- Maybe<Reference> symbol = getSymbol(&mapEntry.name.ident);
- if (!symbol) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "unresolved style attribute");
- return {};
- }
- styleEntry.key = std::move(symbol.value());
-
- } else {
- // The map entry's key (attribute) is a regular reference.
- styleEntry.key.id = ResourceId(util::deviceToHost32(mapEntry.name.ident));
- }
-
- // Parse the attribute's value.
+ Style::Entry styleEntry;
+ styleEntry.key = Reference(util::deviceToHost32(mapEntry.name.ident));
styleEntry.value = parseValue(name, config, &mapEntry.value, 0);
if (!styleEntry.value) {
return {};
}
+ style->entries.push_back(std::move(styleEntry));
}
return style;
}
@@ -807,22 +517,7 @@ std::unique_ptr<Attribute> BinaryResourceParser::parseAttr(const ResourceNameRef
if (attr->typeMask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Attribute::Symbol symbol;
symbol.value = util::deviceToHost32(mapEntry.value.data);
- if (util::deviceToHost32(mapEntry.name.ident) == 0) {
- // The map entry's key (id) is not set. This must be
- // a symbol reference, so resolve it.
- Maybe<Reference> ref = getSymbol(&mapEntry.name.ident);
- if (!ref) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "unresolved attribute symbol");
- return {};
- }
- symbol.symbol = std::move(ref.value());
-
- } else {
- // The map entry's key (id) is a regular reference.
- symbol.symbol.id = ResourceId(util::deviceToHost32(mapEntry.name.ident));
- }
-
+ symbol.symbol = Reference(util::deviceToHost32(mapEntry.name.ident));
attr->symbols.push_back(std::move(symbol));
}
}
@@ -831,115 +526,26 @@ std::unique_ptr<Attribute> BinaryResourceParser::parseAttr(const ResourceNameRef
return attr;
}
-static bool isMetaDataEntry(const ResTable_map& mapEntry) {
- switch (util::deviceToHost32(mapEntry.name.ident)) {
- case ExtendedResTableMapTypes::ATTR_SOURCE_PATH:
- case ExtendedResTableMapTypes::ATTR_SOURCE_LINE:
- case ExtendedResTableMapTypes::ATTR_COMMENT:
- return true;
- }
- return false;
-}
-
-bool BinaryResourceParser::collectMetaData(const ResTable_map& mapEntry, Value* value) {
- switch (util::deviceToHost32(mapEntry.name.ident)) {
- case ExtendedResTableMapTypes::ATTR_SOURCE_PATH:
- value->setSource(Source(util::getString8(mSourcePool,
- util::deviceToHost32(mapEntry.value.data))));
- return true;
- break;
-
- case ExtendedResTableMapTypes::ATTR_SOURCE_LINE:
- value->setSource(value->getSource().withLine(util::deviceToHost32(mapEntry.value.data)));
- return true;
- break;
-
- case ExtendedResTableMapTypes::ATTR_COMMENT:
- value->setComment(util::getString(mSourcePool, util::deviceToHost32(mapEntry.value.data)));
- return true;
- break;
- }
- return false;
-}
-
std::unique_ptr<Array> BinaryResourceParser::parseArray(const ResourceNameRef& name,
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Array> array = util::make_unique<Array>();
- Source source;
for (const ResTable_map& mapEntry : map) {
- if (isMetaDataEntry(mapEntry)) {
- if (array->items.empty()) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "out-of-sequence meta data in array");
- return {};
- }
- collectMetaData(mapEntry, array->items.back().get());
- continue;
- }
-
array->items.push_back(parseValue(name, config, &mapEntry.value, 0));
}
return array;
}
-std::unique_ptr<Styleable> BinaryResourceParser::parseStyleable(const ResourceNameRef& name,
- const ConfigDescription& config,
- const ResTable_map_entry* map) {
- std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
- for (const ResTable_map& mapEntry : map) {
- if (isMetaDataEntry(mapEntry)) {
- if (styleable->entries.empty()) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "out-of-sequence meta data in styleable");
- return {};
- }
- collectMetaData(mapEntry, &styleable->entries.back());
- continue;
- }
-
- if (util::deviceToHost32(mapEntry.name.ident) == 0) {
- // The map entry's key (attribute) is not set. This must be
- // a symbol reference, so resolve it.
- Maybe<Reference> ref = getSymbol(&mapEntry.name.ident);
- if (!ref) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "unresolved styleable symbol");
- return {};
- }
- styleable->entries.emplace_back(std::move(ref.value()));
-
- } else {
- // The map entry's key (attribute) is a regular reference.
- styleable->entries.emplace_back(util::deviceToHost32(mapEntry.name.ident));
- }
- }
- return styleable;
-}
-
std::unique_ptr<Plural> BinaryResourceParser::parsePlural(const ResourceNameRef& name,
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
- Item* lastEntry = nullptr;
for (const ResTable_map& mapEntry : map) {
- if (isMetaDataEntry(mapEntry)) {
- if (!lastEntry) {
- mContext->getDiagnostics()->error(DiagMessage(mSource)
- << "out-of-sequence meta data in plural");
- return {};
- }
- collectMetaData(mapEntry, lastEntry);
- continue;
- }
-
std::unique_ptr<Item> item = parseValue(name, config, &mapEntry.value, 0);
if (!item) {
return {};
}
- lastEntry = item.get();
-
switch (util::deviceToHost32(mapEntry.name.ident)) {
case ResTable_map::ATTR_ZERO:
plural->values[Plural::Zero] = std::move(item);
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.h b/tools/aapt2/unflatten/BinaryResourceParser.h
index 0745a592c296..12bc13db38f2 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.h
+++ b/tools/aapt2/unflatten/BinaryResourceParser.h
@@ -55,14 +55,8 @@ public:
bool parse();
private:
- // Helper method to retrieve the symbol name for a given table offset specified
- // as a pointer.
- Maybe<Reference> getSymbol(const void* data);
-
bool parseTable(const android::ResChunk_header* chunk);
- bool parseSymbolTable(const android::ResChunk_header* chunk);
bool parsePackage(const android::ResChunk_header* chunk);
- bool parsePublic(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
bool parseTypeSpec(const android::ResChunk_header* chunk);
bool parseType(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
@@ -87,10 +81,6 @@ private:
const ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Styleable> parseStyleable(const ResourceNameRef& name,
- const ConfigDescription& config,
- const android::ResTable_map_entry* map);
-
/**
* If the mapEntry is a special type that denotes meta data (source, comment), then it is
* read and added to the Value.
@@ -106,23 +96,6 @@ private:
const void* mData;
const size_t mDataLen;
- // The array of symbol entries. Each element points to an offset
- // in the table and an index into the symbol table string pool.
- const SymbolTable_entry* mSymbolEntries = nullptr;
-
- // Number of symbol entries.
- size_t mSymbolEntryCount = 0;
-
- // The symbol table string pool. Holds the names of symbols
- // referenced in this table but not defined nor resolved to an
- // ID.
- android::ResStringPool mSymbolPool;
-
- // The source string pool. Resource entries may have an extra
- // field that points into this string pool, which denotes where
- // the resource was parsed from originally.
- android::ResStringPool mSourcePool;
-
// The standard value string pool for resource values.
android::ResStringPool mValuePool;
diff --git a/tools/aapt2/unflatten/FileExportHeaderReader.h b/tools/aapt2/unflatten/FileExportHeaderReader.h
deleted file mode 100644
index e552ea176417..000000000000
--- a/tools/aapt2/unflatten/FileExportHeaderReader.h
+++ /dev/null
@@ -1,159 +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.
- */
-
-#ifndef AAPT_UNFLATTEN_FILEEXPORTHEADERREADER_H
-#define AAPT_UNFLATTEN_FILEEXPORTHEADERREADER_H
-
-#include "ResChunkPullParser.h"
-#include "Resource.h"
-#include "ResourceUtils.h"
-
-#include "flatten/ResourceTypeExtensions.h"
-#include "util/StringPiece.h"
-#include "util/Util.h"
-
-#include <androidfw/ResourceTypes.h>
-#include <sstream>
-#include <string>
-
-namespace aapt {
-
-static ssize_t parseFileExportHeaderImpl(const void* data, const size_t len,
- const FileExport_header** outFileExport,
- const ExportedSymbol** outExportedSymbolIndices,
- android::ResStringPool* outStringPool,
- std::string* outError) {
- ResChunkPullParser parser(data, len);
- if (!ResChunkPullParser::isGoodEvent(parser.next())) {
- if (outError) *outError = parser.getLastError();
- return -1;
- }
-
- if (util::deviceToHost16(parser.getChunk()->type) != RES_FILE_EXPORT_TYPE) {
- if (outError) *outError = "no FileExport_header found";
- return -1;
- }
-
- const FileExport_header* fileExport = convertTo<FileExport_header>(parser.getChunk());
- if (!fileExport) {
- if (outError) *outError = "corrupt FileExport_header";
- return -1;
- }
-
- if (memcmp(fileExport->magic, "AAPT", sizeof(fileExport->magic)) != 0) {
- if (outError) *outError = "invalid magic value";
- return -1;
- }
-
- const size_t exportedSymbolCount = util::deviceToHost32(fileExport->exportedSymbolCount);
-
- // Verify that we have enough space for all those symbols.
- size_t dataLen = getChunkDataLen(&fileExport->header);
- if (exportedSymbolCount > dataLen / sizeof(ExportedSymbol)) {
- if (outError) *outError = "too many symbols";
- return -1;
- }
-
- const size_t symbolIndicesSize = exportedSymbolCount * sizeof(ExportedSymbol);
-
- const void* strPoolData = getChunkData(&fileExport->header) + symbolIndicesSize;
- const size_t strPoolDataLen = dataLen - symbolIndicesSize;
- if (outStringPool->setTo(strPoolData, strPoolDataLen, false) != android::NO_ERROR) {
- if (outError) *outError = "corrupt string pool";
- return -1;
- }
-
- *outFileExport = fileExport;
- *outExportedSymbolIndices = (const ExportedSymbol*) getChunkData(
- &fileExport->header);
- return util::deviceToHost16(fileExport->header.headerSize) + symbolIndicesSize +
- outStringPool->bytes();
-}
-
-static ssize_t getWrappedDataOffset(const void* data, size_t len, std::string* outError) {
- const FileExport_header* header = nullptr;
- const ExportedSymbol* entries = nullptr;
- android::ResStringPool pool;
- return parseFileExportHeaderImpl(data, len, &header, &entries, &pool, outError);
-}
-
-/**
- * Reads the FileExport_header and populates outRes with the values in that header.
- */
-static ssize_t unwrapFileExportHeader(const void* data, size_t len, ResourceFile* outRes,
- std::string* outError) {
-
- const FileExport_header* fileExport = nullptr;
- const ExportedSymbol* entries = nullptr;
- android::ResStringPool symbolPool;
- const ssize_t offset = parseFileExportHeaderImpl(data, len, &fileExport, &entries, &symbolPool,
- outError);
- if (offset < 0) {
- return offset;
- }
-
- const size_t exportedSymbolCount = util::deviceToHost32(fileExport->exportedSymbolCount);
- outRes->exportedSymbols.clear();
- outRes->exportedSymbols.reserve(exportedSymbolCount);
-
- for (size_t i = 0; i < exportedSymbolCount; i++) {
- const StringPiece16 str = util::getString(symbolPool,
- util::deviceToHost32(entries[i].name.index));
- StringPiece16 packageStr, typeStr, entryStr;
- ResourceUtils::extractResourceName(str, &packageStr, &typeStr, &entryStr);
- const ResourceType* resType = parseResourceType(typeStr);
- if (!resType || entryStr.empty()) {
- if (outError) {
- std::stringstream errorStr;
- errorStr << "invalid exported symbol at index="
- << util::deviceToHost32(entries[i].name.index)
- << " (" << str << ")";
- *outError = errorStr.str();
- }
- return -1;
- }
-
- outRes->exportedSymbols.push_back(SourcedResourceName{
- ResourceName{ packageStr.toString(), *resType, entryStr.toString() },
- util::deviceToHost32(entries[i].line) });
- }
-
- const StringPiece16 str = util::getString(symbolPool,
- util::deviceToHost32(fileExport->name.index));
- StringPiece16 packageStr, typeStr, entryStr;
- ResourceUtils::extractResourceName(str, &packageStr, &typeStr, &entryStr);
- const ResourceType* resType = parseResourceType(typeStr);
- if (!resType || entryStr.empty()) {
- if (outError) {
- std::stringstream errorStr;
- errorStr << "invalid resource name at index="
- << util::deviceToHost32(fileExport->name.index)
- << " (" << str << ")";
- *outError = errorStr.str();
- }
- return -1;
- }
-
- outRes->name = ResourceName{ packageStr.toString(), *resType, entryStr.toString() };
- outRes->source.path = util::utf16ToUtf8(
- util::getString(symbolPool, util::deviceToHost32(fileExport->source.index)));
- outRes->config.copyFromDtoH(fileExport->config);
- return offset;
-}
-
-} // namespace aapt
-
-#endif /* AAPT_UNFLATTEN_FILEEXPORTHEADERREADER_H */
diff --git a/tools/aapt2/unflatten/FileExportHeaderReader_test.cpp b/tools/aapt2/unflatten/FileExportHeaderReader_test.cpp
deleted file mode 100644
index a76c83bdbd9a..000000000000
--- a/tools/aapt2/unflatten/FileExportHeaderReader_test.cpp
+++ /dev/null
@@ -1,58 +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.
- */
-
-#include "Resource.h"
-
-#include "flatten/FileExportWriter.h"
-#include "unflatten/FileExportHeaderReader.h"
-#include "util/BigBuffer.h"
-#include "util/Util.h"
-
-#include "test/Common.h"
-
-#include <gtest/gtest.h>
-
-namespace aapt {
-
-TEST(FileExportHeaderReaderTest, ReadHeaderWithNoSymbolExports) {
- ResourceFile resFile = {
- test::parseNameOrDie(u"@android:layout/main.xml"),
- test::parseConfigOrDie("sw600dp-v4"),
- Source{ "res/layout/main.xml" },
- };
-
- BigBuffer buffer(1024);
- ChunkWriter writer = wrapBufferWithFileExportHeader(&buffer, &resFile);
- *writer.getBuffer()->nextBlock<uint32_t>() = 42u;
- writer.finish();
-
- std::unique_ptr<uint8_t[]> data = util::copy(buffer);
-
- ResourceFile actualResFile;
-
- ssize_t offset = unwrapFileExportHeader(data.get(), buffer.size(), &actualResFile, nullptr);
- ASSERT_GT(offset, 0);
-
- EXPECT_EQ(offset, getWrappedDataOffset(data.get(), buffer.size(), nullptr));
-
- EXPECT_EQ(actualResFile.config, test::parseConfigOrDie("sw600dp-v4"));
- EXPECT_EQ(actualResFile.name, test::parseNameOrDie(u"@android:layout/main.xml"));
- EXPECT_EQ(actualResFile.source.path, "res/layout/main.xml");
-
- EXPECT_EQ(*(uint32_t*)(data.get() + offset), 42u);
-}
-
-} // namespace aapt
diff --git a/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml b/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml
index 5bb3e3e47922..3681f2aaf3f1 100644
--- a/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml
+++ b/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<option name="myName" value="Project Default" />
@@ -8,6 +7,15 @@
<option name="CHECK_TRY_CATCH_SECTION" value="true" />
<option name="CHECK_METHOD_BODY" value="true" />
</inspection_tool>
+ <inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
+ <option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
+ </inspection_tool>
<inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="false" />
+ <option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="false" />
+ <option name="SUGGEST_PRIVATE_FOR_INNERS" value="true" />
+ </inspection_tool>
</profile>
</component> \ No newline at end of file
diff --git a/tools/layoutlib/.idea/misc.xml b/tools/layoutlib/.idea/misc.xml
index b474bdc00013..44b47f2c91d4 100644
--- a/tools/layoutlib/.idea/misc.xml
+++ b/tools/layoutlib/.idea/misc.xml
@@ -37,7 +37,7 @@
</value>
</option>
</component>
- <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project> \ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml b/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml
index 4f0eb8dc23a4..b402849f22a3 100644
--- a/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml
+++ b/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml
@@ -26,4 +26,4 @@
<ConfigurationWrapper RunnerId="Run" />
<method />
</configuration>
-</component> \ No newline at end of file
+</component>
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 53bfc1581e53..c2ad9ef65faf 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -16,7 +16,7 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
-LOCAL_JAVACFLAGS := -source 6 -target 6
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
#
# Define rules to build temp_layoutlib.jar, which contains a subset of
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 0dbdd5627e63..16e5913ab81d 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -18,8 +18,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAVA_RESOURCE_DIRS := resources
-LOCAL_JAVACFLAGS := -source 6 -target 6
-
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
LOCAL_JAVA_LIBRARIES := \
layoutlib_api-prebuilt \
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 0e392436d748..fe46480f25ab 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -49,6 +49,7 @@ import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Iterator;
+@SuppressWarnings("deprecation")
public final class BridgeResources extends Resources {
private BridgeContext mContext;
@@ -70,6 +71,7 @@ public final class BridgeResources extends Resources {
@Override
public boolean markSupported() {
+ //noinspection SimplifiableIfStatement
if (mFakeMarkSupport) {
// this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
return true;
@@ -595,7 +597,6 @@ public final class BridgeResources extends Resources {
if (value != null) {
ResourceValue resValue = value.getSecond();
- assert resValue != null;
if (resValue != null) {
String v = resValue.getValue();
if (v != null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 07376828a1fe..e3bb3e318749 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -17,9 +17,14 @@
package android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.resources.Density;
+import com.android.resources.ResourceType;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.annotation.Nullable;
@@ -38,6 +43,7 @@ import java.util.EnumSet;
import java.util.Set;
import javax.imageio.ImageIO;
+import libcore.util.NativeAllocationRegistry_Delegate;
/**
* Delegate implementing the native methods of android.graphics.Bitmap
@@ -62,12 +68,13 @@ public final class Bitmap_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Bitmap_Delegate> sManager =
new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
+ private static long sFinalizer = -1;
// ---- delegate helper data ----
// ---- delegate data ----
private final Config mConfig;
- private BufferedImage mImage;
+ private final BufferedImage mImage;
private boolean mHasAlpha = true;
private boolean mHasMipMap = false; // TODO: check the default.
private boolean mIsPremultiplied = true;
@@ -114,10 +121,25 @@ public final class Bitmap_Delegate {
* @see Bitmap#isMutable()
* @see Bitmap#getDensity()
*/
- public static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags,
+ private static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags,
Density density) throws IOException {
// create a delegate with the content of the file.
- Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
+ BufferedImage image = ImageIO.read(input);
+ if (image == null && input.exists()) {
+ // There was a problem decoding the image, or the decoder isn't registered. Webp maybe.
+ // Replace with a broken image icon.
+ BridgeContext currentContext = RenderAction.getCurrentContext();
+ if (currentContext != null) {
+ RenderResources resources = currentContext.getRenderResources();
+ ResourceValue broken = resources.getFrameworkResource(ResourceType.DRAWABLE,
+ "ic_menu_report_image");
+ File brokenFile = new File(broken.getValue());
+ if (brokenFile.exists()) {
+ image = ImageIO.read(brokenFile);
+ }
+ }
+ }
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
return createBitmap(delegate, createFlags, density.getDpiValue());
}
@@ -281,8 +303,13 @@ public final class Bitmap_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeDestructor(long nativeBitmap) {
- sManager.removeJavaReferenceFor(nativeBitmap);
+ /*package*/ static long nativeGetNativeFinalizer() {
+ synchronized (Bitmap_Delegate.class) {
+ if (sFinalizer == -1) {
+ sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
+ }
+ return sFinalizer;
+ }
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index ba0d399ce52f..c4fbd562812a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -21,6 +21,7 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.GcSnapshot;
import com.android.layoutlib.bridge.impl.PorterDuffUtility;
+import com.android.ninepatch.NinePatchChunk;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.annotation.Nullable;
@@ -38,6 +39,8 @@ import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
+import libcore.util.NativeAllocationRegistry_Delegate;
+
/**
* Delegate implementing the native methods of android.graphics.Canvas
@@ -57,6 +60,7 @@ public final class Canvas_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Canvas_Delegate> sManager =
new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
+ private static long sFinalizer = -1;
// ---- delegate helper data ----
@@ -160,6 +164,9 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
+
+ @LayoutlibDelegate
/*package*/ static int native_getWidth(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -749,6 +756,61 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static void native_drawRegion(long nativeCanvas, long nativeRegion,
+ long nativePaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Some canvas paths may not be drawn", null, null);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
+ long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop,
+ final float dstRight, final float dstBottom, long nativePaintOrZero,
+ final int screenDensity, final int bitmapDensity) {
+
+ // get the delegate from the native int.
+ final Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ byte[] c = NinePatch_Delegate.getChunk(ninePatch);
+ if (c == null) {
+ // not a 9-patch?
+ BufferedImage image = bitmapDelegate.getImage();
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 0, 0, image.getWidth(),
+ image.getHeight(), (int) dstLeft, (int) dstTop, (int) dstRight,
+ (int) dstBottom);
+ return;
+ }
+
+ final NinePatchChunk chunkObject = NinePatch_Delegate.getChunk(c);
+ assert chunkObject != null;
+ if (chunkObject == null) {
+ return;
+ }
+
+ Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // this one can be null
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
+
+ canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ @Override
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ chunkObject.draw(bitmapDelegate.getImage(), graphics, (int) dstLeft, (int) dstTop,
+ (int) (dstRight - dstLeft), (int) (dstBottom - dstTop), screenDensity,
+ bitmapDensity);
+ }
+ }, paintDelegate, true, false);
+
+ }
+
+ @LayoutlibDelegate
/*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float left, float top,
long nativePaintOrZero,
@@ -934,20 +996,21 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void finalizer(long nativeCanvas) {
- // get the delegate from the native int so that it can be disposed.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
- if (canvasDelegate == null) {
- return;
+ /*package*/ static long getNativeFinalizer() {
+ synchronized (Canvas_Delegate.class) {
+ if (sFinalizer == -1) {
+ sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> {
+ Canvas_Delegate delegate = sManager.getDelegate(nativePtr);
+ if (delegate != null) {
+ delegate.dispose();
+ }
+ sManager.removeJavaReferenceFor(nativePtr);
+ });
+ }
}
-
- canvasDelegate.dispose();
-
- // remove it from the manager.
- sManager.removeJavaReferenceFor(nativeCanvas);
+ return sFinalizer;
}
-
// ---- Private delegate/helper methods ----
/**
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index c7b24bcb352d..7412bc269c28 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -33,13 +33,13 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
@@ -73,7 +73,7 @@ public class FontFamily_Delegate {
private static final Map<String, FontInfo> sCache =
new LinkedHashMap<String, FontInfo>(CACHE_SIZE) {
@Override
- protected boolean removeEldestEntry(Entry<String, FontInfo> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<String, FontInfo> eldest) {
return size() > CACHE_SIZE;
}
@@ -213,7 +213,7 @@ public class FontFamily_Delegate {
return mValid;
}
- /*package*/ static Font loadFont(String path) {
+ private static Font loadFont(String path) {
if (path.startsWith(SYSTEM_FONTS) ) {
String relativePath = path.substring(SYSTEM_FONTS.length());
File f = new File(sFontLocation, relativePath);
@@ -270,16 +270,12 @@ public class FontFamily_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFont(long nativeFamily, final String path) {
+ /*package*/ static boolean nAddFont(long nativeFamily, final String path, int ttcIndex) {
+ // FIXME: support ttc fonts. Hack JRE??
final FontFamily_Delegate delegate = getDelegate(nativeFamily);
if (delegate != null) {
if (sFontLocation == null) {
- delegate.mPostInitRunnables.add(new Runnable() {
- @Override
- public void run() {
- delegate.addFont(path);
- }
- });
+ delegate.mPostInitRunnables.add(() -> delegate.addFont(path));
return true;
}
return delegate.addFont(path);
@@ -288,17 +284,19 @@ public class FontFamily_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, final String path,
- final int weight, final boolean isItalic) {
+ /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+ int ttcIndex, List<FontListParser.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,
+ final boolean isItalic) {
final FontFamily_Delegate delegate = getDelegate(nativeFamily);
if (delegate != null) {
if (sFontLocation == null) {
- delegate.mPostInitRunnables.add(new Runnable() {
- @Override
- public void run() {
- delegate.addFont(path, weight, isItalic);
- }
- });
+ delegate.mPostInitRunnables.add(() -> delegate.addFont(path, weight, isItalic));
return true;
}
return delegate.addFont(path, weight, isItalic);
@@ -309,6 +307,9 @@ public class FontFamily_Delegate {
@LayoutlibDelegate
/*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily);
+ if (ffd == null) {
+ return false;
+ }
ffd.mValid = true;
if (mgr == null) {
return false;
@@ -452,6 +453,7 @@ public class FontFamily_Delegate {
private FontInfo deriveFont(@NonNull FontInfo srcFont, @NonNull FontInfo outFont) {
int desiredWeight = outFont.mWeight;
int srcWeight = srcFont.mWeight;
+ assert srcFont.mFont != null;
Font derivedFont = srcFont.mFont;
// Embolden the font if required.
if (desiredWeight >= BOLD_FONT_WEIGHT && desiredWeight - srcWeight > BOLD_FONT_WEIGHT_DELTA / 2) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index e8d34d0562aa..1f0eb3bab55b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -169,77 +169,18 @@ public final class NinePatch_Delegate {
sManager.removeJavaReferenceFor(chunk);
}
- @LayoutlibDelegate
- /*package*/ static void nativeDraw(long canvas_instance, RectF loc, Bitmap bitmap_instance,
- long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
- draw(canvas_instance,
- (int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom,
- bitmap_instance, chunk, paint_instance_or_null,
- destDensity, srcDensity);
- }
-
- @LayoutlibDelegate
- /*package*/ static void nativeDraw(long canvas_instance, Rect loc, Bitmap bitmap_instance,
- long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
- draw(canvas_instance,
- loc.left, loc.top, loc.right, loc.bottom,
- bitmap_instance, chunk, paint_instance_or_null,
- destDensity, srcDensity);
- }
@LayoutlibDelegate
/*package*/ static long nativeGetTransparentRegion(Bitmap bitmap, long chunk, Rect location) {
return 0;
}
- // ---- Private Helper methods ----
-
- private static void draw(long canvas_instance,
- final int left, final int top, final int right, final int bottom,
- Bitmap bitmap_instance, long chunk, long paint_instance_or_null,
- final int destDensity, final int srcDensity) {
- // get the delegate from the native int.
- final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
- if (bitmap_delegate == null) {
- return;
- }
-
- byte[] c = null;
- NinePatch_Delegate delegate = sManager.getDelegate(chunk);
+ static byte[] getChunk(long nativeNinePatch) {
+ NinePatch_Delegate delegate = sManager.getDelegate(nativeNinePatch);
if (delegate != null) {
- c = delegate.chunk;
- }
- if (c == null) {
- // not a 9-patch?
- BufferedImage image = bitmap_delegate.getImage();
- Canvas_Delegate.native_drawBitmap(null, canvas_instance, bitmap_instance,
- 0f, 0f, (float)image.getWidth(), (float)image.getHeight(),
- (float)left, (float)top, (float)right, (float)bottom,
- paint_instance_or_null, destDensity, srcDensity);
- return;
+ return delegate.chunk;
}
+ return null;
+ }
- final NinePatchChunk chunkObject = getChunk(c);
- assert chunkObject != null;
- if (chunkObject == null) {
- return;
- }
-
- Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
- if (canvas_delegate == null) {
- return;
- }
-
- // this one can be null
- Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
-
- canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
- @Override
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- chunkObject.draw(bitmap_delegate.getImage(), graphics,
- left, top, right - left, bottom - top, destDensity, srcDensity);
- }
- }, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
-
- }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index dbd45c4f68be..514d7852bd05 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -39,6 +39,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import libcore.util.NativeAllocationRegistry_Delegate;
+
/**
* Delegate implementing the native methods of android.graphics.Paint
*
@@ -65,6 +67,7 @@ public class Paint_Delegate {
// ---- delegate manager ----
private static final DelegateManager<Paint_Delegate> sManager =
new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
+ private static long sFinalizer = -1;
// ---- delegate helper data ----
@@ -250,9 +253,9 @@ public class Paint_Delegate {
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static int getFlags(Paint thisPaint) {
+ /*package*/ static int nGetFlags(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -263,9 +266,9 @@ public class Paint_Delegate {
@LayoutlibDelegate
- /*package*/ static void setFlags(Paint thisPaint, int flags) {
+ /*package*/ static void nSetFlags(Paint thisPaint, long nativePaint, int flags) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -274,14 +277,14 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
- setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
+ /*package*/ static void nSetFilterBitmap(Paint thisPaint, long nativePaint, boolean filter) {
+ setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter);
}
@LayoutlibDelegate
- /*package*/ static int getHinting(Paint thisPaint) {
+ /*package*/ static int nGetHinting(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return Paint.HINTING_ON;
}
@@ -290,9 +293,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setHinting(Paint thisPaint, int mode) {
+ /*package*/ static void nSetHinting(Paint thisPaint, long nativePaint, int mode) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -301,44 +304,48 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
- setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
+ /*package*/ static void nSetAntiAlias(Paint thisPaint, long nativePaint, boolean aa) {
+ setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa);
}
@LayoutlibDelegate
- /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
- setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
+ /*package*/ static void nSetSubpixelText(Paint thisPaint, long nativePaint,
+ boolean subpixelText) {
+ setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
}
@LayoutlibDelegate
- /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
- setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
+ /*package*/ static void nSetUnderlineText(Paint thisPaint, long nativePaint,
+ boolean underlineText) {
+ setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
}
@LayoutlibDelegate
- /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
- setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
+ /*package*/ static void nSetStrikeThruText(Paint thisPaint, long nativePaint,
+ boolean strikeThruText) {
+ setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
}
@LayoutlibDelegate
- /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
- setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
+ /*package*/ static void nSetFakeBoldText(Paint thisPaint, long nativePaint,
+ boolean fakeBoldText) {
+ setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
}
@LayoutlibDelegate
- /*package*/ static void setDither(Paint thisPaint, boolean dither) {
- setFlag(thisPaint, Paint.DITHER_FLAG, dither);
+ /*package*/ static void nSetDither(Paint thisPaint, long nativePaint, boolean dither) {
+ setFlag(nativePaint, Paint.DITHER_FLAG, dither);
}
@LayoutlibDelegate
- /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
- setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
+ /*package*/ static void nSetLinearText(Paint thisPaint, long nativePaint, boolean linearText) {
+ setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText);
}
@LayoutlibDelegate
- /*package*/ static int getColor(Paint thisPaint) {
+ /*package*/ static int nGetColor(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -347,9 +354,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setColor(Paint thisPaint, int color) {
+ /*package*/ static void nSetColor(Paint thisPaint, long nativePaint, int color) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -358,9 +365,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int getAlpha(Paint thisPaint) {
+ /*package*/ static int nGetAlpha(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -369,9 +376,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setAlpha(Paint thisPaint, int a) {
+ /*package*/ static void nSetAlpha(Paint thisPaint, long nativePaint, int a) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -380,9 +387,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float getStrokeWidth(Paint thisPaint) {
+ /*package*/ static float nGetStrokeWidth(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 1.f;
}
@@ -391,9 +398,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
+ /*package*/ static void nSetStrokeWidth(Paint thisPaint, long nativePaint, float width) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -402,9 +409,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float getStrokeMiter(Paint thisPaint) {
+ /*package*/ static float nGetStrokeMiter(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 1.f;
}
@@ -413,9 +420,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
+ /*package*/ static void nSetStrokeMiter(Paint thisPaint, long nativePaint, float miter) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -424,7 +431,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setShadowLayer(long paint, float radius, float dx, float dy,
+ /*package*/ static void nSetShadowLayer(long paint, float radius, float dx, float dy,
int color) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -432,7 +439,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean native_hasShadowLayer(long paint) {
+ /*package*/ static boolean nHasShadowLayer(long paint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Paint.hasShadowLayer is not supported.", null, null /*data*/);
@@ -440,16 +447,17 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
+ /*package*/ static boolean nIsElegantTextHeight(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
}
@LayoutlibDelegate
- /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
+ /*package*/ static void nSetElegantTextHeight(Paint thisPaint, long nativePaint,
+ boolean elegant) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -458,9 +466,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float getTextSize(Paint thisPaint) {
+ /*package*/ static float nGetTextSize(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 1.f;
}
@@ -469,9 +477,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
+ /*package*/ static void nSetTextSize(Paint thisPaint, long nativePaint, float textSize) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -483,9 +491,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float getTextScaleX(Paint thisPaint) {
+ /*package*/ static float nGetTextScaleX(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 1.f;
}
@@ -494,9 +502,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
+ /*package*/ static void nSetTextScaleX(Paint thisPaint, long nativePaint, float scaleX) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -508,9 +516,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float getTextSkewX(Paint thisPaint) {
+ /*package*/ static float nGetTextSkewX(Paint thisPaint, long nativePaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 1.f;
}
@@ -519,9 +527,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
+ /*package*/ static void nSetTextSkewX(Paint thisPaint, long nativePaint, float skewX) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
@@ -533,9 +541,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float ascent(Paint thisPaint) {
+ /*package*/ static float nAscent(Paint thisPaint, long nativePaint, long nativeTypeface) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -550,9 +558,9 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float descent(Paint thisPaint) {
+ /*package*/ static float nDescent(Paint thisPaint, long nativePaint, long nativeTypeface) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -567,9 +575,10 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
+ /*package*/ static float nGetFontMetrics(Paint thisPaint, long nativePaint, long nativeTypeface,
+ FontMetrics metrics) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -578,9 +587,10 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
+ /*package*/ static int nGetFontMetricsInt(Paint thisPaint, long nativePaint,
+ long nativeTypeface, FontMetricsInt fmi) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
}
@@ -603,31 +613,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
- int count, int bidiFlags) {
- // get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
- if (delegate == null) {
- return 0;
- }
-
- RectF bounds = delegate.measureText(text, index, count, null, 0, bidiFlags);
- return bounds.right - bounds.left;
- }
-
- @LayoutlibDelegate
- /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end,
- int bidiFlags) {
- return native_measureText(thisPaint, text.toCharArray(), start, end - start, bidiFlags);
- }
-
- @LayoutlibDelegate
- /*package*/ static float native_measureText(Paint thisPaint, String text, int bidiFlags) {
- return native_measureText(thisPaint, text.toCharArray(), 0, text.length(), bidiFlags);
- }
-
- @LayoutlibDelegate
- /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, char[] text,
+ /*package*/ static int nBreakText(long nativePaint, long nativeTypeface, char[] text,
int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) {
// get the delegate
@@ -669,21 +655,21 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, String text,
+ /*package*/ static int nBreakText(long nativePaint, long nativeTypeface, String text,
boolean measureForwards,
float maxWidth, int bidiFlags, float[] measuredWidth) {
- return native_breakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(),
+ return nBreakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(),
maxWidth, bidiFlags, measuredWidth);
}
@LayoutlibDelegate
- /*package*/ static long native_init() {
+ /*package*/ static long nInit() {
Paint_Delegate newDelegate = new Paint_Delegate();
return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
- /*package*/ static long native_initWithPaint(long paint) {
+ /*package*/ static long nInitWithPaint(long paint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(paint);
if (delegate == null) {
@@ -695,7 +681,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_reset(long native_object) {
+ /*package*/ static void nReset(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -706,7 +692,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_set(long native_dst, long native_src) {
+ /*package*/ static void nSet(long native_dst, long native_src) {
// get the delegate from the native int.
Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
if (delegate_dst == null) {
@@ -723,7 +709,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_getStyle(long native_object) {
+ /*package*/ static int nGetStyle(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -734,7 +720,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setStyle(long native_object, int style) {
+ /*package*/ static void nSetStyle(long native_object, int style) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -745,7 +731,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_getStrokeCap(long native_object) {
+ /*package*/ static int nGetStrokeCap(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -756,7 +742,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setStrokeCap(long native_object, int cap) {
+ /*package*/ static void nSetStrokeCap(long native_object, int cap) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -767,7 +753,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_getStrokeJoin(long native_object) {
+ /*package*/ static int nGetStrokeJoin(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -778,7 +764,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setStrokeJoin(long native_object, int join) {
+ /*package*/ static void nSetStrokeJoin(long native_object, int join) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -789,7 +775,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean native_getFillPath(long native_object, long src, long dst) {
+ /*package*/ static boolean nGetFillPath(long native_object, long src, long dst) {
Paint_Delegate paint = sManager.getDelegate(native_object);
if (paint == null) {
return false;
@@ -815,7 +801,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setShader(long native_object, long shader) {
+ /*package*/ static long nSetShader(long native_object, long shader) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -828,7 +814,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setColorFilter(long native_object, long filter) {
+ /*package*/ static long nSetColorFilter(long native_object, long filter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -847,7 +833,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setXfermode(long native_object, long xfermode) {
+ /*package*/ static long nSetXfermode(long native_object, long xfermode) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -860,7 +846,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setPathEffect(long native_object, long effect) {
+ /*package*/ static long nSetPathEffect(long native_object, long effect) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -873,7 +859,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setMaskFilter(long native_object, long maskfilter) {
+ /*package*/ static long nSetMaskFilter(long native_object, long maskfilter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -892,7 +878,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setTypeface(long native_object, long typeface) {
+ /*package*/ static long nSetTypeface(long native_object, long typeface) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -909,7 +895,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_setRasterizer(long native_object, long rasterizer) {
+ /*package*/ static long nSetRasterizer(long native_object, long rasterizer) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -928,7 +914,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_getTextAlign(long native_object) {
+ /*package*/ static int nGetTextAlign(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -939,7 +925,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setTextAlign(long native_object, int align) {
+ /*package*/ static void nSetTextAlign(long native_object, int align) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -950,58 +936,27 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setTextLocale(long native_object, String locale) {
- // get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(native_object);
- if (delegate == null) {
- return;
- }
-
- delegate.setTextLocale(locale);
- }
-
- @LayoutlibDelegate
- /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
- char[] text, int index, int count, int bidiFlags, float[] widths) {
-
- if (widths != null) {
- for (int i = 0; i< count; i++) {
- widths[i]=0;
- }
- }
+ /*package*/ static int nSetTextLocales(long native_object, String locale) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return 0;
}
- // native_typeface is passed here since Framework's old implementation did not have the
- // typeface object associated with the Paint. Since, we follow the new framework way,
- // we store the typeface with the paint and use it directly.
- assert (native_typeface == delegate.mNativeTypeface);
-
- RectF bounds = delegate.measureText(text, index, count, widths, 0, bidiFlags);
- return ((int) (bounds.right - bounds.left));
- }
-
- @LayoutlibDelegate
- /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
- String text, int start, int end, int bidiFlags, float[] widths) {
- return native_getTextWidths(native_object, native_typeface, text.toCharArray(), start,
- end - start, bidiFlags, widths);
+ delegate.setTextLocale(locale);
+ return 0;
}
@LayoutlibDelegate
- /* package */static int native_getTextGlyphs(long native_object, String text, int start,
- int end, int contextStart, int contextEnd, int flags, char[] glyphs) {
+ /*package*/ static void nSetTextLocalesByMinikinLangListId(long paintPtr,
+ int mMinikinLangListId) {
// FIXME
- return 0;
}
@LayoutlibDelegate
- /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
+ /*package*/ static float nGetTextAdvances(long native_object, long native_typeface,
char[] text, int index, int count, int contextIndex, int contextCount,
- boolean isRtl, float[] advances, int advancesIndex) {
+ int bidiFlags, float[] advances, int advancesIndex) {
if (advances != null)
for (int i = advancesIndex; i< advancesIndex+count; i++)
@@ -1017,25 +972,25 @@ public class Paint_Delegate {
// we store the typeface with the paint and use it directly.
assert (native_typeface == delegate.mNativeTypeface);
- RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, isRtl);
+ RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, bidiFlags);
return bounds.right - bounds.left;
}
@LayoutlibDelegate
- /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
+ /*package*/ static float nGetTextAdvances(long native_object, long native_typeface,
String text, int start, int end, int contextStart, int contextEnd,
- boolean isRtl, float[] advances, int advancesIndex) {
+ int bidiFlags, float[] advances, int advancesIndex) {
// FIXME: support contextStart and contextEnd
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count,
- contextStart, contextEnd - contextStart, isRtl, advances, advancesIndex);
+ return nGetTextAdvances(native_object, native_typeface, buffer, 0, count,
+ contextStart, contextEnd - contextStart, bidiFlags, advances, advancesIndex);
}
@LayoutlibDelegate
- /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, char[] text,
+ /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1044,7 +999,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, String text,
+ /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, String text,
int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1053,7 +1008,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_getTextPath(long native_object, long native_typeface,
+ /*package*/ static void nGetTextPath(long native_object, long native_typeface,
int bidiFlags, char[] text, int index, int count, float x, float y, long path) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1061,7 +1016,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_getTextPath(long native_object, long native_typeface,
+ /*package*/ static void nGetTextPath(long native_object, long native_typeface,
int bidiFlags, String text, int start, int end, float x, float y, long path) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1069,14 +1024,14 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeGetStringBounds(long nativePaint, long native_typeface,
+ /*package*/ static void nGetStringBounds(long nativePaint, long native_typeface,
String text, int start, int end, int bidiFlags, Rect bounds) {
- nativeGetCharArrayBounds(nativePaint, native_typeface, text.toCharArray(), start,
+ nGetCharArrayBounds(nativePaint, native_typeface, text.toCharArray(), start,
end - start, bidiFlags, bounds);
}
@LayoutlibDelegate
- /*package*/ static void nativeGetCharArrayBounds(long nativePaint, long native_typeface,
+ /*package*/ static void nGetCharArrayBounds(long nativePaint, long native_typeface,
char[] text, int index, int count, int bidiFlags, Rect bounds) {
// get the delegate from the native int.
@@ -1092,12 +1047,18 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void finalizer(long nativePaint) {
- sManager.removeJavaReferenceFor(nativePaint);
+ /*package*/ static long nGetNativeFinalizer() {
+ synchronized (Paint_Delegate.class) {
+ if (sFinalizer == -1) {
+ sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
+ sManager::removeJavaReferenceFor);
+ }
+ }
+ return sFinalizer;
}
@LayoutlibDelegate
- /*package*/ static float native_getLetterSpacing(long nativePaint) {
+ /*package*/ static float nGetLetterSpacing(long nativePaint) {
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
@@ -1106,7 +1067,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setLetterSpacing(long nativePaint, float letterSpacing) {
+ /*package*/ static void nSetLetterSpacing(long nativePaint, float letterSpacing) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
"Paint.setLetterSpacing() not supported.", null, null);
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -1117,13 +1078,13 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setFontFeatureSettings(long nativePaint, String settings) {
+ /*package*/ static void nSetFontFeatureSettings(long nativePaint, String settings) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
"Paint.setFontFeatureSettings() not supported.", null, null);
}
@LayoutlibDelegate
- /*package*/ static int native_getHyphenEdit(long nativePaint) {
+ /*package*/ static int nGetHyphenEdit(long nativePaint) {
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return 0;
@@ -1132,7 +1093,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setHyphenEdit(long nativePaint, int hyphen) {
+ /*package*/ static void nSetHyphenEdit(long nativePaint, int hyphen) {
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
@@ -1141,7 +1102,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean native_hasGlyph(long nativePaint, long nativeTypeface, int bidiFlags,
+ /*package*/ static boolean nHasGlyph(long nativePaint, long nativeTypeface, int bidiFlags,
String string) {
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -1169,13 +1130,14 @@ public class Paint_Delegate {
@LayoutlibDelegate
- /*package*/ static float native_getRunAdvance(long nativePaint, long nativeTypeface,
+ /*package*/ static float nGetRunAdvance(long nativePaint, long nativeTypeface,
@NonNull char[] text, int start, int end, int contextStart, int contextEnd,
boolean isRtl, int offset) {
int count = end - start;
float[] advances = new float[count];
- native_getTextRunAdvances(nativePaint, nativeTypeface, text, start, count,
- contextStart, contextEnd - contextStart, isRtl, advances, 0);
+ int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
+ nGetTextAdvances(nativePaint, nativeTypeface, text, start, count,
+ contextStart, contextEnd - contextStart, bidiFlags, advances, 0);
int startOffset = offset - start; // offset from start.
float sum = 0;
for (int i = 0; i < startOffset; i++) {
@@ -1185,13 +1147,14 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int native_getOffsetForAdvance(long nativePaint, long nativeTypeface,
+ /*package*/ static int nGetOffsetForAdvance(long nativePaint, long nativeTypeface,
char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl,
float advance) {
int count = end - start;
float[] advances = new float[count];
- native_getTextRunAdvances(nativePaint, nativeTypeface, text, start, count,
- contextStart, contextEnd - contextStart, isRtl, advances, 0);
+ int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
+ nGetTextAdvances(nativePaint, nativeTypeface, text, start, count,
+ contextStart, contextEnd - contextStart, bidiFlags, advances, 0);
float sum = 0;
int i;
for (i = 0; i < count && sum < advance; i++) {
@@ -1359,9 +1322,9 @@ public class Paint_Delegate {
mLocale = new Locale(locale);
}
- private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
+ private static void setFlag(long nativePaint, int flagMask, boolean flagValue) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
return;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index d0dd22f8faad..e1da27ba3497 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -75,7 +75,7 @@ public final class Path_Delegate {
return sManager.getDelegate(nPath);
}
- public Shape getJavaShape() {
+ public Path2D getJavaShape() {
return mPath;
}
@@ -388,21 +388,18 @@ public final class Path_Delegate {
@LayoutlibDelegate
/*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
float bottom, float[] radii, int dir) {
- // Java2D doesn't support different rounded corners in each corner, so just use the
- // first value.
- native_addRoundRect(nPath, left, top, right, bottom, radii[0], radii[1], dir);
-
- // there can be a case where this API is used but with similar values for all corners, so
- // in that case we don't warn.
- // we only care if 2 corners are different so just compare to the next one.
- for (int i = 0 ; i < 3 ; i++) {
- if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Different corner sizes are not supported in Path.addRoundRect.",
- null, null /*data*/);
- break;
- }
+
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ float[] cornerDimensions = new float[radii.length];
+ for (int i = 0; i < radii.length; i++) {
+ cornerDimensions[i] = 2 * radii[i];
}
+ pathDelegate.mPath.append(new RoundRectangle(left, top, right - left, bottom - top,
+ cornerDimensions), false);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java b/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java
new file mode 100644
index 000000000000..edd36e54aa77
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java
@@ -0,0 +1,370 @@
+/*
+ * 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.graphics;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RectangularShape;
+import java.awt.geom.RoundRectangle2D;
+import java.util.EnumSet;
+import java.util.NoSuchElementException;
+
+/**
+ * Defines a rectangle with rounded corners, where the sizes of the corners
+ * are potentially different.
+ */
+public class RoundRectangle extends RectangularShape {
+ public double x;
+ public double y;
+ public double width;
+ public double height;
+ public double ulWidth;
+ public double ulHeight;
+ public double urWidth;
+ public double urHeight;
+ public double lrWidth;
+ public double lrHeight;
+ public double llWidth;
+ public double llHeight;
+
+ private enum Zone {
+ CLOSE_OUTSIDE,
+ CLOSE_INSIDE,
+ MIDDLE,
+ FAR_INSIDE,
+ FAR_OUTSIDE
+ }
+
+ private final EnumSet<Zone> close = EnumSet.of(Zone.CLOSE_OUTSIDE, Zone.CLOSE_INSIDE);
+ private final EnumSet<Zone> far = EnumSet.of(Zone.FAR_OUTSIDE, Zone.FAR_INSIDE);
+
+ /**
+ * @param cornerDimensions array of 8 floating-point number corresponding to the width and
+ * the height of each corner in the following order: upper-left, upper-right, lower-right,
+ * lower-left. It assumes for the size the same convention as {@link RoundRectangle2D}, that
+ * is that the width and height of a corner correspond to the total width and height of the
+ * ellipse that corner is a quarter of.
+ */
+ public RoundRectangle(float x, float y, float width, float height, float[] cornerDimensions) {
+ if (cornerDimensions.length != 8) {
+ throw new IllegalArgumentException("The array of corner dimensions must have eight " +
+ "elements");
+ }
+
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+
+ float[] dimensions = cornerDimensions.clone();
+ // If a value is negative, the corresponding corner is squared
+ for (int i = 0; i < dimensions.length; i += 2) {
+ if (dimensions[i] < 0 || dimensions[i + 1] < 0) {
+ dimensions[i] = 0;
+ dimensions[i + 1] = 0;
+ }
+ }
+
+ double topCornerWidth = (dimensions[0] + dimensions[2]) / 2d;
+ double bottomCornerWidth = (dimensions[4] + dimensions[6]) / 2d;
+ double leftCornerHeight = (dimensions[1] + dimensions[7]) / 2d;
+ double rightCornerHeight = (dimensions[3] + dimensions[5]) / 2d;
+
+ // Rescale the corner dimensions if they are bigger than the rectangle
+ double scale = Math.min(1.0, width / topCornerWidth);
+ scale = Math.min(scale, width / bottomCornerWidth);
+ scale = Math.min(scale, height / leftCornerHeight);
+ scale = Math.min(scale, height / rightCornerHeight);
+
+ this.ulWidth = dimensions[0] * scale;
+ this.ulHeight = dimensions[1] * scale;
+ this.urWidth = dimensions[2] * scale;
+ this.urHeight = dimensions[3] * scale;
+ this.lrWidth = dimensions[4] * scale;
+ this.lrHeight = dimensions[5] * scale;
+ this.llWidth = dimensions[6] * scale;
+ this.llHeight = dimensions[7] * scale;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return (width <= 0d) || (height <= 0d);
+ }
+
+ @Override
+ public void setFrame(double x, double y, double w, double h) {
+ this.x = x;
+ this.y = y;
+ this.width = w;
+ this.height = h;
+ }
+
+ @Override
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+
+ @Override
+ public boolean contains(double x, double y) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double x0 = getX();
+ double y0 = getY();
+ double x1 = x0 + getWidth();
+ double y1 = y0 + getHeight();
+ // Check for trivial rejection - point is outside bounding rectangle
+ if (x < x0 || y < y0 || x >= x1 || y >= y1) {
+ return false;
+ }
+
+ double insideTopX0 = x0 + ulWidth / 2d;
+ double insideLeftY0 = y0 + ulHeight / 2d;
+ if (x < insideTopX0 && y < insideLeftY0) {
+ // In the upper-left corner
+ return isInsideCorner(x - insideTopX0, y - insideLeftY0, ulWidth / 2d, ulHeight / 2d);
+ }
+
+ double insideTopX1 = x1 - urWidth / 2d;
+ double insideRightY0 = y0 + urHeight / 2d;
+ if (x > insideTopX1 && y < insideRightY0) {
+ // In the upper-right corner
+ return isInsideCorner(x - insideTopX1, y - insideRightY0, urWidth / 2d, urHeight / 2d);
+ }
+
+ double insideBottomX1 = x1 - lrWidth / 2d;
+ double insideRightY1 = y1 - lrHeight / 2d;
+ if (x > insideBottomX1 && y > insideRightY1) {
+ // In the lower-right corner
+ return isInsideCorner(x - insideBottomX1, y - insideRightY1, lrWidth / 2d,
+ lrHeight / 2d);
+ }
+
+ double insideBottomX0 = x0 + llWidth / 2d;
+ double insideLeftY1 = y1 - llHeight / 2d;
+ if (x < insideBottomX0 && y > insideLeftY1) {
+ // In the lower-left corner
+ return isInsideCorner(x - insideBottomX0, y - insideLeftY1, llWidth / 2d,
+ llHeight / 2d);
+ }
+
+ // In the central part of the rectangle
+ return true;
+ }
+
+ private boolean isInsideCorner(double x, double y, double width, double height) {
+ double squareDist = height * height * x * x + width * width * y * y;
+ return squareDist <= width * width * height * height;
+ }
+
+ private Zone classify(double coord, double side1, double arcSize1, double side2,
+ double arcSize2) {
+ if (coord < side1) {
+ return Zone.CLOSE_OUTSIDE;
+ } else if (coord < side1 + arcSize1) {
+ return Zone.CLOSE_INSIDE;
+ } else if (coord < side2 - arcSize2) {
+ return Zone.MIDDLE;
+ } else if (coord < side2) {
+ return Zone.FAR_INSIDE;
+ } else {
+ return Zone.FAR_OUTSIDE;
+ }
+ }
+
+ public boolean intersects(double x, double y, double w, double h) {
+ if (isEmpty() || w <= 0 || h <= 0) {
+ return false;
+ }
+ double x0 = getX();
+ double y0 = getY();
+ double x1 = x0 + getWidth();
+ double y1 = y0 + getHeight();
+ // Check for trivial rejection - bounding rectangles do not intersect
+ if (x + w <= x0 || x >= x1 || y + h <= y0 || y >= y1) {
+ return false;
+ }
+
+ double maxLeftCornerWidth = Math.max(ulWidth, llWidth) / 2d;
+ double maxRightCornerWidth = Math.max(urWidth, lrWidth) / 2d;
+ double maxUpperCornerHeight = Math.max(ulHeight, urHeight) / 2d;
+ double maxLowerCornerHeight = Math.max(llHeight, lrHeight) / 2d;
+ Zone x0class = classify(x, x0, maxLeftCornerWidth, x1, maxRightCornerWidth);
+ Zone x1class = classify(x + w, x0, maxLeftCornerWidth, x1, maxRightCornerWidth);
+ Zone y0class = classify(y, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight);
+ Zone y1class = classify(y + h, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight);
+
+ // Trivially accept if any point is inside inner rectangle
+ if (x0class == Zone.MIDDLE || x1class == Zone.MIDDLE || y0class == Zone.MIDDLE || y1class == Zone.MIDDLE) {
+ return true;
+ }
+ // Trivially accept if either edge spans inner rectangle
+ if ((close.contains(x0class) && far.contains(x1class)) || (close.contains(y0class) &&
+ far.contains(y1class))) {
+ return true;
+ }
+
+ // Since neither edge spans the center, then one of the corners
+ // must be in one of the rounded edges. We detect this case if
+ // a [xy]0class is 3 or a [xy]1class is 1. One of those two cases
+ // must be true for each direction.
+ // We now find a "nearest point" to test for being inside a rounded
+ // corner.
+ if (x1class == Zone.CLOSE_INSIDE && y1class == Zone.CLOSE_INSIDE) {
+ // Potentially in upper-left corner
+ x = x + w - x0 - ulWidth / 2d;
+ y = y + h - y0 - ulHeight / 2d;
+ return x > 0 || y > 0 || isInsideCorner(x, y, ulWidth / 2d, ulHeight / 2d);
+ }
+ if (x1class == Zone.CLOSE_INSIDE) {
+ // Potentially in lower-left corner
+ x = x + w - x0 - llWidth / 2d;
+ y = y - y1 + llHeight / 2d;
+ return x > 0 || y < 0 || isInsideCorner(x, y, llWidth / 2d, llHeight / 2d);
+ }
+ if (y1class == Zone.CLOSE_INSIDE) {
+ //Potentially in the upper-right corner
+ x = x - x1 + urWidth / 2d;
+ y = y + h - y0 - urHeight / 2d;
+ return x < 0 || y > 0 || isInsideCorner(x, y, urWidth / 2d, urHeight / 2d);
+ }
+ // Potentially in the lower-right corner
+ x = x - x1 + lrWidth / 2d;
+ y = y - y1 + lrHeight / 2d;
+ return x < 0 || y < 0 || isInsideCorner(x, y, lrWidth / 2d, lrHeight / 2d);
+ }
+
+ @Override
+ public boolean contains(double x, double y, double w, double h) {
+ if (isEmpty() || w <= 0 || h <= 0) {
+ return false;
+ }
+ return (contains(x, y) &&
+ contains(x + w, y) &&
+ contains(x, y + h) &&
+ contains(x + w, y + h));
+ }
+
+ @Override
+ public PathIterator getPathIterator(final AffineTransform at) {
+ return new PathIterator() {
+ int index;
+
+ // ArcIterator.btan(Math.PI/2)
+ public static final double CtrlVal = 0.5522847498307933;
+ private final double ncv = 1.0 - CtrlVal;
+
+ // Coordinates of control points for Bezier curves approximating the straight lines
+ // and corners of the rounded rectangle.
+ private final double[][] ctrlpts = {
+ {0.0, 0.0, 0.0, ulHeight},
+ {0.0, 0.0, 1.0, -llHeight},
+ {0.0, 0.0, 1.0, -llHeight * ncv, 0.0, ncv * llWidth, 1.0, 0.0, 0.0, llWidth,
+ 1.0, 0.0},
+ {1.0, -lrWidth, 1.0, 0.0},
+ {1.0, -lrWidth * ncv, 1.0, 0.0, 1.0, 0.0, 1.0, -lrHeight * ncv, 1.0, 0.0, 1.0,
+ -lrHeight},
+ {1.0, 0.0, 0.0, urHeight},
+ {1.0, 0.0, 0.0, ncv * urHeight, 1.0, -urWidth * ncv, 0.0, 0.0, 1.0, -urWidth,
+ 0.0, 0.0},
+ {0.0, ulWidth, 0.0, 0.0},
+ {0.0, ncv * ulWidth, 0.0, 0.0, 0.0, 0.0, 0.0, ncv * ulHeight, 0.0, 0.0, 0.0,
+ ulHeight},
+ {}
+ };
+ private final int[] types = {
+ SEG_MOVETO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_LINETO, SEG_CUBICTO,
+ SEG_CLOSE,
+ };
+
+ @Override
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ @Override
+ public boolean isDone() {
+ return index >= ctrlpts.length;
+ }
+
+ @Override
+ public void next() {
+ index++;
+ }
+
+ @Override
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException("roundrect iterator out of bounds");
+ }
+ int nc = 0;
+ double ctrls[] = ctrlpts[index];
+ for (int i = 0; i < ctrls.length; i += 4) {
+ coords[nc++] = (float) (x + ctrls[i] * width + ctrls[i + 1] / 2d);
+ coords[nc++] = (float) (y + ctrls[i + 2] * height + ctrls[i + 3] / 2d);
+ }
+ if (at != null) {
+ at.transform(coords, 0, coords, 0, nc / 2);
+ }
+ return types[index];
+ }
+
+ @Override
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException("roundrect iterator out of bounds");
+ }
+ int nc = 0;
+ double ctrls[] = ctrlpts[index];
+ for (int i = 0; i < ctrls.length; i += 4) {
+ coords[nc++] = x + ctrls[i] * width + ctrls[i + 1] / 2d;
+ coords[nc++] = y + ctrls[i + 2] * height + ctrls[i + 3] / 2d;
+ }
+ if (at != null) {
+ at.transform(coords, 0, coords, 0, nc / 2);
+ }
+ return types[index];
+ }
+ };
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 85e65e690dc7..5cd34f6e000f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -24,8 +24,10 @@ import android.graphics.FontFamily_Delegate.FontVariant;
import java.awt.Font;
import java.io.File;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import static android.graphics.FontFamily_Delegate.getFontLocation;
@@ -205,6 +207,17 @@ public final class Typeface_Delegate {
return new File(getFontLocation());
}
+ @LayoutlibDelegate
+ /*package*/ static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+ Map<String, ByteBuffer> bufferForPath) {
+ FontFamily fontFamily = new FontFamily(family.lang, family.variant);
+ for (FontListParser.Font font : family.fonts) {
+ FontFamily_Delegate.addFont(fontFamily.mNativePtr, font.fontName, font.weight,
+ font.isItalic);
+ }
+ return fontFamily;
+ }
+
// ---- Private delegate/helper methods ----
private Typeface_Delegate(@NonNull FontFamily_Delegate[] fontFamilies, int style) {
diff --git a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
index 44ce7311a95c..fcd63ea993c8 100644
--- a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
@@ -25,7 +25,7 @@ import java.nio.ByteBuffer;
/**
* Delegate that overrides implementation for certain methods in {@link android.text.Hyphenator}
* <p/>
- * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
+ * Through the layoutlib_create tool, selected methods of Hyphenator have been replaced
* by calls to methods of the same name in this delegate class.
*/
public class Hyphenator_Delegate {
@@ -39,7 +39,8 @@ public class Hyphenator_Delegate {
return null;
}
- /*package*/ static long loadHyphenator(ByteBuffer buf, int offset) {
+ /*package*/ @SuppressWarnings("UnusedParameters") // TODO implement this.
+ static long loadHyphenator(ByteBuffer buffer, int offset) {
return sDelegateManager.addNewDelegate(new Hyphenator_Delegate());
}
}
diff --git a/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
new file mode 100644
index 000000000000..d3af837ffd29
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
@@ -0,0 +1,757 @@
+/*
+ * 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.util;
+
+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.Path_Delegate;
+
+import java.awt.geom.Path2D;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Delegate that provides implementation for native methods in {@link android.util.PathParser}
+ * <p/>
+ * Through the layoutlib_create tool, selected methods of PathParser have been replaced by calls to
+ * methods of the same name in this delegate class.
+ *
+ * Most of the code has been taken from the implementation in
+ * {@code tools/base/sdk-common/src/main/java/com/android/ide/common/vectordrawable/PathParser.java}
+ * revision be6fe89a3b686db5a75e7e692a148699973957f3
+ */
+public class PathParser_Delegate {
+
+ private static final Logger LOGGER = Logger.getLogger("PathParser");
+
+ // ---- Builder delegate manager ----
+ private static final DelegateManager<PathParser_Delegate> sManager =
+ new DelegateManager<PathParser_Delegate>(PathParser_Delegate.class);
+
+ // ---- delegate data ----
+ @NonNull
+ private PathDataNode[] mPathDataNodes;
+
+ private PathParser_Delegate(@NonNull PathDataNode[] nodes) {
+ mPathDataNodes = nodes;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nParseStringForPath(long pathPtr, @NonNull String pathString, int
+ stringLength) {
+ Path_Delegate path_delegate = Path_Delegate.getDelegate(pathPtr);
+ if (path_delegate == null) {
+ return false;
+ }
+ assert pathString.length() == stringLength;
+ PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate.getJavaShape());
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCreatePathFromPathData(long outPathPtr, long pathData) {
+ Path_Delegate path_delegate = Path_Delegate.getDelegate(outPathPtr);
+ PathParser_Delegate source = sManager.getDelegate(outPathPtr);
+ if (source == null || path_delegate == null) {
+ return;
+ }
+ PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate.getJavaShape());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreateEmptyPathData() {
+ PathParser_Delegate newDelegate = new PathParser_Delegate(new PathDataNode[0]);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreatePathData(long nativePtr) {
+ PathParser_Delegate source = sManager.getDelegate(nativePtr);
+ if (source == null) {
+ return 0;
+ }
+ PathParser_Delegate dest = new PathParser_Delegate(deepCopyNodes(source.mPathDataNodes));
+ return sManager.addNewDelegate(dest);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nCreatePathDataFromString(@NonNull String pathString,
+ int stringLength) {
+ assert pathString.length() == stringLength : "Inconsistent path string length.";
+ PathDataNode[] nodes = createNodesFromPathData(pathString);
+ PathParser_Delegate delegate = new PathParser_Delegate(nodes);
+ return sManager.addNewDelegate(delegate);
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nInterpolatePathData(long outDataPtr, long fromDataPtr,
+ long toDataPtr, float fraction) {
+ PathParser_Delegate out = sManager.getDelegate(outDataPtr);
+ PathParser_Delegate from = sManager.getDelegate(fromDataPtr);
+ PathParser_Delegate to = sManager.getDelegate(toDataPtr);
+ if (out == null || from == null || to == null) {
+ return false;
+ }
+ int length = from.mPathDataNodes.length;
+ if (length != to.mPathDataNodes.length) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Cannot interpolate path data with different lengths (from " + length + " to " +
+ to.mPathDataNodes.length + ").", null);
+ return false;
+ }
+ if (out.mPathDataNodes.length != length) {
+ out.mPathDataNodes = new PathDataNode[length];
+ }
+ for (int i = 0; i < length; i++) {
+ out.mPathDataNodes[i].interpolatePathDataNode(from.mPathDataNodes[i],
+ to.mPathDataNodes[i], fraction);
+ }
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nFinalize(long nativePtr) {
+ sManager.removeJavaReferenceFor(nativePtr);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nCanMorph(long fromDataPtr, long toDataPtr) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "morphing path data isn't " +
+ "supported", null, null);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nSetPathData(long outDataPtr, long fromDataPtr) {
+ PathParser_Delegate out = sManager.getDelegate(outDataPtr);
+ PathParser_Delegate from = sManager.getDelegate(fromDataPtr);
+ if (from == null || out == null) {
+ return;
+ }
+ out.mPathDataNodes = deepCopyNodes(from.mPathDataNodes);
+ }
+
+ /**
+ * @param pathData The string representing a path, the same as "d" string in svg file.
+ *
+ * @return an array of the PathDataNode.
+ */
+ @NonNull
+ private static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
+ int start = 0;
+ int end = 1;
+
+ ArrayList<PathDataNode> list = new ArrayList<PathDataNode>();
+ while (end < pathData.length()) {
+ end = nextStart(pathData, end);
+ String s = pathData.substring(start, end).trim();
+ if (s.length() > 0) {
+ float[] val = getFloats(s);
+ addNode(list, s.charAt(0), val);
+ }
+
+ start = end;
+ end++;
+ }
+ if ((end - start) == 1 && start < pathData.length()) {
+ addNode(list, pathData.charAt(start), new float[0]);
+ }
+ return list.toArray(new PathDataNode[list.size()]);
+ }
+
+ /**
+ * @param source The array of PathDataNode to be duplicated.
+ *
+ * @return a deep copy of the <code>source</code>.
+ */
+ @NonNull
+ private static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
+ PathDataNode[] copy = new PathDataNode[source.length];
+ for (int i = 0; i < source.length; i++) {
+ copy[i] = new PathDataNode(source[i]);
+ }
+ return copy;
+ }
+
+ private static int nextStart(@NonNull String s, int end) {
+ char c;
+
+ while (end < s.length()) {
+ c = s.charAt(end);
+ // Note that 'e' or 'E' are not valid path commands, but could be
+ // used for floating point numbers' scientific notation.
+ // Therefore, when searching for next command, we should ignore 'e'
+ // and 'E'.
+ if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
+ && c != 'e' && c != 'E') {
+ return end;
+ }
+ end++;
+ }
+ return end;
+ }
+
+ /**
+ * Calculate the position of the next comma or space or negative sign
+ *
+ * @param s the string to search
+ * @param start the position to start searching
+ * @param result the result of the extraction, including the position of the the starting
+ * position of next number, whether it is ending with a '-'.
+ */
+ private static void extract(@NonNull String s, int start, @NonNull ExtractFloatResult result) {
+ // Now looking for ' ', ',', '.' or '-' from the start.
+ int currentIndex = start;
+ boolean foundSeparator = false;
+ result.mEndWithNegOrDot = false;
+ boolean secondDot = false;
+ boolean isExponential = false;
+ for (; currentIndex < s.length(); currentIndex++) {
+ boolean isPrevExponential = isExponential;
+ isExponential = false;
+ char currentChar = s.charAt(currentIndex);
+ switch (currentChar) {
+ case ' ':
+ case ',':
+ foundSeparator = true;
+ break;
+ case '-':
+ // The negative sign following a 'e' or 'E' is not a separator.
+ if (currentIndex != start && !isPrevExponential) {
+ foundSeparator = true;
+ result.mEndWithNegOrDot = true;
+ }
+ break;
+ case '.':
+ if (!secondDot) {
+ secondDot = true;
+ } else {
+ // This is the second dot, and it is considered as a separator.
+ foundSeparator = true;
+ result.mEndWithNegOrDot = true;
+ }
+ break;
+ case 'e':
+ case 'E':
+ isExponential = true;
+ break;
+ }
+ if (foundSeparator) {
+ break;
+ }
+ }
+ // When there is nothing found, then we put the end position to the end
+ // of the string.
+ result.mEndPosition = currentIndex;
+ }
+
+ /**
+ * Parse the floats in the string. This is an optimized version of
+ * parseFloat(s.split(",|\\s"));
+ *
+ * @param s the string containing a command and list of floats
+ *
+ * @return array of floats
+ */
+ @NonNull
+ private static float[] getFloats(@NonNull String s) {
+ if (s.charAt(0) == 'z' || s.charAt(0) == 'Z') {
+ return new float[0];
+ }
+ try {
+ float[] results = new float[s.length()];
+ int count = 0;
+ int startPosition = 1;
+ int endPosition;
+
+ ExtractFloatResult result = new ExtractFloatResult();
+ int totalLength = s.length();
+
+ // The startPosition should always be the first character of the
+ // current number, and endPosition is the character after the current
+ // number.
+ while (startPosition < totalLength) {
+ extract(s, startPosition, result);
+ endPosition = result.mEndPosition;
+
+ if (startPosition < endPosition) {
+ results[count++] = Float.parseFloat(
+ s.substring(startPosition, endPosition));
+ }
+
+ if (result.mEndWithNegOrDot) {
+ // Keep the '-' or '.' sign with next number.
+ startPosition = endPosition;
+ } else {
+ startPosition = endPosition + 1;
+ }
+ }
+ return Arrays.copyOf(results, count);
+ } catch (NumberFormatException e) {
+ throw new RuntimeException("error in parsing \"" + s + "\"", e);
+ }
+ }
+
+
+ private static void addNode(@NonNull ArrayList<PathDataNode> list, char cmd,
+ @NonNull float[] val) {
+ list.add(new PathDataNode(cmd, val));
+ }
+
+ private static class ExtractFloatResult {
+ // We need to return the position of the next separator and whether the
+ // next float starts with a '-' or a '.'.
+ private int mEndPosition;
+ private boolean mEndWithNegOrDot;
+ }
+
+ /**
+ * Each PathDataNode represents one command in the "d" attribute of the svg file. An array of
+ * PathDataNode can represent the whole "d" attribute.
+ */
+ private static class PathDataNode {
+ private char mType;
+ @NonNull
+ private float[] mParams;
+
+ private PathDataNode(char type, @NonNull float[] params) {
+ mType = type;
+ mParams = params;
+ }
+
+ public char getType() {
+ return mType;
+ }
+
+ @NonNull
+ public float[] getParams() {
+ return mParams;
+ }
+
+ private PathDataNode(@NonNull PathDataNode n) {
+ mType = n.mType;
+ mParams = Arrays.copyOf(n.mParams, n.mParams.length);
+ }
+
+ /**
+ * Convert an array of PathDataNode to Path.
+ *
+ * @param node The source array of PathDataNode.
+ * @param path The target Path object.
+ */
+ private static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path2D path) {
+ float[] current = new float[6];
+ char previousCommand = 'm';
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < node.length; i++) {
+ addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
+ previousCommand = node[i].mType;
+ }
+ }
+
+ /**
+ * The current PathDataNode will be interpolated between the <code>nodeFrom</code> and
+ * <code>nodeTo</code> according to the <code>fraction</code>.
+ *
+ * @param nodeFrom The start value as a PathDataNode.
+ * @param nodeTo The end value as a PathDataNode
+ * @param fraction The fraction to interpolate.
+ */
+ private void interpolatePathDataNode(@NonNull PathDataNode nodeFrom,
+ @NonNull PathDataNode nodeTo, float fraction) {
+ for (int i = 0; i < nodeFrom.mParams.length; i++) {
+ mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
+ + nodeTo.mParams[i] * fraction;
+ }
+ }
+
+ @SuppressWarnings("PointlessArithmeticExpression")
+ private static void addCommand(@NonNull Path2D path, float[] current, char cmd,
+ char lastCmd, @NonNull float[] val) {
+
+ int incr = 2;
+
+ float cx = current[0];
+ float cy = current[1];
+ float cpx = current[2];
+ float cpy = current[3];
+ float loopX = current[4];
+ float loopY = current[5];
+
+ switch (cmd) {
+ case 'z':
+ case 'Z':
+ path.closePath();
+ cx = loopX;
+ cy = loopY;
+ case 'm':
+ case 'M':
+ case 'l':
+ case 'L':
+ case 't':
+ case 'T':
+ incr = 2;
+ break;
+ case 'h':
+ case 'H':
+ case 'v':
+ case 'V':
+ incr = 1;
+ break;
+ case 'c':
+ case 'C':
+ incr = 6;
+ break;
+ case 's':
+ case 'S':
+ case 'q':
+ case 'Q':
+ incr = 4;
+ break;
+ case 'a':
+ case 'A':
+ incr = 7;
+ }
+
+ for (int k = 0; k < val.length; k += incr) {
+ boolean reflectCtrl;
+ float tempReflectedX, tempReflectedY;
+
+ switch (cmd) {
+ case 'm':
+ cx += val[k + 0];
+ cy += val[k + 1];
+ if (k > 0) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ path.lineTo(cx, cy);
+ } else {
+ path.moveTo(cx, cy);
+ loopX = cx;
+ loopY = cy;
+ }
+ break;
+ case 'M':
+ cx = val[k + 0];
+ cy = val[k + 1];
+ if (k > 0) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ path.lineTo(cx, cy);
+ } else {
+ path.moveTo(cx, cy);
+ loopX = cx;
+ loopY = cy;
+ }
+ break;
+ case 'l':
+ cx += val[k + 0];
+ cy += val[k + 1];
+ path.lineTo(cx, cy);
+ break;
+ case 'L':
+ cx = val[k + 0];
+ cy = val[k + 1];
+ path.lineTo(cx, cy);
+ break;
+ case 'z':
+ case 'Z':
+ path.closePath();
+ cx = loopX;
+ cy = loopY;
+ break;
+ case 'h':
+ cx += val[k + 0];
+ path.lineTo(cx, cy);
+ break;
+ case 'H':
+ path.lineTo(val[k + 0], cy);
+ cx = val[k + 0];
+ break;
+ case 'v':
+ cy += val[k + 0];
+ path.lineTo(cx, cy);
+ break;
+ case 'V':
+ path.lineTo(cx, val[k + 0]);
+ cy = val[k + 0];
+ break;
+ case 'c':
+ path.curveTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
+ cy + val[k + 3], cx + val[k + 4], cy + val[k + 5]);
+ cpx = cx + val[k + 2];
+ cpy = cy + val[k + 3];
+ cx += val[k + 4];
+ cy += val[k + 5];
+ break;
+ case 'C':
+ path.curveTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+ val[k + 4], val[k + 5]);
+ cx = val[k + 4];
+ cy = val[k + 5];
+ cpx = val[k + 2];
+ cpy = val[k + 3];
+ break;
+ case 's':
+ reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
+ lastCmd == 'S');
+ path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
+ * cy - cpy : cy, cx + val[k + 0], cy + val[k + 1], cx
+ + val[k + 2], cy + val[k + 3]);
+
+ cpx = cx + val[k + 0];
+ cpy = cy + val[k + 1];
+ cx += val[k + 2];
+ cy += val[k + 3];
+ break;
+ case 'S':
+ reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
+ lastCmd == 'S');
+ path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
+ * cy - cpy : cy, val[k + 0], val[k + 1], val[k + 2],
+ val[k + 3]);
+ cpx = (val[k + 0]);
+ cpy = (val[k + 1]);
+ cx = val[k + 2];
+ cy = val[k + 3];
+ break;
+ case 'q':
+ path.quadTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
+ cy + val[k + 3]);
+ cpx = cx + val[k + 0];
+ cpy = cy + val[k + 1];
+ // Note that we have to update cpx first, since cx will be updated here.
+ cx += val[k + 2];
+ cy += val[k + 3];
+ break;
+ case 'Q':
+ path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+ cx = val[k + 2];
+ cy = val[k + 3];
+ cpx = val[k + 0];
+ cpy = val[k + 1];
+ break;
+ case 't':
+ reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
+ lastCmd == 'T');
+ tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
+ tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
+ path.quadTo(tempReflectedX, tempReflectedY, cx + val[k + 0],
+ cy + val[k + 1]);
+ cpx = tempReflectedX;
+ cpy = tempReflectedY;
+ cx += val[k + 0];
+ cy += val[k + 1];
+ break;
+ case 'T':
+ reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
+ lastCmd == 'T');
+ tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
+ tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
+ path.quadTo(tempReflectedX, tempReflectedY, val[k + 0], val[k + 1]);
+ cx = val[k + 0];
+ cy = val[k + 1];
+ cpx = tempReflectedX;
+ cpy = tempReflectedY;
+ break;
+ case 'a':
+ // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
+ drawArc(path, cx, cy, val[k + 5] + cx, val[k + 6] + cy,
+ val[k + 0], val[k + 1], val[k + 2], val[k + 3] != 0,
+ val[k + 4] != 0);
+ cx += val[k + 5];
+ cy += val[k + 6];
+ cpx = cx;
+ cpy = cy;
+
+ break;
+ case 'A':
+ drawArc(path, cx, cy, val[k + 5], val[k + 6], val[k + 0],
+ val[k + 1], val[k + 2], val[k + 3] != 0,
+ val[k + 4] != 0);
+ cx = val[k + 5];
+ cy = val[k + 6];
+ cpx = cx;
+ cpy = cy;
+ break;
+
+ }
+ lastCmd = cmd;
+ }
+ current[0] = cx;
+ current[1] = cy;
+ current[2] = cpx;
+ current[3] = cpy;
+ current[4] = loopX;
+ current[5] = loopY;
+
+ }
+
+ private static void drawArc(@NonNull Path2D p, float x0, float y0, float x1,
+ float y1, float a, float b, float theta, boolean isMoreThanHalf,
+ boolean isPositiveArc) {
+
+ LOGGER.log(Level.FINE, "(" + x0 + "," + y0 + ")-(" + x1 + "," + y1
+ + ") {" + a + " " + b + "}");
+ /* Convert rotation angle from degrees to radians */
+ double thetaD = theta * Math.PI / 180.0f;
+ /* Pre-compute rotation matrix entries */
+ double cosTheta = Math.cos(thetaD);
+ double sinTheta = Math.sin(thetaD);
+ /* Transform (x0, y0) and (x1, y1) into unit space */
+ /* using (inverse) rotation, followed by (inverse) scale */
+ double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
+ double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
+ double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
+ double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
+ LOGGER.log(Level.FINE, "unit space (" + x0p + "," + y0p + ")-(" + x1p
+ + "," + y1p + ")");
+ /* Compute differences and averages */
+ double dx = x0p - x1p;
+ double dy = y0p - y1p;
+ double xm = (x0p + x1p) / 2;
+ double ym = (y0p + y1p) / 2;
+ /* Solve for intersecting unit circles */
+ double dsq = dx * dx + dy * dy;
+ if (dsq == 0.0) {
+ LOGGER.log(Level.FINE, " Points are coincident");
+ return; /* Points are coincident */
+ }
+ double disc = 1.0 / dsq - 1.0 / 4.0;
+ if (disc < 0.0) {
+ LOGGER.log(Level.FINE, "Points are too far apart " + dsq);
+ float adjust = (float) (Math.sqrt(dsq) / 1.99999);
+ drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta,
+ isMoreThanHalf, isPositiveArc);
+ return; /* Points are too far apart */
+ }
+ double s = Math.sqrt(disc);
+ double sdx = s * dx;
+ double sdy = s * dy;
+ double cx;
+ double cy;
+ if (isMoreThanHalf == isPositiveArc) {
+ cx = xm - sdy;
+ cy = ym + sdx;
+ } else {
+ cx = xm + sdy;
+ cy = ym - sdx;
+ }
+
+ double eta0 = Math.atan2((y0p - cy), (x0p - cx));
+ LOGGER.log(Level.FINE, "eta0 = Math.atan2( " + (y0p - cy) + " , "
+ + (x0p - cx) + ") = " + Math.toDegrees(eta0));
+
+ double eta1 = Math.atan2((y1p - cy), (x1p - cx));
+ LOGGER.log(Level.FINE, "eta1 = Math.atan2( " + (y1p - cy) + " , "
+ + (x1p - cx) + ") = " + Math.toDegrees(eta1));
+ double sweep = (eta1 - eta0);
+ if (isPositiveArc != (sweep >= 0)) {
+ if (sweep > 0) {
+ sweep -= 2 * Math.PI;
+ } else {
+ sweep += 2 * Math.PI;
+ }
+ }
+
+ cx *= a;
+ cy *= b;
+ double tcx = cx;
+ cx = cx * cosTheta - cy * sinTheta;
+ cy = tcx * sinTheta + cy * cosTheta;
+ LOGGER.log(
+ Level.FINE,
+ "cx, cy, a, b, x0, y0, thetaD, eta0, sweep = " + cx + " , "
+ + cy + " , " + a + " , " + b + " , " + x0 + " , " + y0
+ + " , " + Math.toDegrees(thetaD) + " , "
+ + Math.toDegrees(eta0) + " , " + Math.toDegrees(sweep));
+
+ arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
+ }
+
+ /**
+ * Converts an arc to cubic Bezier segments and records them in p.
+ *
+ * @param p The target for the cubic Bezier segments
+ * @param cx The x coordinate center of the ellipse
+ * @param cy The y coordinate center of the ellipse
+ * @param a The radius of the ellipse in the horizontal direction
+ * @param b The radius of the ellipse in the vertical direction
+ * @param e1x E(eta1) x coordinate of the starting point of the arc
+ * @param e1y E(eta2) y coordinate of the starting point of the arc
+ * @param theta The angle that the ellipse bounding rectangle makes with the horizontal
+ * plane
+ * @param start The start angle of the arc on the ellipse
+ * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
+ */
+ private static void arcToBezier(@NonNull Path2D p, double cx, double cy, double a,
+ double b, double e1x, double e1y, double theta, double start,
+ double sweep) {
+ // Taken from equations at:
+ // http://spaceroots.org/documents/ellipse/node8.html
+ // and http://www.spaceroots.org/documents/ellipse/node22.html
+ // Maximum of 45 degrees per cubic Bezier segment
+ int numSegments = (int) Math.ceil(Math.abs(sweep * 4 / Math.PI));
+
+
+ double eta1 = start;
+ double cosTheta = Math.cos(theta);
+ double sinTheta = Math.sin(theta);
+ double cosEta1 = Math.cos(eta1);
+ double sinEta1 = Math.sin(eta1);
+ double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
+ double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
+
+ double anglePerSegment = sweep / numSegments;
+ for (int i = 0; i < numSegments; i++) {
+ double eta2 = eta1 + anglePerSegment;
+ double sinEta2 = Math.sin(eta2);
+ double cosEta2 = Math.cos(eta2);
+ double e2x = cx + (a * cosTheta * cosEta2)
+ - (b * sinTheta * sinEta2);
+ double e2y = cy + (a * sinTheta * cosEta2)
+ + (b * cosTheta * sinEta2);
+ double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
+ double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
+ double tanDiff2 = Math.tan((eta2 - eta1) / 2);
+ double alpha = Math.sin(eta2 - eta1)
+ * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
+ double q1x = e1x + alpha * ep1x;
+ double q1y = e1y + alpha * ep1y;
+ double q2x = e2x - alpha * ep2x;
+ double q2y = e2y - alpha * ep2y;
+
+ p.curveTo((float) q1x, (float) q1y, (float) q2x, (float) q2y,
+ (float) e2x, (float) e2y);
+ eta1 = eta2;
+ e1x = e2x;
+ e1y = e2y;
+ ep1x = ep2x;
+ ep1y = ep2y;
+ }
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 4901f72b23d6..94f3f546d0c3 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -45,4 +45,10 @@ public class AttachInfo_Accessor {
public static void dispatchOnPreDraw(View view) {
view.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
}
+
+ public static void detachFromWindow(View view) {
+ if (view != null) {
+ view.dispatchDetachedFromWindow();
+ }
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java b/tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java
new file mode 100644
index 000000000000..e580ed0e14f7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/HandlerActionQueue_Delegate.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of
+ * {@link HandlerActionQueue}
+ *
+ * Through the layoutlib_create tool, the original methods of ViewRootImpl.RunQueue have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+public class HandlerActionQueue_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static void postDelayed(HandlerActionQueue thisQueue, Runnable action, long
+ delayMillis) {
+ // The actual HandlerActionQueue is never run and therefore never cleared. This method
+ // avoids runnables to be added to the RunQueue so they do not leak resources.
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 8d1b124809a3..d2103c811d3e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -20,6 +20,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IShortcutService;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -566,4 +567,8 @@ public class IWindowManagerImpl implements IWindowManager {
@Override
public void getStableInsets(Rect outInsets) throws RemoteException {
}
+
+ @Override
+ public void registerShortcutKey(long shortcutCode, IShortcutService service)
+ throws RemoteException {}
}
diff --git a/tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java b/tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java
deleted file mode 100644
index 1bd98301dc42..000000000000
--- a/tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java
+++ /dev/null
@@ -1,44 +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.widget;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.view.KeyEvent;
-
-/**
- * Delegate used to provide new implementation of few methods in {@link TimePickerClockDelegate}.
- */
-public class TimePickerClockDelegate_Delegate {
-
- // Copied from TimePickerClockDelegate.
- private static final int AM = 0;
- private static final int PM = 1;
-
- @LayoutlibDelegate
- static int getAmOrPmKeyCode(TimePickerClockDelegate tpcd, int amOrPm) {
- // We don't care about locales here.
- if (amOrPm == AM) {
- return KeyEvent.KEYCODE_A;
- } else if (amOrPm == PM) {
- return KeyEvent.KEYCODE_P;
- } else {
- assert false : "amOrPm value in TimePickerSpinnerDelegate can only be 0 or 1";
- return -1;
- }
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 2ac212c312c0..fea633e7036d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -208,6 +208,9 @@ public class BridgeRenderSession extends RenderSession {
@Override
public void dispose() {
+ if (mSession != null) {
+ mSession.dispose();
+ }
}
/*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
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 4b89217a581e..17ab2ff5cf5e 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
@@ -1382,6 +1382,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public File getDataDir() {
+ // pass
+ return null;
+ }
+
+ @Override
public File getFilesDir() {
// pass
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 01c3c500855d..5c74caf2695d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -184,15 +184,6 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
}
@Override
- public InputBindResult startInput(
- /* @InputMethodClient.StartInputReason */ int startInputReason,
- IInputMethodClient client, IInputContext inputContext, EditorInfo attribute,
- int controlFlags) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
public boolean switchToLastInputMethod(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
@@ -228,7 +219,7 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
}
@Override
- public InputBindResult windowGainedFocus(
+ public InputBindResult startInputOrWindowGainedFocus(
/* @InputMethodClient.StartInputReason */ int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext)
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 037ce57ced1b..fcfbad2743ed 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
@@ -308,6 +308,11 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public String getServicesSystemSharedLibraryPackageName() {
+ return null;
+ }
+
+ @Override
public FeatureInfo[] getSystemAvailableFeatures() {
return new FeatureInfo[0];
}
@@ -318,6 +323,11 @@ public class BridgePackageManager extends PackageManager {
}
@Override
+ public boolean hasSystemFeature(String name, int version) {
+ return false;
+ }
+
+ @Override
public ResolveInfo resolveActivity(Intent intent, int flags) {
return null;
}
@@ -774,7 +784,13 @@ public class BridgePackageManager extends PackageManager {
}
@Override
- public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+ int userId) {
+ return new String[]{};
+ }
+
+ @Override
+ public boolean isPackageSuspendedForUser(String packageName, int userId) {
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 2000fbc0fa47..533a10a6b13a 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
@@ -50,7 +50,8 @@ public final class BridgeWindow implements IWindow {
@Override
public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
- boolean b, Configuration configuration, Rect rect7, boolean b2) throws RemoteException {
+ boolean b, Configuration configuration, Rect rect7, boolean b2, boolean b3)
+ throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 7b8e29a03d86..fe05b0e91e83 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -236,4 +236,9 @@ public final class BridgeWindowSession implements IWindowSession {
public void prepareToReplaceChildren(IBinder appToken) {
// pass for now.
}
+
+ @Override
+ public void updatePointerIcon(IWindow window) {
+ // pass for now.
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index ec50cfe55651..99af226e4c4c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -1396,4 +1396,21 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
public RenderSession getSession() {
return mScene;
}
+
+ public void dispose() {
+ AttachInfo_Accessor.detachFromWindow(mViewRoot);
+ if (mCanvas != null) {
+ mCanvas.release();
+ mCanvas = null;
+ }
+ if (mViewInfoList != null) {
+ mViewInfoList.clear();
+ }
+ if (mSystemViewInfoList != null) {
+ mSystemViewInfoList.clear();
+ }
+ mImage = null;
+ mViewRoot = null;
+ mContentRoot = null;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
index 8c60bae4f11e..c0ca1d5916e9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -36,9 +36,9 @@ import android.widget.TextView;
/**
* A Helper class to do fake data binding in {@link AdapterView} objects.
*/
-@SuppressWarnings("deprecation")
public class AdapterHelper {
+ @SuppressWarnings("deprecation")
static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
LayoutlibCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
// we don't care about recycling here because we never scroll.
diff --git a/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java b/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java
new file mode 100644
index 000000000000..6246ec1b8661
--- /dev/null
+++ b/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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 libcore.util;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of {@link NativeAllocationRegistry}
+ *
+ * Through the layoutlib_create tool, the original native methods of NativeAllocationRegistry have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original NativeAllocationRegistry class.
+ *
+ * @see DelegateManager
+ */
+public class NativeAllocationRegistry_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<NativeAllocationRegistry_Delegate> sManager =
+ new DelegateManager<>(NativeAllocationRegistry_Delegate.class);
+
+ private final FreeFunction mFinalizer;
+
+ private NativeAllocationRegistry_Delegate(FreeFunction finalizer) {
+ mFinalizer = finalizer;
+ }
+
+ /**
+ * The result of this method should be cached by the class and reused.
+ */
+ public static long createFinalizer(FreeFunction finalizer) {
+ return sManager.addNewDelegate(new NativeAllocationRegistry_Delegate(finalizer));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void applyFreeFunction(long freeFunction, long nativePtr) {
+ NativeAllocationRegistry_Delegate delegate = sManager.getDelegate(freeFunction);
+ if (delegate != null) {
+ delegate.mFinalizer.free(nativePtr);
+ }
+ }
+
+ public interface FreeFunction {
+ void free(long nativePtr);
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 5eef24adbdef..5c062d0c7042 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -16,10 +16,11 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
# Only compile source java files in this lib.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_RESOURCE_DIRS := res
-LOCAL_JAVACFLAGS := -source 6 -target 6
LOCAL_MODULE := layoutlib-tests
LOCAL_MODULE_TAGS := optional
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
index 16911bdd7c2a..8f9fa8a2bcf6 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
@@ -75,8 +75,12 @@ public class ImageUtils {
}
}
else {
- BufferedImage goldenImage = ImageIO.read(is);
- assertImageSimilar(relativePath, goldenImage, thumbnail, MAX_PERCENT_DIFFERENCE);
+ try {
+ BufferedImage goldenImage = ImageIO.read(is);
+ assertImageSimilar(relativePath, goldenImage, thumbnail, MAX_PERCENT_DIFFERENCE);
+ } finally {
+ is.close();
+ }
}
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index fe16a3ed8459..6b23da71861a 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -291,7 +291,6 @@ public class Main {
@Test
public void testActivity() throws ClassNotFoundException {
renderAndVerify("activity.xml", "activity.png");
-
}
/** Test allwidgets.xml */
@@ -431,6 +430,8 @@ public class Main {
ImageUtils.requireSimilar(goldenImagePath, session.getImage());
} catch (IOException e) {
getLogger().error(e, e.getMessage());
+ } finally {
+ session.dispose();
}
}
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index c7f2c4137687..47377ae42d01 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -16,6 +16,8 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAR_MANIFEST := manifest.txt
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
index 758bd48e6067..01c940ad665c 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
@@ -176,17 +176,6 @@ public abstract class AbstractClassAdapter extends ClassVisitor {
}
}
- /* Java 7 verifies the StackMapTable of a class if its version number is greater than 50.0.
- * However, the check is disabled if the class version number is 50.0 or less. Generation
- * of the StackMapTable requires a rewrite using the tree API of ASM. As a workaround,
- * we rewrite the version number of the class to be 50.0
- *
- * http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6693236
- */
- if (version > 50) {
- version = 50;
- }
-
super.visit(version, access, name, signature, superName, interfaces);
}
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 d106592118c8..8a23e4b9d3da 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
@@ -144,11 +144,8 @@ public final class CreateInfo implements ICreateInfo {
InjectMethodRunnable.class,
InjectMethodRunnables.class,
/* Java package classes */
- AutoCloseable.class,
- Objects.class,
IntegralToString.class,
UnsafeByteSequence.class,
- Charsets.class,
System_Delegate.class,
LinkedHashMap_Delegate.class,
};
@@ -169,6 +166,7 @@ public final class CreateInfo implements ICreateInfo {
"android.graphics.BitmapFactory#setDensityFromOptions",
"android.graphics.drawable.GradientDrawable#buildRing",
"android.graphics.Typeface#getSystemFontConfigLocation",
+ "android.graphics.Typeface#makeFamilyFromParsed",
"android.os.Handler#sendMessageAtTime",
"android.os.HandlerThread#run",
"android.preference.Preference#getView",
@@ -180,6 +178,7 @@ public final class CreateInfo implements ICreateInfo {
"android.view.Choreographer#scheduleVsyncLocked",
"android.view.Display#updateDisplayInfoLocked",
"android.view.Display#getWindowManager",
+ "android.view.HandlerActionQueue#postDelayed",
"android.view.LayoutInflater#rInflate",
"android.view.LayoutInflater#parseInclude",
"android.view.View#getWindowToken",
@@ -188,6 +187,7 @@ public final class CreateInfo implements ICreateInfo {
"android.view.WindowManagerGlobal#getWindowManagerService",
"android.view.inputmethod.InputMethodManager#getInstance",
"android.view.MenuInflater#registerMenu",
+ "android.view.RenderNode#getMatrix",
"android.view.RenderNode#nCreate",
"android.view.RenderNode#nDestroyRenderNode",
"android.view.RenderNode#nSetElevation",
@@ -200,7 +200,6 @@ public final class CreateInfo implements ICreateInfo {
"android.view.RenderNode#nGetTranslationZ",
"android.view.RenderNode#nSetRotation",
"android.view.RenderNode#nGetRotation",
- "android.view.RenderNode#getMatrix",
"android.view.RenderNode#nSetLeft",
"android.view.RenderNode#nSetTop",
"android.view.RenderNode#nSetRight",
@@ -216,7 +215,6 @@ public final class CreateInfo implements ICreateInfo {
"android.view.RenderNode#nGetScaleY",
"android.view.RenderNode#nIsPivotExplicitlySet",
"android.view.ViewGroup#drawChild",
- "android.widget.TimePickerClockDelegate#getAmOrPmKeyCode",
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
@@ -224,6 +222,7 @@ public final class CreateInfo implements ICreateInfo {
"libcore.io.MemoryMappedFile#mmapRO",
"libcore.io.MemoryMappedFile#close",
"libcore.io.MemoryMappedFile#bigEndianIterator",
+ "libcore.util.NativeAllocationRegistry#applyFreeFunction",
};
/**
@@ -274,6 +273,7 @@ public final class CreateInfo implements ICreateInfo {
"android.os.SystemProperties",
"android.text.AndroidBidi",
"android.text.StaticLayout",
+ "android.util.PathParser",
"android.view.Display",
"libcore.icu.ICU",
};
@@ -306,12 +306,13 @@ public final class CreateInfo implements ICreateInfo {
*/
private final static String[] JAVA_PKG_CLASSES =
new String[] {
- "java.lang.AutoCloseable", "com.android.tools.layoutlib.java.AutoCloseable",
- "java.util.Objects", "com.android.tools.layoutlib.java.Objects",
- "java.nio.charset.Charsets", "com.android.tools.layoutlib.java.Charsets",
+ "java.nio.charset.Charsets", "java.nio.charset.StandardCharsets",
"java.lang.IntegralToString", "com.android.tools.layoutlib.java.IntegralToString",
"java.lang.UnsafeByteSequence", "com.android.tools.layoutlib.java.UnsafeByteSequence",
- "java.nio.charset.StandardCharsets", "com.android.tools.layoutlib.java.Charsets",
+ // Use android.icu.text versions of DateFormat and SimpleDateFormat since the
+ // original ones do not match the Android implementation
+ "java.text.DateFormat", "android.icu.text.DateFormat",
+ "java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat"
};
private final static String[] EXCLUDED_CLASSES =
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
index 91161f573b33..024e32f2ddbc 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
@@ -16,9 +16,11 @@
package com.android.tools.layoutlib.create;
+import java.util.Arrays;
import java.util.HashMap;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
public class RefactorClassAdapter extends AbstractClassAdapter {
@@ -30,6 +32,14 @@ public class RefactorClassAdapter extends AbstractClassAdapter {
}
@Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
+
+ return new RefactorStackMapAdapter(mw);
+ }
+
+ @Override
protected String renameInternalType(String oldClassName) {
if (oldClassName != null) {
String newName = mRefactorClasses.get(oldClassName);
@@ -46,4 +56,49 @@ public class RefactorClassAdapter extends AbstractClassAdapter {
}
return oldClassName;
}
+
+ /**
+ * A method visitor that renames all references from an old class name to a new class name in
+ * the stackmap of the method.
+ */
+ private class RefactorStackMapAdapter extends MethodVisitor {
+
+ private RefactorStackMapAdapter(MethodVisitor mv) {
+ super(Main.ASM_VERSION, mv);
+ }
+
+
+ private Object[] renameFrame(Object[] elements) {
+ if (elements == null) {
+ return null;
+ }
+
+ // The input array cannot be modified. We only copy the source array on write
+ boolean copied = false;
+ for (int i = 0; i < elements.length; i++) {
+ if (!(elements[i] instanceof String)) {
+ continue;
+ }
+
+ if (!copied) {
+ elements = Arrays.copyOf(elements, elements.length);
+ copied = true;
+ }
+
+ String type = (String)elements[i];
+ if (type.indexOf(';') > 0) {
+ elements[i] = renameTypeDesc(type);
+ } else {
+ elements[i] = renameInternalType(type);
+ }
+ }
+
+ return elements;
+ }
+
+ @Override
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ super.visitFrame(type, nLocal, renameFrame(local), nStack, renameFrame(stack));
+ }
+ }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
index b5ab73855189..4ba7237d7991 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
@@ -103,6 +103,7 @@ class StubMethodAdapter extends MethodVisitor {
mParentVisitor.visitInsn(Opcodes.ICONST_1);
mParentVisitor.visitInsn(Opcodes.IRETURN);
mParentVisitor.visitLabel(l1);
+ mParentVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mParentVisitor.visitInsn(Opcodes.ICONST_0);
break;
case Type.CHAR:
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index dafb9c6f9402..c59528e81ef2 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -15,6 +15,8 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
# Only compile source java files in this lib.
LOCAL_SRC_FILES := $(call all-java-files-under, com)
diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
index 611ed15c76b5..9fc1706ceb03 100644
--- a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
+++ b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
@@ -36,15 +36,15 @@ public class PasspointManagementObjectDefinition implements Parcelable {
mMoTree = moTree;
}
- public String getmBaseUri() {
+ public String getBaseUri() {
return mBaseUri;
}
- public String getmUrn() {
+ public String getUrn() {
return mUrn;
}
- public String getmMoTree() {
+ public String getMoTree() {
return mMoTree;
}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 9137d9d90439..59416b83dda1 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -23,7 +23,7 @@ import java.util.concurrent.CountDownLatch;
@SystemApi
public class RttManager {
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final String TAG = "RttManager";
/** @deprecated It is Not supported anymore. */
@@ -324,6 +324,11 @@ public class RttManager {
public int requestType;
/**
+ * Whether the secure RTT protocol needs to be used for ranging this peer device.
+ */
+ public boolean secure;
+
+ /**
* mac address of the device being ranged
* Default value: null
*/
@@ -478,6 +483,7 @@ public class RttManager {
for (RttParams params : mParams) {
dest.writeInt(params.deviceType);
dest.writeInt(params.requestType);
+ dest.writeByte(params.secure ? (byte) 1 : 0);
dest.writeString(params.bssid);
dest.writeInt(params.channelWidth);
dest.writeInt(params.frequency);
@@ -515,6 +521,7 @@ public class RttManager {
params[i] = new RttParams();
params[i].deviceType = in.readInt();
params[i].requestType = in.readInt();
+ params[i].secure = (in.readByte() != 0);
params[i].bssid = in.readString();
params[i].channelWidth = in.readInt();
params[i].frequency = in.readInt();
@@ -690,6 +697,11 @@ public class RttManager {
/** LCR information Element, only available to double side RTT. */
public WifiInformationElement LCR;
+
+ /**
+ * Whether the secure RTT protocol was used for ranging.
+ */
+ public boolean secure;
}
@@ -742,6 +754,7 @@ public class RttManager {
dest.writeInt((byte) result.LCR.data.length);
dest.writeByte(result.LCR.id);
}
+ dest.writeByte(result.secure ? (byte) 1 : 0);
}
} else {
dest.writeInt(0);
@@ -796,6 +809,7 @@ public class RttManager {
results[i].LCR.data = new byte[length];
in.readByteArray(results[i].LCR.data);
}
+ results[i].secure = (in.readByte() != 0);
}
ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 4a86c59542ab..a46aaec984ac 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -160,21 +160,6 @@ public class ScanResult implements Parcelable {
}
}
- /** @hide */
- public static final int ENABLED = 0;
- /** @hide */
- public static final int AUTO_ROAM_DISABLED = 16;
- /** @hide */
- public static final int AUTO_JOIN_DISABLED = 32;
- /** @hide */
- public static final int AUTHENTICATION_ERROR = 128;
-
- /**
- * Status: indicating join status
- * @hide
- */
- public int autoJoinStatus;
-
/**
* num IP configuration failures
* @hide
@@ -187,17 +172,6 @@ public class ScanResult implements Parcelable {
*/
public long blackListTimestamp;
- /** @hide **/
- public void setAutoJoinStatus(int status) {
- if (status < 0) status = 0;
- if (status == 0) {
- blackListTimestamp = 0;
- } else if (status > autoJoinStatus) {
- blackListTimestamp = System.currentTimeMillis();
- }
- autoJoinStatus = status;
- }
-
/**
* Status: indicating the scan result is not a result
* that is part of user's saved configurations
@@ -331,7 +305,9 @@ public class ScanResult implements Parcelable {
*/
public static class InformationElement {
public static final int EID_SSID = 0;
+ public static final int EID_TIM = 5;
public static final int EID_BSS_LOAD = 11;
+ public static final int EID_RSN = 48;
public static final int EID_HT_OPERATION = 61;
public static final int EID_INTERWORKING = 107;
public static final int EID_ROAMING_CONSORTIUM = 111;
@@ -460,7 +436,6 @@ public class ScanResult implements Parcelable {
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
seen = source.seen;
- autoJoinStatus = source.autoJoinStatus;
untrusted = source.untrusted;
numConnection = source.numConnection;
numUsage = source.numUsage;
@@ -504,9 +479,6 @@ public class ScanResult implements Parcelable {
sb.append(", passpoint: ");
sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
- if (autoJoinStatus != 0) {
- sb.append(", status: ").append(autoJoinStatus);
- }
sb.append(", ChannelBandwidth: ").append(channelWidth);
sb.append(", centerFreq0: ").append(centerFreq0);
sb.append(", centerFreq1: ").append(centerFreq1);
@@ -542,7 +514,6 @@ public class ScanResult implements Parcelable {
dest.writeInt(centerFreq0);
dest.writeInt(centerFreq1);
dest.writeLong(seen);
- dest.writeInt(autoJoinStatus);
dest.writeInt(untrusted ? 1 : 0);
dest.writeInt(numConnection);
dest.writeInt(numUsage);
@@ -613,7 +584,6 @@ public class ScanResult implements Parcelable {
);
sr.seen = in.readLong();
- sr.autoJoinStatus = in.readInt();
sr.untrusted = in.readInt() != 0;
sr.numConnection = in.readInt();
sr.numUsage = in.readInt();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a9132a59ced5..ddd8f437955d 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -26,7 +26,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.BackupUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
@@ -37,6 +42,10 @@ import java.util.HashMap;
*/
public class WifiConfiguration implements Parcelable {
private static final String TAG = "WifiConfiguration";
+ /**
+ * Current Version of the Backup Serializer.
+ */
+ private static final int BACKUP_VERSION = 2;
/** {@hide} */
public static final String ssidVarName = "ssid";
/** {@hide} */
@@ -230,12 +239,24 @@ public class WifiConfiguration implements Parcelable {
public String BSSID;
/**
+ * 2GHz band.
+ * @hide
+ */
+ public static final int AP_BAND_2GHZ = 0;
+
+ /**
+ * 5GHz band.
+ * @hide
+ */
+ public static final int AP_BAND_5GHZ = 1;
+
+ /**
* The band which AP resides on
* 0-2G 1-5G
* By default, 2G is chosen
* @hide
*/
- public int apBand = 0;
+ public int apBand = AP_BAND_2GHZ;
/**
* The channel which AP resides on,currently, US only
@@ -382,6 +403,15 @@ public class WifiConfiguration implements Parcelable {
/**
* @hide
+ * The number of beacon intervals between Delivery Traffic Indication Maps (DTIM)
+ * This value is populated from scan results that contain Beacon Frames, which are infrequent.
+ * The value is not guaranteed to be set or current (Although it SHOULDNT change once set)
+ * Valid values are from 1 - 255. Initialized here as 0, use this to check if set.
+ */
+ public int dtimInterval = 0;
+
+ /**
+ * @hide
* Uid of app creating the configuration
*/
@SystemApi
@@ -1277,6 +1307,7 @@ public class WifiConfiguration implements Parcelable {
lastUpdateUid = -1;
creatorUid = -1;
shared = true;
+ dtimInterval = 0;
}
/**
@@ -1450,10 +1481,10 @@ public class WifiConfiguration implements Parcelable {
if (diff <= 0) {
sbuf.append(" blackListed since <incorrect>");
} else {
- sbuf.append(" blackListed: ").append(Long.toString(diff/1000)).append( "sec ");
+ sbuf.append(" blackListed: ").append(Long.toString(diff / 1000)).append("sec ");
}
}
- if (creatorUid != 0) sbuf.append(" cuid=" + Integer.toString(creatorUid));
+ if (creatorUid != 0) sbuf.append(" cuid=" + creatorUid);
if (creatorName != null) sbuf.append(" cname=" + creatorName);
if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
@@ -1468,7 +1499,7 @@ public class WifiConfiguration implements Parcelable {
if (diff <= 0) {
sbuf.append("lastConnected since <incorrect>");
} else {
- sbuf.append("lastConnected: ").append(Long.toString(diff/1000)).append( "sec ");
+ sbuf.append("lastConnected: ").append(Long.toString(diff / 1000)).append("sec ");
}
}
if (this.lastConnectionFailure != 0) {
@@ -1477,8 +1508,8 @@ public class WifiConfiguration implements Parcelable {
if (diff <= 0) {
sbuf.append("lastConnectionFailure since <incorrect> ");
} else {
- sbuf.append("lastConnectionFailure: ").append(Long.toString(diff/1000));
- sbuf.append( "sec ");
+ sbuf.append("lastConnectionFailure: ").append(Long.toString(diff / 1000));
+ sbuf.append("sec ");
}
}
if (this.lastRoamingFailure != 0) {
@@ -1487,20 +1518,19 @@ public class WifiConfiguration implements Parcelable {
if (diff <= 0) {
sbuf.append("lastRoamingFailure since <incorrect> ");
} else {
- sbuf.append("lastRoamingFailure: ").append(Long.toString(diff/1000));
- sbuf.append( "sec ");
+ sbuf.append("lastRoamingFailure: ").append(Long.toString(diff / 1000));
+ sbuf.append("sec ");
}
}
sbuf.append("roamingFailureBlackListTimeMilli: ").
append(Long.toString(this.roamingFailureBlackListTimeMilli));
sbuf.append('\n');
if (this.linkedConfigurations != null) {
- for(String key : this.linkedConfigurations.keySet()) {
+ for (String key : this.linkedConfigurations.keySet()) {
sbuf.append(" linked: ").append(key);
sbuf.append('\n');
}
}
-
sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1748,11 +1778,6 @@ public class WifiConfiguration implements Parcelable {
}
/** @hide */
- public boolean isVisibleToUser(int userId) {
- return shared || (UserHandle.getUserId(creatorUid) == userId);
- }
-
- /** @hide */
public void setPasspointManagementObjectTree(String passpointManagementObjectTree) {
mPasspointManagementObjectTree = passpointManagementObjectTree;
}
@@ -1990,4 +2015,43 @@ public class WifiConfiguration implements Parcelable {
return new WifiConfiguration[size];
}
};
+
+ /**
+ * Serializes the object for backup
+ * @hide
+ */
+ public byte[] getBytesForBackup() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+
+ out.writeInt(BACKUP_VERSION);
+ BackupUtils.writeString(out, SSID);
+ out.writeInt(apBand);
+ out.writeInt(apChannel);
+ BackupUtils.writeString(out, preSharedKey);
+ out.writeInt(getAuthType());
+ return baos.toByteArray();
+ }
+
+ /**
+ * Deserializes a byte array into the WiFiConfiguration Object
+ * @hide
+ */
+ public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
+ BackupUtils.BadVersionException {
+ WifiConfiguration config = new WifiConfiguration();
+ int version = in.readInt();
+ if (version < 1 || version > BACKUP_VERSION) {
+ throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+ }
+
+ if (version == 1) return null; // Version 1 is a bad dataset.
+
+ config.SSID = BackupUtils.readString(in);
+ config.apBand = in.readInt();
+ config.apChannel = in.readInt();
+ config.preSharedKey = BackupUtils.readString(in);
+ config.allowedKeyManagement.set(in.readInt());
+ return config;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index a0dbd85049b2..58e876130e0c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -20,6 +20,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.security.Credentials;
import android.text.TextUtils;
+import android.util.Log;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
@@ -101,6 +102,8 @@ public class WifiEnterpriseConfig implements Parcelable {
/** @hide */
public static final String CA_CERT_KEY = "ca_cert";
/** @hide */
+ public static final String CA_PATH_KEY = "ca_path";
+ /** @hide */
public static final String ENGINE_KEY = "engine";
/** @hide */
public static final String ENGINE_ID_KEY = "engine_id";
@@ -114,10 +117,30 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final String CA_CERT_ALIAS_DELIMITER = " ";
+ // Fields to copy verbatim from wpa_supplicant.
+ private static final String[] SUPPLICANT_CONFIG_KEYS = new String[] {
+ IDENTITY_KEY,
+ ANON_IDENTITY_KEY,
+ PASSWORD_KEY,
+ CLIENT_CERT_KEY,
+ CA_CERT_KEY,
+ SUBJECT_MATCH_KEY,
+ ENGINE_KEY,
+ ENGINE_ID_KEY,
+ PRIVATE_KEY_ID_KEY,
+ ALTSUBJECT_MATCH_KEY,
+ DOM_SUFFIX_MATCH_KEY,
+ CA_PATH_KEY
+ };
+
private HashMap<String, String> mFields = new HashMap<String, String>();
private X509Certificate[] mCaCerts;
private PrivateKey mClientPrivateKey;
private X509Certificate mClientCertificate;
+ private int mEapMethod = Eap.NONE;
+ private int mPhase2Method = Phase2.NONE;
+
+ private static final String TAG = "WifiEnterpriseConfig";
public WifiEnterpriseConfig() {
// Do not set defaults so that the enterprise fields that are not changed
@@ -132,6 +155,8 @@ public class WifiEnterpriseConfig implements Parcelable {
for (String key : source.mFields.keySet()) {
mFields.put(key, source.mFields.get(key));
}
+ mEapMethod = source.mEapMethod;
+ mPhase2Method = source.mPhase2Method;
}
@Override
@@ -147,6 +172,8 @@ public class WifiEnterpriseConfig implements Parcelable {
dest.writeString(entry.getValue());
}
+ dest.writeInt(mEapMethod);
+ dest.writeInt(mPhase2Method);
writeCertificates(dest, mCaCerts);
if (mClientPrivateKey != null) {
@@ -198,6 +225,8 @@ public class WifiEnterpriseConfig implements Parcelable {
enterpriseConfig.mFields.put(key, value);
}
+ enterpriseConfig.mEapMethod = in.readInt();
+ enterpriseConfig.mPhase2Method = in.readInt();
enterpriseConfig.mCaCerts = readCertificates(in);
PrivateKey userKey = null;
@@ -294,7 +323,8 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final int MSCHAPV2 = 3;
/** Generic Token Card */
public static final int GTC = 4;
- private static final String PREFIX = "auth=";
+ private static final String AUTH_PREFIX = "auth=";
+ private static final String AUTHEAP_PREFIX = "autheap=";
/** @hide */
public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
"MSCHAPV2", "GTC" };
@@ -303,11 +333,98 @@ public class WifiEnterpriseConfig implements Parcelable {
private Phase2() {}
}
- /** Internal use only
+ // Loader and saver interfaces for exchanging data with wpa_supplicant.
+ // TODO: Decouple this object (which is just a placeholder of the configuration)
+ // from the implementation that knows what wpa_supplicant wants.
+ /**
+ * Interface used for retrieving supplicant configuration from WifiEnterpriseConfig
+ * @hide
+ */
+ public interface SupplicantSaver {
+ /**
+ * Set a value within wpa_supplicant configuration
+ * @param key index to set within wpa_supplciant
+ * @param value the value for the key
+ * @return true if successful; false otherwise
+ */
+ boolean saveValue(String key, String value);
+ }
+
+ /**
+ * Interface used for populating a WifiEnterpriseConfig from supplicant configuration
+ * @hide
+ */
+ public interface SupplicantLoader {
+ /**
+ * Returns a value within wpa_supplicant configuration
+ * @param key index to set within wpa_supplciant
+ * @return string value if successful; null otherwise
+ */
+ String loadValue(String key);
+ }
+
+ /**
+ * Internal use only; supply field values to wpa_supplicant config. The configuration
+ * process aborts on the first failed call on {@code saver}.
+ * @param saver proxy for setting configuration in wpa_supplciant
+ * @return whether the save succeeded on all attempts
* @hide
*/
- public HashMap<String, String> getFields() {
- return mFields;
+ public boolean saveToSupplicant(SupplicantSaver saver) {
+ if (!isEapMethodValid()) {
+ return false;
+ }
+
+ for (String key : mFields.keySet()) {
+ if (!saver.saveValue(key, mFields.get(key))) {
+ return false;
+ }
+ }
+
+ if (!saver.saveValue(EAP_KEY, Eap.strings[mEapMethod])) {
+ return false;
+ }
+
+ if (mEapMethod != Eap.TLS && mPhase2Method != Phase2.NONE) {
+ boolean is_autheap = mEapMethod == Eap.TTLS && mPhase2Method == Phase2.GTC;
+ String prefix = is_autheap ? Phase2.AUTHEAP_PREFIX : Phase2.AUTH_PREFIX;
+ String value = convertToQuotedString(prefix + Phase2.strings[mPhase2Method]);
+ return saver.saveValue(PHASE2_KEY, value);
+ } else if (mPhase2Method == Phase2.NONE) {
+ // By default, send a null phase 2 to clear old configuration values.
+ return saver.saveValue(PHASE2_KEY, null);
+ } else {
+ Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies a "
+ + "phase 2 method but the phase1 method does not support it.");
+ return false;
+ }
+ }
+
+ /**
+ * Internal use only; retrieve configuration from wpa_supplicant config.
+ * @param loader proxy for retrieving configuration keys from wpa_supplicant
+ * @hide
+ */
+ public void loadFromSupplicant(SupplicantLoader loader) {
+ for (String key : SUPPLICANT_CONFIG_KEYS) {
+ String value = loader.loadValue(key);
+ if (value == null) {
+ mFields.put(key, EMPTY_VALUE);
+ } else {
+ mFields.put(key, value);
+ }
+ }
+ String eapMethod = loader.loadValue(EAP_KEY);
+ mEapMethod = getStringIndex(Eap.strings, eapMethod, Eap.NONE);
+
+ String phase2Method = removeDoubleQuotes(loader.loadValue(PHASE2_KEY));
+ // Remove "auth=" or "autheap=" prefix.
+ if (phase2Method.startsWith(Phase2.AUTH_PREFIX)) {
+ phase2Method = phase2Method.substring(Phase2.AUTH_PREFIX.length());
+ } else if (phase2Method.startsWith(Phase2.AUTHEAP_PREFIX)) {
+ phase2Method = phase2Method.substring(Phase2.AUTHEAP_PREFIX.length());
+ }
+ mPhase2Method = getStringIndex(Phase2.strings, phase2Method, Phase2.NONE);
}
/**
@@ -328,7 +445,7 @@ public class WifiEnterpriseConfig implements Parcelable {
case Eap.SIM:
case Eap.AKA:
case Eap.AKA_PRIME:
- mFields.put(EAP_KEY, Eap.strings[eapMethod]);
+ mEapMethod = eapMethod;
mFields.put(OPP_KEY_CACHING, "1");
break;
default:
@@ -341,8 +458,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return eap method configured
*/
public int getEapMethod() {
- String eapMethod = mFields.get(EAP_KEY);
- return getStringIndex(Eap.strings, eapMethod, Eap.NONE);
+ return mEapMethod;
}
/**
@@ -357,15 +473,11 @@ public class WifiEnterpriseConfig implements Parcelable {
public void setPhase2Method(int phase2Method) {
switch (phase2Method) {
case Phase2.NONE:
- mFields.put(PHASE2_KEY, EMPTY_VALUE);
- break;
- /** Valid methods */
case Phase2.PAP:
case Phase2.MSCHAP:
case Phase2.MSCHAPV2:
case Phase2.GTC:
- mFields.put(PHASE2_KEY, convertToQuotedString(
- Phase2.PREFIX + Phase2.strings[phase2Method]));
+ mPhase2Method = phase2Method;
break;
default:
throw new IllegalArgumentException("Unknown Phase 2 method");
@@ -377,12 +489,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return a phase 2 method defined at {@link Phase2}
* */
public int getPhase2Method() {
- String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY));
- // Remove auth= prefix
- if (phase2Method.startsWith(Phase2.PREFIX)) {
- phase2Method = phase2Method.substring(Phase2.PREFIX.length());
- }
- return getStringIndex(Phase2.strings, phase2Method, Phase2.NONE);
+ return mPhase2Method;
}
/**
@@ -410,7 +517,8 @@ public class WifiEnterpriseConfig implements Parcelable {
setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, "");
}
- /** Get the anonymous identity
+ /**
+ * Get the anonymous identity
* @return anonymous identity
*/
public String getAnonymousIdentity() {
@@ -625,6 +733,33 @@ public class WifiEnterpriseConfig implements Parcelable {
mCaCerts = null;
}
+ /**
+ * Set the ca_path directive on wpa_supplicant.
+ *
+ * From wpa_supplicant documentation:
+ *
+ * Directory path for CA certificate files (PEM). This path may contain
+ * multiple CA certificates in OpenSSL format. Common use for this is to
+ * point to system trusted CA list which is often installed into directory
+ * like /etc/ssl/certs. If configured, these certificates are added to the
+ * list of trusted CAs. ca_cert may also be included in that case, but it is
+ * not required.
+ * @param domain The path for CA certificate files
+ * @hide
+ */
+ public void setCaPath(String path) {
+ setFieldValue(CA_PATH_KEY, path);
+ }
+
+ /**
+ * Get the domain_suffix_match value. See setDomSuffixMatch.
+ * @return The path for CA certificate files.
+ * @hide
+ */
+ public String getCaPath() {
+ return getFieldValue(CA_PATH_KEY, "");
+ }
+
/** Set Client certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -810,18 +945,15 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
- String getKeyId(WifiEnterpriseConfig current) {
- String eap = mFields.get(EAP_KEY);
- String phase2 = mFields.get(PHASE2_KEY);
-
- // If either eap or phase2 are not initialized, use current config details
- if (TextUtils.isEmpty((eap))) {
- eap = current.mFields.get(EAP_KEY);
+ public String getKeyId(WifiEnterpriseConfig current) {
+ // If EAP method is not initialized, use current config details
+ if (mEapMethod == Eap.NONE) {
+ return (current != null) ? current.getKeyId(null) : EMPTY_VALUE;
}
- if (TextUtils.isEmpty(phase2)) {
- phase2 = current.mFields.get(PHASE2_KEY);
+ if (!isEapMethodValid()) {
+ return EMPTY_VALUE;
}
- return eap + "_" + phase2;
+ return Eap.strings[mEapMethod] + "_" + Phase2.strings[mPhase2Method];
}
private String removeDoubleQuotes(String string) {
@@ -838,7 +970,8 @@ public class WifiEnterpriseConfig implements Parcelable {
return "\"" + string + "\"";
}
- /** Returns the index at which the toBeFound string is found in the array.
+ /**
+ * Returns the index at which the toBeFound string is found in the array.
* @param arr array of strings
* @param toBeFound string to be found
* @param defaultIndex default index to be returned when string is not found
@@ -852,13 +985,16 @@ public class WifiEnterpriseConfig implements Parcelable {
return defaultIndex;
}
- /** Returns the field value for the key.
+ /**
+ * Returns the field value for the key.
* @param key into the hash
* @param prefix is the prefix that the value may have
* @return value
* @hide
*/
public String getFieldValue(String key, String prefix) {
+ // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+ // neither of these keys should be retrieved in this manner.
String value = mFields.get(key);
// Uninitialized or known to be empty after reading from supplicant
if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
@@ -871,13 +1007,16 @@ public class WifiEnterpriseConfig implements Parcelable {
}
}
- /** Set a value with an optional prefix at key
+ /**
+ * Set a value with an optional prefix at key
* @param key into the hash
* @param value to be set
* @param prefix an optional value to be prefixed to actual value
* @hide
*/
public void setFieldValue(String key, String value, String prefix) {
+ // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+ // neither of these keys should be set in this manner.
if (TextUtils.isEmpty(value)) {
mFields.put(key, EMPTY_VALUE);
} else {
@@ -886,13 +1025,16 @@ public class WifiEnterpriseConfig implements Parcelable {
}
- /** Set a value with an optional prefix at key
+ /**
+ * Set a value with an optional prefix at key
* @param key into the hash
* @param value to be set
* @param prefix an optional value to be prefixed to actual value
* @hide
*/
public void setFieldValue(String key, String value) {
+ // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+ // neither of these keys should be set in this manner.
if (TextUtils.isEmpty(value)) {
mFields.put(key, EMPTY_VALUE);
} else {
@@ -910,4 +1052,25 @@ public class WifiEnterpriseConfig implements Parcelable {
}
return sb.toString();
}
+
+ /**
+ * Returns whether the EAP method data is valid, i.e., whether mEapMethod and mPhase2Method
+ * are valid indices into {@code Eap.strings[]} and {@code Phase2.strings[]} respectively.
+ */
+ private boolean isEapMethodValid() {
+ if (mEapMethod == Eap.NONE) {
+ Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies no EAP method.");
+ return false;
+ }
+ if (mEapMethod < 0 || mEapMethod >= Eap.strings.length) {
+ Log.e(TAG, "mEapMethod is invald for WiFi enterprise configuration: " + mEapMethod);
+ return false;
+ }
+ if (mPhase2Method < 0 || mPhase2Method >= Phase2.strings.length) {
+ Log.e(TAG, "mPhase2Method is invald for WiFi enterprise configuration: "
+ + mPhase2Method);
+ return false;
+ }
+ return true;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2ad3c2e16e21..4921073cce6c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -44,6 +44,7 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -892,6 +893,24 @@ public class WifiManager {
}
/**
+ * Sets whether or not the given network is metered from a network policy
+ * point of view. A network should be classified as metered when the user is
+ * sensitive to heavy data usage on that connection due to monetary costs,
+ * data limitations or battery/performance issues. A typical example would
+ * be a wifi connection where the user was being charged for usage.
+ * @param netId the integer that identifies the network configuration
+ * to the supplicant.
+ * @param isMetered True to mark the network as metered.
+ * @return {@code true} if the operation succeeded.
+ * @hide
+ */
+ @SystemApi
+ public boolean setMetered(int netId, boolean isMetered) {
+ // TODO(jjoslin): Implement
+ return false;
+ }
+
+ /**
* Remove the specified network from the list of configured networks.
* This may result in the asynchronous delivery of state change
* events.
@@ -1301,13 +1320,15 @@ public class WifiManager {
* @return the list of access points found in the most recent scan. An app must hold
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get valid results.
+ * in order to get valid results. If there is a remote exception (e.g., either a communication
+ * problem with the system service or an exception within the framework) an empty list will be
+ * returned.
*/
public List<ScanResult> getScanResults() {
try {
return mService.getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
- return null;
+ return new ArrayList<ScanResult>();
}
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 44be671a4309..69e179ddfaf5 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -30,7 +30,9 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
import java.util.List;
@@ -78,6 +80,8 @@ public class WifiScanner {
public static final int REASON_INVALID_REQUEST = -3;
/** Invalid request */
public static final int REASON_NOT_AUTHORIZED = -4;
+ /** An outstanding request with the same listener hasn't finished yet. */
+ public static final int REASON_DUPLICATE_REQEUST = -5;
/** @hide */
public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";
@@ -155,10 +159,6 @@ public class WifiScanner {
* Do not place scans in the chip's scan history buffer
*/
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
- /**
- * report full scan results and completion event to the context hub
- */
- public static final int REPORT_EVENT_CONTEXT_HUB = (1 << 3);
/**
* scan configuration parameters to be sent to {@link #startBackgroundScan}
@@ -464,8 +464,11 @@ public class WifiScanner {
* scans should also not share this object.
*/
public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = addListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
+ sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, settings);
}
/**
* stop an ongoing wifi scan
@@ -473,8 +476,11 @@ public class WifiScanner {
* #startBackgroundScan}
*/
public void stopBackgroundScan(ScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = removeListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+ sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
}
/**
* reports currently available scan results on appropriate listeners
@@ -495,8 +501,11 @@ public class WifiScanner {
* scans should also not share this object.
*/
public void startScan(ScanSettings settings, ScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = addListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, putListener(listener), settings);
+ sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, settings);
}
/**
@@ -505,8 +514,11 @@ public class WifiScanner {
* @param listener
*/
public void stopScan(ScanListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = removeListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, removeListener(listener));
+ sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
}
/** specifies information about an access point of interest */
@@ -638,8 +650,11 @@ public class WifiScanner {
* provided on {@link #stopTrackingWifiChange}
*/
public void startTrackingWifiChange(WifiChangeListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = addListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+ sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
}
/**
@@ -648,8 +663,10 @@ public class WifiScanner {
* #stopTrackingWifiChange}
*/
public void stopTrackingWifiChange(WifiChangeListener listener) {
+ int key = removeListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+ sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
}
/** @hide */
@@ -734,11 +751,14 @@ public class WifiScanner {
*/
public void startTrackingBssids(BssidInfo[] bssidInfos,
int apLostThreshold, BssidListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = addListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
HotlistSettings settings = new HotlistSettings();
settings.bssidInfos = bssidInfos;
settings.apLostThreshold = apLostThreshold;
- sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+ sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
}
/**
@@ -746,8 +766,11 @@ public class WifiScanner {
* @param listener same object provided in {@link #startTrackingBssids}
*/
public void stopTrackingBssids(BssidListener listener) {
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ int key = removeListener(listener);
+ if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+ sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
}
@@ -816,7 +839,7 @@ public class WifiScanner {
private static final Object sThreadRefLock = new Object();
private static int sThreadRefCount;
- private static HandlerThread sHandlerThread;
+ private static Handler sInternalHandler;
/**
* Create a new WifiScanner instance.
@@ -828,12 +851,29 @@ public class WifiScanner {
* @hide
*/
public WifiScanner(Context context, IWifiScanner service) {
+ this(context, service, null, true);
+ }
+
+ /**
+ * Create a new WifiScanner instance.
+ *
+ * @param context The application context.
+ * @param service The IWifiScanner Binder interface
+ * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
+ * created for running WifiScanner operations.
+ * @param waitForConnection If true, this will not return until a connection to Wifi Scanner
+ * service is established.
+ * @hide
+ */
+ @VisibleForTesting
+ public WifiScanner(Context context, IWifiScanner service, Looper looper,
+ boolean waitForConnection) {
mContext = context;
mService = service;
- init();
+ init(looper, waitForConnection);
}
- private void init() {
+ private void init(Looper looper, boolean waitForConnection) {
synchronized (sThreadRefLock) {
if (++sThreadRefCount == 1) {
Messenger messenger = null;
@@ -850,17 +890,23 @@ public class WifiScanner {
return;
}
- sHandlerThread = new HandlerThread("WifiScanner");
sAsyncChannel = new AsyncChannel();
sConnected = new CountDownLatch(1);
- sHandlerThread.start();
- Handler handler = new ServiceHandler(sHandlerThread.getLooper());
- sAsyncChannel.connect(mContext, handler, messenger);
- try {
- sConnected.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "interrupted wait at init");
+ if (looper == null) {
+ HandlerThread thread = new HandlerThread("WifiScanner");
+ thread.start();
+ sInternalHandler = new ServiceHandler(thread.getLooper());
+ } else {
+ sInternalHandler = new ServiceHandler(looper);
+ }
+ sAsyncChannel.connect(mContext, sInternalHandler, messenger);
+ if (waitForConnection) {
+ try {
+ sConnected.await();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "interrupted wait at init");
+ }
}
}
}
@@ -871,6 +917,30 @@ public class WifiScanner {
"No permission to access and change wifi or a bad initialization");
}
+ // Add a listener into listener map. If the listener already exists, return INVALID_KEY and
+ // send an error message to internal handler; Otherwise add the listener to the listener map and
+ // return the key of the listener.
+ private int addListener(ActionListener listener) {
+ synchronized (sListenerMap) {
+ boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
+ // Note we need to put the listener into listener map even if it's a duplicate as the
+ // internal handler will need the key to find the listener. In case of duplicates,
+ // removing duplicate key logic will be handled in internal handler.
+ int key = putListener(listener);
+ if (keyExists) {
+ if (DBG) Log.d(TAG, "listener key already exists");
+ OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
+ "Outstanding request with same key not stopped yet");
+ Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+ operationResult);
+ message.sendToTarget();
+ return INVALID_KEY;
+ } else {
+ return key;
+ }
+ }
+ }
+
private static int putListener(Object listener) {
if (listener == null) return INVALID_KEY;
int key;
@@ -914,7 +984,10 @@ public class WifiScanner {
private static int removeListener(Object listener) {
int key = getListenerKey(listener);
- if (key == INVALID_KEY) return key;
+ if (key == INVALID_KEY) {
+ Log.e(TAG, "listener cannot be found");
+ return key;
+ }
synchronized (sListenerMapLock) {
sListenerMap.remove(key);
return key;
diff --git a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
index 17cc29fe4f80..f5cad139bd23 100644
--- a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
+++ b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
@@ -16,8 +16,8 @@
package android.net.wifi;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
/**
* A class representing wifi wake reason accounting.
@@ -52,6 +52,8 @@ public class WifiWakeReasonAndCounts implements Parcelable {
public int ipv4RxMulticast;
public int ipv6Multicast;
public int otherRxMulticast;
+ public int[] cmdEventWakeCntArray;
+ public int[] driverFWLocalWakeCntArray;
/* {@hide} */
public WifiWakeReasonAndCounts () {
@@ -78,6 +80,13 @@ public class WifiWakeReasonAndCounts implements Parcelable {
sb.append(" ipv4RxMulticast ").append(ipv4RxMulticast);
sb.append(" ipv6Multicast ").append(ipv6Multicast);
sb.append(" otherRxMulticast ").append(otherRxMulticast);
+ for (int i = 0; i < cmdEventWakeCntArray.length; i++) {
+ sb.append(" cmdEventWakeCntArray[" + i + "] " + cmdEventWakeCntArray[i]);
+ }
+ for (int i = 0; i < driverFWLocalWakeCntArray.length; i++) {
+ sb.append(" driverFWLocalWakeCntArray[" + i + "] " + driverFWLocalWakeCntArray[i]);
+ }
+
return sb.toString();
}
@@ -111,6 +120,8 @@ public class WifiWakeReasonAndCounts implements Parcelable {
dest.writeInt(ipv4RxMulticast);
dest.writeInt(ipv6Multicast);
dest.writeInt(otherRxMulticast);
+ dest.writeIntArray(cmdEventWakeCntArray);
+ dest.writeIntArray(driverFWLocalWakeCntArray);
}
/* Implement the Parcelable interface
@@ -137,6 +148,8 @@ public class WifiWakeReasonAndCounts implements Parcelable {
counts.ipv4RxMulticast = in.readInt();
counts.ipv6Multicast = in.readInt();
counts.otherRxMulticast = in.readInt();
+ in.readIntArray(counts.cmdEventWakeCntArray);
+ in.readIntArray(counts.driverFWLocalWakeCntArray);
return counts;
}
/* Implement the Parcelable interface
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
index 5c18bd7e0f07..9e6ed4ee9634 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
@@ -36,7 +36,7 @@ import android.util.Log;
*/
public class WifiNanEventListener {
private static final String TAG = "WifiNanEventListener";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
/**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index cb82268ec195..667c4b1de6d0 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -38,7 +38,7 @@ import android.util.Log;
*/
public class WifiNanManager {
private static final String TAG = "WifiNanManager";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
private IBinder mBinder;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index d0a94109d0d8..bc1787fee478 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -27,7 +27,7 @@ import android.util.Log;
*/
public class WifiNanSession {
private static final String TAG = "WifiNanSession";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
/**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index 092508766570..b9af7def6868 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -43,7 +43,7 @@ import android.util.Log;
*/
public class WifiNanSessionListener {
private static final String TAG = "WifiNanSessionListener";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
/**